Class: PxModule::PerimeterxPayload

Inherits:
Object
  • Object
show all
Defined in:
lib/perimeterx/internal/payload/perimeter_x_payload.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(px_config) ⇒ PerimeterxPayload

Returns a new instance of PerimeterxPayload.



10
11
12
13
# File 'lib/perimeterx/internal/payload/perimeter_x_payload.rb', line 10

def initialize(px_config)
  @px_config = px_config
  @logger = px_config[:logger]
end

Instance Attribute Details

Returns the value of attribute cookie_secret.



8
9
10
# File 'lib/perimeterx/internal/payload/perimeter_x_payload.rb', line 8

def cookie_secret
  @cookie_secret
end

Returns the value of attribute decoded_cookie.



8
9
10
# File 'lib/perimeterx/internal/payload/perimeter_x_payload.rb', line 8

def decoded_cookie
  @decoded_cookie
end

#px_configObject

Returns the value of attribute px_config.



8
9
10
# File 'lib/perimeterx/internal/payload/perimeter_x_payload.rb', line 8

def px_config
  @px_config
end

Returns the value of attribute px_cookie.



8
9
10
# File 'lib/perimeterx/internal/payload/perimeter_x_payload.rb', line 8

def px_cookie
  @px_cookie
end

#px_ctxObject

Returns the value of attribute px_ctx.



8
9
10
# File 'lib/perimeterx/internal/payload/perimeter_x_payload.rb', line 8

def px_ctx
  @px_ctx
end

Class Method Details



15
16
17
18
19
20
21
22
23
24
25
# File 'lib/perimeterx/internal/payload/perimeter_x_payload.rb', line 15

def self.px_cookie_factory(px_ctx, px_config)
  if px_ctx.context[:cookie_origin] == 'header'
    if (px_ctx.context[:px_cookie].key?(:v3))
      return PerimeterxTokenV3.new(px_config,px_ctx)
    end
    return PerimeterxTokenV1.new(px_config,px_ctx)
  elsif (px_ctx.context[:px_cookie].key?(:v3))
    return PerimeterxCookieV3.new(px_config, px_ctx)
  end
  return PerimeterxCookieV1.new(px_config, px_ctx)
end

Instance Method Details

Raises:

  • (Exception)


42
43
44
45
# File 'lib/perimeterx/internal/payload/perimeter_x_payload.rb', line 42

def cookie_block_action
  #abstract, must be implemented
  raise Exception.new("Unimplemented method")
end

Raises:

  • (Exception)


32
33
34
35
# File 'lib/perimeterx/internal/payload/perimeter_x_payload.rb', line 32

def cookie_hmac
  #abstract, must be implemented
  raise Exception.new("Unimplemented method")
end

Raises:

  • (Exception)


27
28
29
30
# File 'lib/perimeterx/internal/payload/perimeter_x_payload.rb', line 27

def cookie_score
  #abstract, must be implemented
  raise Exception.new("Unimplemented method")
end


56
57
58
# File 'lib/perimeterx/internal/payload/perimeter_x_payload.rb', line 56

def cookie_time
  return @decoded_cookie[:t]
end


60
61
62
# File 'lib/perimeterx/internal/payload/perimeter_x_payload.rb', line 60

def cookie_uuid
  return @decoded_cookie[:u]
end


64
65
66
# File 'lib/perimeterx/internal/payload/perimeter_x_payload.rb', line 64

def cookie_vid
  return @decoded_cookie[:v]
end

#decode(px_cookie) ⇒ Object



133
134
135
# File 'lib/perimeterx/internal/payload/perimeter_x_payload.rb', line 133

def decode(px_cookie)
  return JSON.parse(Base64.decode64(px_cookie), symbolize_names: true)
end

#decrypt(px_cookie) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/perimeterx/internal/payload/perimeter_x_payload.rb', line 103

