Class: Dev::Php::Audit

Inherits:
Object show all
Defined in:
lib/firespring_dev_commands/php/audit.rb

Overview

Class which contains commands and customizations for security audit reports

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data) ⇒ Audit

Returns a new instance of Audit.



11
12
13
# File 'lib/firespring_dev_commands/php/audit.rb', line 11

def initialize(data)
  @data = JSON.parse(Dev::Common.new.strip_non_json(data))
end

Instance Attribute Details

#dataObject

Returns the value of attribute data.



9
10
11
# File 'lib/firespring_dev_commands/php/audit.rb', line 9

def data
  @data
end

Instance Method Details

#cvss_to_severity(score) ⇒ Object

Take a given cvss scrore and map it to a severity string



66
67
68
69
70
71
72
# File 'lib/firespring_dev_commands/php/audit.rb', line 66

def cvss_to_severity(score)
  return Dev::Audit::Report::Level::LOW if score <= 3.9
  return Dev::Audit::Report::Level::MODERATE if score <= 6.9
  return Dev::Audit::Report::Level::HIGH if score <= 8.9

  Dev::Audit::Report::Level::CRITICAL
end

#severity(cve) ⇒ Object

Takes the give CVE number and looks it up on the NIST api Returns the highest severity reported (worst case scneario)



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/firespring_dev_commands/php/audit.rb', line 39

def severity(cve)
  # Sleep to make sure we don't get rate limited
  sleep(6)
  url = "https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=#{cve}"
  response = Net::HTTP.get_response(URI.parse(url))

  # If we can't talk to NIST, just assume the worst at 'unknown'
  raise "#{response.code} #{response.message}" unless response.is_a?(Net::HTTPSuccess)

  # Get the cve data out of the json body
  cve_data = JSON.parse(response.body)['vulnerabilities'].first['cve']

  # Sanity check to make sure it gave us the correct information
  raise 'returned cve did not matche expected' unless cve == cve_data['id']

  # Find the max cvss reported for this vulnerability
  max_cvss = cve_data['metrics']['cvssMetricV31']&.map { |it| it['cvssData']['baseScore'] }&.max.to_f

  # Map that severity to the correct level
  cvss_to_severity(max_cvss)
rescue => e
  LOG.error("Error looking up severity for #{cve}: #{e.message}")
  LOG.error('WARNING: Unable to determine severity - ignoring with UNKNOWN')
  Dev::Audit::Report::Level::UNKNOWN
end

#to_reportObject

Convert the php audit data to the standardized audit report object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/firespring_dev_commands/php/audit.rb', line 16

def to_report
  Dev::Audit::Report.new(
    data['advisories'].map do |_, v|
      # If there are multiple advisories for the same package, v changes from an array into a hash
      v = v.values if v.is_a?(Hash)

      # Iterate over the advisories and turn them into report items
      v.map do |it|
        Dev::Audit::Report::Item.new(
          id: it['advisoryId'],
          name: it['packageName'],
          severity: severity(it['cve']),
          title: it['title'],
          url: it['link'],
          version: it['affectedVersions']
        )
      end
    end.flatten
  )
end