Class: Contrast::Utils::HashDigest

Inherits:
Digest::Class
  • Object
show all
Includes:
Digest::Instance
Defined in:
lib/contrast/utils/hash_digest.rb

Overview

We use this class to provide hashes for our Request and Finding objects based upon our definitions of uniqueness. While the uniqueness of the request object is something internal to the Ruby agent, the uniqueness of the Finding hash is defined by a specification shared across all agent teams. The spec can be found here: bitbucket.org/contrastsecurity/assess-specifications/src/master/vulnerability/preflight.md

Constant Summary collapse

CONTENT_LENGTH_HEADER =
'Content-Length'
CRYPTO_RULES =
%w[
  crypto-bad-ciphers
  crypto-bad-mac
].cs__freeze
CONFIG_PATH_KEY =
'path'
CONFIG_SESSION_ID_KEY =
'sessionId'
CLASS_SOURCE_KEY =
'source'
CLASS_CONSTANT_NAME_KEY =
'name'
CLASS_LINE_NO_KEY =
'lineNo'
CHARS =
%w[a b c d e f g].cs__freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeHashDigest

Returns a new instance of HashDigest.



133
134
135
136
# File 'lib/contrast/utils/hash_digest.rb', line 133

def initialize
  super
  @crc32 = 0
end

Class Method Details

.generate_class_scanning_hash(finding) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/contrast/utils/hash_digest.rb', line 59

def generate_class_scanning_hash finding
  hash = new
  hash.update(finding.rule_id)
  module_name = finding.properties[CLASS_SOURCE_KEY]
  hash.update(module_name)
  # We're not currently collecting this. 30/7/19 HM
  line_no = finding.properties[CLASS_LINE_NO_KEY]
  hash.update(line_no)
  field = finding.properties[CLASS_CONSTANT_NAME_KEY]
  hash.update(field)
  hash.finish
end

.generate_config_hash(finding) ⇒ Object



49
50
51
52
53
54
55
56
57
# File 'lib/contrast/utils/hash_digest.rb', line 49

def generate_config_hash finding
  hash = new
  hash.update(finding.rule_id)
  path = finding.properties[CONFIG_PATH_KEY]
  hash.update(path)
  method = finding.properties[CONFIG_SESSION_ID_KEY]
  hash.update(method)
  hash.finish
end

.generate_event_hash(finding, source) ⇒ Object



40
41
42
43
44
45
46
47
# File 'lib/contrast/utils/hash_digest.rb', line 40

def generate_event_hash finding, source
  return generate_dataflow_hash(finding) if finding.events.length.to_i > 1

  id = finding.rule_id
  return generate_crypto_hash(finding, source) if CRYPTO_RULES.include?(id)

  generate_trigger_hash(finding)
end

.generate_request_hash(request) ⇒ Object



28
29
30
31
32
33
34
35
36
37
38
# File 'lib/contrast/utils/hash_digest.rb', line 28

def generate_request_hash request
  hash = new
  hash.update(request.request_method)
  hash.update(request.normalized_uri)
  request.parameters.each_key do |name|
    hash.update(name)
  end
  cl = request.headers[CONTENT_LENGTH_HEADER]
  hash.update_on_content_length(cl) if cl
  hash.finish
end

Instance Method Details

#finishObject



144
145
146
# File 'lib/contrast/utils/hash_digest.rb', line 144

def finish
  @crc32.to_s
end

#update(str) ⇒ Object



138
139
140
141
142
# File 'lib/contrast/utils/hash_digest.rb', line 138

def update str
  return unless str

  @crc32 = Zlib.crc32(str, @crc32)
end

#update_on_content_length(chr) ⇒ Object

This method converts and integer value for length into a string value that we can hash on, based on the logarithmic value of the length, and updates the current hash with that value.

Parameters:

  • chr (Numeric)

    the length to translate



129
130
131
# File 'lib/contrast/utils/hash_digest.rb', line 129

def update_on_content_length chr
  update(CHARS[Math.log10(chr.to_s.length).to_i] || CHARS[-1])
end

#update_on_requestObject



98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/contrast/utils/hash_digest.rb', line 98

def update_on_request
  context = Contrast::Agent::REQUEST_TRACKER.current
  return unless context

  route = context.route
  request = context.request
  if route
    update(route.route)
    update(route.verb)
  elsif request
    update(request.normalized_uri)
    update(request.request_method)
  end
end

#update_on_sources(events) ⇒ Object



113
114
115
116
117
118
119
120
121
122
# File 'lib/contrast/utils/hash_digest.rb', line 113

def update_on_sources events
  return unless events&.any?

  events.each do |event|
    event.event_sources.each do |source|
      update(source.type)
      update(source.name)
    end
  end
end