def decrypt(px_cookie)
  begin
    if (px_cookie.nil?)
      return
    end
    px_cookie = px_cookie.gsub(' ', '+')
    salt, iterations, cipher_text = px_cookie.split(':')
    iterations = iterations.to_i
    if (iterations > @px_config[:risk_cookie_max_iterations] || iterations < 500)
      return
    end
    salt = Base64.decode64(salt)
    cipher_text = Base64.decode64(cipher_text)
    digest = OpenSSL::Digest::SHA256.new
    value = OpenSSL::PKCS5.pbkdf2_hmac(@px_config[:cookie_key], salt, iterations, 48, digest)
    key = value[0..31]
    iv = value[32..-1]
    cipher = OpenSSL::Cipher::AES256.new(:CBC)
    cipher.decrypt
    cipher.key = key
    cipher.iv = iv
    plaintext = cipher.update(cipher_text) + cipher.final

    return JSON.parse(plaintext, symbolize_names: true)
  rescue Exception => e
    @logger.debug("PerimeterxCookie[decrypt]: Cookie decrypt fail #{e.message}")
    raise PxCookieDecryptionException.new("Cookie decrypt fail => #{e.message}");
  end
end

#deserializeObject



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/perimeterx/internal/payload/perimeter_x_payload.rb', line 77

def deserialize
  if (!@decoded_cookie.nil?)
    return true
  end

  # Decode or decrypt, depends on configuration
  if (@px_config[:encryption_enabled])
    cookie = decrypt(@px_cookie)
  else
    cookie = decode(@px_cookie)
  end

  if (cookie.nil?)
    return false
  end

  if (!valid_format?(cookie))
    return false
  end

  @decoded_cookie = cookie

  return true
end

#expired?Boolean

Returns:

  • (Boolean)


72
73
74
# File 'lib/perimeterx/internal/payload/perimeter_x_payload.rb', line 72

def expired?
  return cookie_time < (Time.now.to_f*1000).floor
end

#high_score?Boolean

Returns:

  • (Boolean)


68
69
70
# File 'lib/perimeterx/internal/payload/perimeter_x_payload.rb', line 68

def high_score?
  return cookie_score >= @px_config[:blocking_score]
end

#hmac_valid?(hmac_str, cookie_hmac) ⇒ Boolean

Returns:

  • (Boolean)


138
139
140
141
# File 'lib/perimeterx/internal/payload/perimeter_x_payload.rb', line 138

def hmac_valid?(hmac_str, cookie_hmac)
  hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new, @cookie_secret, hmac_str)
  password_correct = secure_compare(hmac, cookie_hmac)
end

#is_valid?Boolean

Returns:

  • (Boolean)


52
53
54
# File 'lib/perimeterx/internal/payload/perimeter_x_payload.rb', line 52

def is_valid?
  return deserialize && !expired? && secured?
end

#secure_compare(a, b) ⇒ Object



143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/perimeterx/internal/payload/perimeter_x_payload.rb', line 143

def secure_compare(a, b)
  # https://github.com/rails/rails/blob/main/activesupport/lib/active_support/security_utils.rb
  if (a.bytesize != b.bytesize)
    return false
  end

  l = a.unpack "C#{a.bytesize}"

  res = 0
  b.each_byte { |byte| res |= byte ^ l.shift }
  res == 0
end

#secured?Boolean

Returns:

  • (Boolean)

Raises:

  • (Exception)


47
48
49
50
# File 'lib/perimeterx/internal/payload/perimeter_x_payload.rb', line 47

def secured?
  #abstract, must be implemented
  raise Exception.new("Unimplemented method")
end

#valid_format?(cookie) ⇒ Boolean

Returns:

  • (Boolean)

Raises:

  • (Exception)


37
38
39
40
# File 'lib/perimeterx/internal/payload/perimeter_x_payload.rb', line 37

def valid_format?(cookie)
  #abstract, must be implemented
  raise Exception.new("Unimplemented method")
end