Commit 72e21af5 authored by Rémy Coutable's avatar Rémy Coutable

Merge branch '13034-update-dast-report-fixture' into 'master'

Update DAST report fixture, Fix deduplication logic

See merge request gitlab-org/gitlab!18688
parents e3b96f13 e142ff53
......@@ -77,9 +77,10 @@ module Security
occurrence.identifiers.each do |identifier|
# TODO: remove .downcase here after the DAST parser is harmonized to the common library identifiers' keys format
# See https://gitlab.com/gitlab-org/gitlab/issues/11976#note_191257912
next if identifier.external_type.casecmp("cwe").zero? # ignored because it describes a class of vulnerabilities
next if %w[cwe wasc].include?(identifier.external_type.downcase) # ignored because these describe a class of vulnerabilities
seen = check_or_mark_seen_identifier!(identifier, occurrence.location.fingerprint, seen_identifiers)
break if seen
end
......
---
title: Fix deduplication of WASC vulnerabilities in the Security dashboard
merge_request: 17778
author:
type: fixed
......@@ -95,5 +95,11 @@ FactoryBot.define do
build.job_artifacts << create(:ee_ci_job_artifact, :corrupted_license_management_report, job: build)
end
end
trait :low_severity_dast_report do
after(:build) do |build|
build.job_artifacts << create(:ee_ci_job_artifact, :low_severity_dast_report, job: build)
end
end
end
end
......@@ -182,6 +182,16 @@ FactoryBot.define do
end
end
trait :low_severity_dast_report do
file_format { :raw }
file_type { :dast }
after(:build) do |artifact, _|
artifact.file = fixture_file_upload(
Rails.root.join('ee/spec/fixtures/security_reports/master/gl-dast-report-low-severity.json'), 'text/plain')
end
end
trait :metrics do
file_format { :gzip }
file_type { :metrics }
......
......@@ -3,6 +3,22 @@
require 'spec_helper'
describe Security::PipelineVulnerabilitiesFinder do
class NoDeduplicationMergeReportsService
def initialize(*source_reports)
@source_reports = source_reports
end
def execute
@source_reports.last
end
end
def disable_deduplication
allow(::Security::MergeReportsService).to receive(:new) do |*args|
NoDeduplicationMergeReportsService.new(*args)
end
end
describe '#execute' do
set(:project) { create(:project, :repository) }
set(:pipeline) { create(:ci_pipeline, :success, project: project) }
......@@ -18,12 +34,20 @@ describe Security::PipelineVulnerabilitiesFinder do
set(:artifact_sast) { create(:ee_ci_job_artifact, :sast, job: build_sast, project: project) }
let(:cs_count) { read_fixture(artifact_cs)['unapproved'].count }
let(:dast_count) { read_fixture(artifact_dast)['site'].first['alerts'].first['instances'].count }
let(:ds_count) { read_fixture(artifact_ds)['vulnerabilities'].count }
let(:sast_count) { read_fixture(artifact_sast)['vulnerabilities'].count }
let(:dast_count) do
read_fixture(artifact_dast)['site'].sum do |site|
site['alerts'].sum do |alert|
alert['instances'].size
end
end
end
before do
stub_licensed_features(sast: true, dependency_scanning: true, container_scanning: true, dast: true)
# Stub out deduplication, if not done the expectations will vary based on the fixtures (which may/may not have duplicates)
disable_deduplication
end
subject { described_class.new(pipeline: pipeline, params: params).execute }
......@@ -121,7 +145,7 @@ describe Security::PipelineVulnerabilitiesFinder do
subject { described_class.new(pipeline: pipeline).execute }
it 'returns all vulnerability severity levels' do
expect(subject.map(&:severity).uniq).to match_array %w[undefined unknown low medium high critical]
expect(subject.map(&:severity).uniq).to match_array %w[undefined unknown low medium high critical info]
end
end
......@@ -159,7 +183,7 @@ describe Security::PipelineVulnerabilitiesFinder do
it 'filters by all params' do
expect(subject.count).to eq cs_count + dast_count + ds_count + sast_count
expect(subject.map(&:confidence).uniq).to match_array %w[undefined unknown low medium high]
expect(subject.map(&:severity).uniq).to match_array %w[undefined unknown low medium high critical]
expect(subject.map(&:severity).uniq).to match_array %w[undefined unknown low medium high critical info]
end
end
......
{
"site": {
"alerts": [
{
"sourceid": "3",
"wascid": "15",
"cweid": "16",
"reference": "<p>http://msdn.microsoft.com/en-us/library/ie/gg622941%28v=vs.85%29.aspx</p><p>https://www.owasp.org/index.php/List_of_useful_HTTP_headers</p>",
"otherinfo": "<p>This issue still applies to error type pages (401, 403, 500, etc) as those pages are often still affected by injection issues, in which case there is still concern for browsers sniffing pages away from their actual content type.</p><p>At \"High\" threshold this scanner will not alert on client or server error responses.</p>",
"solution": "<p>Ensure that the application/web server sets the Content-Type header appropriately, and that it sets the X-Content-Type-Options header to 'nosniff' for all web pages.</p><p>If possible, ensure that the end user uses a standards-compliant and modern web browser that does not perform MIME-sniffing at all, or that can be directed by the web application/web server to not perform MIME-sniffing.</p>",
"count": "2",
"pluginid": "10021",
"alert": "X-Content-Type-Options Header Missing",
"name": "X-Content-Type-Options Header Missing",
"riskcode": "1",
"confidence": "2",
"riskdesc": "Low (Medium)",
"desc": "<p>The Anti-MIME-Sniffing header X-Content-Type-Options was not set to 'nosniff'. This allows older versions of Internet Explorer and Chrome to perform MIME-sniffing on the response body, potentially causing the response body to be interpreted and displayed as a content type other than the declared content type. Current (early 2014) and legacy versions of Firefox will use the declared content type (if one is set), rather than performing MIME-sniffing.</p>",
"instances": [
{
"param": "X-Content-Type-Options",
"method": "GET",
"uri": "http://bikebilly-spring-auto-devops-review-feature-br-3y2gpb.35.192.176.43.xip.io"
},
{
"param": "X-Content-Type-Options",
"method": "GET",
"uri": "http://bikebilly-spring-auto-devops-review-feature-br-3y2gpb.35.192.176.43.xip.io/"
}
]
}
],
"@ssl": "false",
"@port": "80",
"@host": "bikebilly-spring-auto-devops-review-feature-br-3y2gpb.35.192.176.43.xip.io",
"@name": "http://bikebilly-spring-auto-devops-review-feature-br-3y2gpb.35.192.176.43.xip.io"
},
"@generated": "Fri, 13 Apr 2018 09:22:01",
"@version": "2.7.0"
}
{
"site": [
{
"@port": "8080",
"@host": "goat",
"@name": "http://goat:8080",
"alerts": [
{
"count": "4",
"riskdesc": "Low (Medium)",
"name": "Absence of Anti-CSRF Tokens",
"reference": "<p>http://projects.webappsec.org/Cross-Site-Request-Forgery</p><p>http://cwe.mitre.org/data/definitions/352.html</p>",
"otherinfo": "<p>No known Anti-CSRF token [anticsrf, CSRFToken, __RequestVerificationToken, csrfmiddlewaretoken, authenticity_token, OWASP_CSRFTOKEN, anoncsrf, csrf_token, _csrf, _csrfSecret] was found in the following HTML form: [Form 1: \"exampleInputEmail1\" \"exampleInputPassword1\" ].</p>",
"sourceid": "3",
"confidence": "2",
"alert": "Absence of Anti-CSRF Tokens",
"instances": [
{
"evidence": "<form method=\"POST\" style=\"width: 200px;\" action=\"/WebGoat/login\">",
"uri": "http://goat:8080/WebGoat/login",
"method": "GET"
},
{
"evidence": "<form method=\"POST\" style=\"width: 200px;\" action=\"/WebGoat/login\">",
"uri": "http://goat:8080/WebGoat/login?error",
"method": "GET"
},
{
"evidence": "<form class=\"form-horizontal\" action=\"/WebGoat/register.mvc\" method=\"POST\">",
"uri": "http://goat:8080/WebGoat/registration",
"method": "GET"
},
{
"evidence": "<form class=\"form-horizontal\" action=\"/WebGoat/register.mvc\" method=\"POST\">",
"uri": "http://goat:8080/WebGoat/register.mvc",
"method": "POST"
}
],
"pluginid": "10202",
"riskcode": "1",
"wascid": "9",
"solution": "<p>Phase: Architecture and Design</p><p>Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid.</p><p>For example, use anti-CSRF packages such as the OWASP CSRFGuard.</p><p></p><p>Phase: Implementation</p><p>Ensure that your application is free of cross-site scripting issues, because most CSRF defenses can be bypassed using attacker-controlled script.</p><p></p><p>Phase: Architecture and Design</p><p>Generate a unique nonce for each form, place the nonce into the form, and verify the nonce upon receipt of the form. Be sure that the nonce is not predictable (CWE-330).</p><p>Note that this can be bypassed using XSS.</p><p></p><p>Identify especially dangerous operations. When the user performs a dangerous operation, send a separate confirmation request to ensure that the user intended to perform that operation.</p><p>Note that this can be bypassed using XSS.</p><p></p><p>Use the ESAPI Session Management control.</p><p>This control includes a component for CSRF.</p><p></p><p>Do not use the GET method for any request that triggers a state change.</p><p></p><p>Phase: Implementation</p><p>Check the HTTP Referer header to see if the request originated from an expected page. This could break legitimate functionality, because users or proxies may have disabled sending the Referer for privacy reasons.</p>",
"cweid": "352",
"desc": "<p>No Anti-CSRF tokens were found in a HTML submission form.</p><p>A cross-site request forgery is an attack that involves forcing a victim to send an HTTP request to a target destination without their knowledge or intent in order to perform an action as the victim. The underlying cause is application functionality using predictable URL/form actions in a repeatable way. The nature of the attack is that CSRF exploits the trust that a web site has for a user. By contrast, cross-site scripting (XSS) exploits the trust that a user has for a web site. Like XSS, CSRF attacks are not necessarily cross-site, but they can be. Cross-site request forgery is also known as CSRF, XSRF, one-click attack, session riding, confused deputy, and sea surf.</p><p></p><p>CSRF attacks are effective in a number of situations, including:</p><p> * The victim has an active session on the target site.</p><p> * The victim is authenticated via HTTP auth on the target site.</p><p> * The victim is on the same local network as the target site.</p><p></p><p>CSRF has primarily been used to perform an action against a target site using the victim's privileges, but recent techniques have been discovered to disclose information by gaining access to the response. The risk of information disclosure is dramatically increased when the target site is vulnerable to XSS, because XSS can be used as a platform for CSRF, allowing the attack to operate within the bounds of the same-origin policy.</p>"
},
{
"count": "2",
"riskdesc": "Low (Medium)",
"name": "Cookie Without SameSite Attribute",
"reference": "<p>https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site</p>",
"sourceid": "3",
"confidence": "2",
"alert": "Cookie Without SameSite Attribute",
"instances": [
{
"evidence": "Set-Cookie: JSESSIONID",
"uri": "http://goat:8080/WebGoat/logout",
"param": "JSESSIONID",
"method": "GET"
},
{
"evidence": "Set-Cookie: JSESSIONID",
"uri": "http://goat:8080/WebGoat/login?logout",
"param": "JSESSIONID",
"method": "GET"
}
],
"pluginid": "10054",
"riskcode": "1",
"wascid": "13",
"solution": "<p>Ensure that the SameSite attribute is set to either 'lax' or ideally 'strict' for all cookies.</p>",
"cweid": "16",
"desc": "<p>A cookie has been set without the SameSite attribute, which means that the cookie can be sent as a result of a 'cross-site' request. The SameSite attribute is an effective counter measure to cross-site request forgery, cross-site script inclusion, and timing attacks.</p>"
},
{
"count": "2",
"riskdesc": "Informational (Low)",
"name": "Loosely Scoped Cookie",
"reference": "<p>https://tools.ietf.org/html/rfc6265#section-4.1</p><p>https://www.owasp.org/index.php/Testing_for_cookies_attributes_(OTG-SESS-002)</p><p>http://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_cookies</p>",
"otherinfo": "<p>The origin domain used for comparison was: </p><p>goat</p><p>JSESSIONID=78EC2C9D7CE583610DCC7826EE416D7F</p><p></p>",
"sourceid": "3",
"confidence": "1",
"alert": "Loosely Scoped Cookie",
"instances": [
{
"uri": "http://goat:8080/WebGoat/login?logout",
"method": "GET"
},
{
"uri": "http://goat:8080/WebGoat/logout",
"method": "GET"
}
],
"pluginid": "90033",
"riskcode": "0",
"wascid": "15",
"solution": "<p>Always scope cookies to a FQDN (Fully Qualified Domain Name).</p>",
"cweid": "565",
"desc": "<p>Cookies can be scoped by domain or path. This check is only concerned with domain scope.The domain scope applied to a cookie determines which domains can access it. For example, a cookie can be scoped strictly to a subdomain e.g. www.nottrusted.com, or loosely scoped to a parent domain e.g. nottrusted.com. In the latter case, any subdomain of nottrusted.com can access the cookie. Loosely scoped cookies are common in mega-applications like google.com and live.com. Cookies set from a subdomain like app.foo.bar are transmitted only to that domain by the browser. However, cookies scoped to a parent-level domain may be transmitted to the parent, or any subdomain of the parent.</p>"
},
{
"count": "4",
"riskdesc": "Informational (Medium)",
"name": "Information Disclosure - Suspicious Comments",
"reference": "<p></p>",
"otherinfo": "<p><!--<button type=\"button\" id=\"admin-button\" class=\"btn btn-default right_nav_button\" title=\"Administrator\">--></p><p><!--<button type=\"button\" id=\"user-management\" class=\"btn btn-default right_nav_button\"--></p><p><!--title=\"User management\">--></p><p></p>",
"sourceid": "3",
"confidence": "2",
"alert": "Information Disclosure - Suspicious Comments",
"instances": [
{
"uri": "http://goat:8080/WebGoat/start.mvc",
"method": "GET"
},
{
"uri": "http://goat:8080/WebGoat/js/html5shiv.js",
"method": "GET"
},
{
"uri": "http://goat:8080/WebGoat/js/modernizr-2.6.2.min.js",
"method": "GET"
},
{
"uri": "http://goat:8080/WebGoat/js/respond.min.js",
"method": "GET"
}
],
"pluginid": "10027",
"riskcode": "0",
"wascid": "13",
"solution": "<p>Remove all comments that return information that may help an attacker and fix any underlying problems they refer to.</p>",
"cweid": "200",
"desc": "<p>The response appears to contain suspicious comments which may help an attacker.</p>"
},
{
"count": "5",
"riskdesc": "Informational (Low)",
"name": "Timestamp Disclosure - Unix",
"reference": "<p>https://www.owasp.org/index.php/Top_10_2013-A6-Sensitive_Data_Exposure</p><p>http://projects.webappsec.org/w/page/13246936/Information%20Leakage</p>",
"otherinfo": "<p>00000000, which evaluates to: 1970-01-01 00:00:00</p>",
"sourceid": "3",
"confidence": "1",
"alert": "Timestamp Disclosure - Unix",
"instances": [
{
"evidence": "00000000",
"uri": "http://goat:8080/WebGoat/plugins/bootstrap/css/bootstrap.min.css",
"method": "GET"
},
{
"evidence": "33333333",
"uri": "http://goat:8080/WebGoat/plugins/bootstrap/css/bootstrap.min.css",
"method": "GET"
},
{
"evidence": "42857143",
"uri": "http://goat:8080/WebGoat/plugins/bootstrap/css/bootstrap.min.css",
"method": "GET"
},
{
"evidence": "80000000",
"uri": "http://goat:8080/WebGoat/plugins/bootstrap/css/bootstrap.min.css",
"method": "GET"
},
{
"evidence": "66666667",
"uri": "http://goat:8080/WebGoat/plugins/bootstrap/css/bootstrap.min.css",
"method": "GET"
}
],
"pluginid": "10096",
"riskcode": "0",
"wascid": "13",
"solution": "<p>Manually confirm that the timestamp data is not sensitive, and that the data cannot be aggregated to disclose exploitable patterns.</p>",
"cweid": "200",
"desc": "<p>A timestamp was disclosed by the application/web server - Unix</p>"
},
{
"count": "2",
"riskdesc": "Low (Medium)",
"name": "Cookie No HttpOnly Flag",
"reference": "<p>http://www.owasp.org/index.php/HttpOnly</p>",
"sourceid": "3",
"confidence": "2",
"alert": "Cookie No HttpOnly Flag",
"instances": [
{
"evidence": "Set-Cookie: JSESSIONID",
"uri": "http://goat:8080/WebGoat/login?logout",
"param": "JSESSIONID",
"method": "GET"
},
{
"evidence": "Set-Cookie: JSESSIONID",
"uri": "http://goat:8080/WebGoat/logout",
"param": "JSESSIONID",
"method": "GET"
}
],
"pluginid": "10010",
"riskcode": "1",
"wascid": "13",
"solution": "<p>Ensure that the HttpOnly flag is set for all cookies.</p>",
"cweid": "16",
"desc": "<p>A cookie has been set without the HttpOnly flag, which means that the cookie can be accessed by JavaScript. If a malicious script can be run on this page then the cookie will be accessible and can be transmitted to another site. If this is a session cookie then session hijacking may be possible.</p>"
},
{
"count": "1",
"riskdesc": "Informational (Low)",
"name": "Charset Mismatch (Header Versus Meta Content-Type Charset)",
"reference": "<p>http://code.google.com/p/browsersec/wiki/Part2#Character_set_handling_and_detection</p>",
"otherinfo": "<p>There was a charset mismatch between the HTTP Header and the META content-type encoding declarations: [UTF-8] and [ISO-8859-1] do not match.</p>",
"sourceid": "3",
"confidence": "1",
"alert": "Charset Mismatch (Header Versus Meta Content-Type Charset)",
"instances": [
{
"uri": "http://goat:8080/WebGoat/start.mvc",
"method": "GET"
}
],
"pluginid": "90011",
"riskcode": "0",
"wascid": "15",
"solution": "<p>Force UTF-8 for all text content in both the HTTP header and meta tags in HTML or encoding declarations in XML.</p>",
"cweid": "16",
"desc": "<p>This check identifies responses where the HTTP Content-Type header declares a charset different from the charset defined by the body of the HTML or XML. When there's a charset mismatch between the HTTP header and content body Web browsers can be forced into an undesirable content-sniffing mode to determine the content's correct character set.</p><p></p><p>An attacker could manipulate content on the page to be interpreted in an encoding of their choice. For example, if an attacker can control content at the beginning of the page, they could inject script using UTF-7 encoded text and manipulate some browsers into interpreting that text.</p>"
}
],
"@ssl": "false"
}
],
"spider": {
"progress": "100",
"state": "FINISHED",
"result": {
"urlsIoError": [],
"urlsOutOfScope": [
"http://getbootstrap.com/",
"http://daneden.me/animate",
"http://fontawesome.io/",
"https://github.com/twbs/bootstrap/blob/master/LICENSE",
"https://github.com/nickpettit/glide",
"http://fontawesome.io/license"
],
"urlsInScope": [
{
"url": "http://goat:8080",
"statusReason": "",
"reasonNotProcessed": "Not Text",
"processed": "false",
"method": "GET",
"statusCode": "404"
},
{
"url": "http://goat:8080/robots.txt",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "404"
},
{
"url": "http://goat:8080/sitemap.xml",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "404"
},
{
"url": "http://goat:8080/WebGoat",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "302"
},
{
"url": "http://goat:8080/WebGoat/attack",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "302"
},
{
"url": "http://goat:8080/",
"statusReason": "",
"reasonNotProcessed": "Not Text",
"processed": "false",
"method": "GET",
"statusCode": "404"
},
{
"url": "http://goat:8080/WebGoat/",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "302"
},
{
"url": "http://goat:8080/WebGoat/start.mvc",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/welcome.mvc",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "302"
},
{
"url": "http://goat:8080/WebGoat/logout",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "302"
},
{
"url": "http://goat:8080/WebGoat/css/main.css",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/images/favicon.ico",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "404"
},
{
"url": "http://goat:8080/WebGoat/plugins/bootstrap/css/bootstrap.min.css",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/css/font-awesome.min.css",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/css/coderay.css",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/css/animate.css",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/js/modernizr-2.6.2.min.js",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/css/lessons.css",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/js/html5shiv.js",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/js/respond.min.js",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/js/libs/require.min.js",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/login?logout",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "302"
},
{
"url": "http://goat:8080/WebGoat/login",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/login",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "POST",
"statusCode": "302"
},
{
"url": "http://goat:8080/WebGoat/login?error",
"statusReason": "",
"reasonNotProcessed": "Max Depth",
"processed": "false",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/registration",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/register.mvc",
"statusReason": "",
"reasonNotProcessed": "Max Depth",
"processed": "false",
"method": "POST",
"statusCode": "200"
}
]
}
},
"@generated": "Fri, 13 Apr 2018 09:22:01",
"@version": "2.7.0"
}
{
"site": [
{
"@port": "8080",
"@host": "goat",
"@name": "http://goat:8080",
"alerts": [
{
"count": "4",
"riskdesc": "High (Medium)",
"name": "Anti CSRF Tokens Scanner",
"reference": "<p>http://projects.webappsec.org/Cross-Site-Request-Forgery</p><p>http://cwe.mitre.org/data/definitions/352.html</p>",
"sourceid": "1",
"confidence": "2",
"alert": "Anti CSRF Tokens Scanner",
"instances": [
{
"evidence": "<form method=\"POST\" style=\"width: 200px;\" action=\"/WebGoat/login\">",
"uri": "http://goat:8080/WebGoat/login?error",
"method": "GET"
},
{
"evidence": "<form method=\"POST\" style=\"width: 200px;\" action=\"/WebGoat/login\">",
"uri": "http://goat:8080/WebGoat/login",
"method": "GET"
},
{
"evidence": "<form class=\"form-horizontal\" action=\"/WebGoat/register.mvc\" method=\"POST\">",
"uri": "http://goat:8080/WebGoat/register.mvc",
"method": "POST"
},
{
"evidence": "<form class=\"form-horizontal\" action=\"/WebGoat/register.mvc\" method=\"POST\">",
"uri": "http://goat:8080/WebGoat/registration",
"method": "GET"
}
],
"pluginid": "20012",
"riskcode": "3",
"wascid": "9",
"solution": "<p>Phase: Architecture and Design</p><p>Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid.</p><p>For example, use anti-CSRF packages such as the OWASP CSRFGuard.</p><p></p><p>Phase: Implementation</p><p>Ensure that your application is free of cross-site scripting issues, because most CSRF defenses can be bypassed using attacker-controlled script.</p><p></p><p>Phase: Architecture and Design</p><p>Generate a unique nonce for each form, place the nonce into the form, and verify the nonce upon receipt of the form. Be sure that the nonce is not predictable (CWE-330).</p><p>Note that this can be bypassed using XSS.</p><p></p><p>Identify especially dangerous operations. When the user performs a dangerous operation, send a separate confirmation request to ensure that the user intended to perform that operation.</p><p>Note that this can be bypassed using XSS.</p><p></p><p>Use the ESAPI Session Management control.</p><p>This control includes a component for CSRF.</p><p></p><p>Do not use the GET method for any request that triggers a state change.</p><p></p><p>Phase: Implementation</p><p>Check the HTTP Referer header to see if the request originated from an expected page. This could break legitimate functionality, because users or proxies may have disabled sending the Referer for privacy reasons.</p>",
"cweid": "352",
"desc": "<p>A cross-site request forgery is an attack that involves forcing a victim to send an HTTP request to a target destination without their knowledge or intent in order to perform an action as the victim. The underlying cause is application functionality using predictable URL/form actions in a repeatable way. The nature of the attack is that CSRF exploits the trust that a web site has for a user. By contrast, cross-site scripting (XSS) exploits the trust that a user has for a web site. Like XSS, CSRF attacks are not necessarily cross-site, but they can be. Cross-site request forgery is also known as CSRF, XSRF, one-click attack, session riding, confused deputy, and sea surf.</p><p></p><p>CSRF attacks are effective in a number of situations, including:</p><p> * The victim has an active session on the target site.</p><p> * The victim is authenticated via HTTP auth on the target site.</p><p> * The victim is on the same local network as the target site.</p><p></p><p>CSRF has primarily been used to perform an action against a target site using the victim's privileges, but recent techniques have been discovered to disclose information by gaining access to the response. The risk of information disclosure is dramatically increased when the target site is vulnerable to XSS, because XSS can be used as a platform for CSRF, allowing the attack to operate within the bounds of the same-origin policy.</p>"
},
{
"count": "4",
"riskdesc": "Low (Medium)",
"name": "Absence of Anti-CSRF Tokens",
"reference": "<p>http://projects.webappsec.org/Cross-Site-Request-Forgery</p><p>http://cwe.mitre.org/data/definitions/352.html</p>",
"otherinfo": "<p>No known Anti-CSRF token [anticsrf, CSRFToken, __RequestVerificationToken, csrfmiddlewaretoken, authenticity_token, OWASP_CSRFTOKEN, anoncsrf, csrf_token, _csrf, _csrfSecret] was found in the following HTML form: [Form 1: \"exampleInputEmail1\" \"exampleInputPassword1\" ].</p>",
"sourceid": "3",
"wascid": "15",
"cweid": "16",
"reference": "<p>http://msdn.microsoft.com/en-us/library/ie/gg622941%28v=vs.85%29.aspx</p><p>https://www.owasp.org/index.php/List_of_useful_HTTP_headers</p>",
"otherinfo": "<p>This issue still applies to error type pages (401, 403, 500, etc) as those pages are often still affected by injection issues, in which case there is still concern for browsers sniffing pages away from their actual content type.</p><p>At \"High\" threshold this scanner will not alert on client or server error responses.</p>",
"solution": "<p>Ensure that the application/web server sets the Content-Type header appropriately, and that it sets the X-Content-Type-Options header to 'nosniff' for all web pages.</p><p>If possible, ensure that the end user uses a standards-compliant and modern web browser that does not perform MIME-sniffing at all, or that can be directed by the web application/web server to not perform MIME-sniffing.</p>",
"confidence": "2",
"alert": "Absence of Anti-CSRF Tokens",
"instances": [
{
"evidence": "<form method=\"POST\" style=\"width: 200px;\" action=\"/WebGoat/login\">",
"uri": "http://goat:8080/WebGoat/login",
"method": "GET"
},
{
"evidence": "<form method=\"POST\" style=\"width: 200px;\" action=\"/WebGoat/login\">",
"uri": "http://goat:8080/WebGoat/login?error",
"method": "GET"
},
{
"evidence": "<form class=\"form-horizontal\" action=\"/WebGoat/register.mvc\" method=\"POST\">",
"uri": "http://goat:8080/WebGoat/registration",
"method": "GET"
},
{
"evidence": "<form class=\"form-horizontal\" action=\"/WebGoat/register.mvc\" method=\"POST\">",
"uri": "http://goat:8080/WebGoat/register.mvc",
"method": "POST"
}
],
"pluginid": "10202",
"riskcode": "1",
"wascid": "9",
"solution": "<p>Phase: Architecture and Design</p><p>Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid.</p><p>For example, use anti-CSRF packages such as the OWASP CSRFGuard.</p><p></p><p>Phase: Implementation</p><p>Ensure that your application is free of cross-site scripting issues, because most CSRF defenses can be bypassed using attacker-controlled script.</p><p></p><p>Phase: Architecture and Design</p><p>Generate a unique nonce for each form, place the nonce into the form, and verify the nonce upon receipt of the form. Be sure that the nonce is not predictable (CWE-330).</p><p>Note that this can be bypassed using XSS.</p><p></p><p>Identify especially dangerous operations. When the user performs a dangerous operation, send a separate confirmation request to ensure that the user intended to perform that operation.</p><p>Note that this can be bypassed using XSS.</p><p></p><p>Use the ESAPI Session Management control.</p><p>This control includes a component for CSRF.</p><p></p><p>Do not use the GET method for any request that triggers a state change.</p><p></p><p>Phase: Implementation</p><p>Check the HTTP Referer header to see if the request originated from an expected page. This could break legitimate functionality, because users or proxies may have disabled sending the Referer for privacy reasons.</p>",
"cweid": "352",
"desc": "<p>No Anti-CSRF tokens were found in a HTML submission form.</p><p>A cross-site request forgery is an attack that involves forcing a victim to send an HTTP request to a target destination without their knowledge or intent in order to perform an action as the victim. The underlying cause is application functionality using predictable URL/form actions in a repeatable way. The nature of the attack is that CSRF exploits the trust that a web site has for a user. By contrast, cross-site scripting (XSS) exploits the trust that a user has for a web site. Like XSS, CSRF attacks are not necessarily cross-site, but they can be. Cross-site request forgery is also known as CSRF, XSRF, one-click attack, session riding, confused deputy, and sea surf.</p><p></p><p>CSRF attacks are effective in a number of situations, including:</p><p> * The victim has an active session on the target site.</p><p> * The victim is authenticated via HTTP auth on the target site.</p><p> * The victim is on the same local network as the target site.</p><p></p><p>CSRF has primarily been used to perform an action against a target site using the victim's privileges, but recent techniques have been discovered to disclose information by gaining access to the response. The risk of information disclosure is dramatically increased when the target site is vulnerable to XSS, because XSS can be used as a platform for CSRF, allowing the attack to operate within the bounds of the same-origin policy.</p>"
},
{
"count": "2",
"pluginid": "10021",
"alert": "X-Content-Type-Options Header Missing",
"name": "X-Content-Type-Options Header Missing",
"riskdesc": "Low (Medium)",
"name": "Cookie Without SameSite Attribute",
"reference": "<p>https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site</p>",
"sourceid": "3",
"confidence": "2",
"alert": "Cookie Without SameSite Attribute",
"instances": [
{
"evidence": "Set-Cookie: JSESSIONID",
"uri": "http://goat:8080/WebGoat/logout",
"param": "JSESSIONID",
"method": "GET"
},
{
"evidence": "Set-Cookie: JSESSIONID",
"uri": "http://goat:8080/WebGoat/login?logout",
"param": "JSESSIONID",
"method": "GET"
}
],
"pluginid": "10054",
"riskcode": "1",
"wascid": "13",
"solution": "<p>Ensure that the SameSite attribute is set to either 'lax' or ideally 'strict' for all cookies.</p>",
"cweid": "16",
"desc": "<p>A cookie has been set without the SameSite attribute, which means that the cookie can be sent as a result of a 'cross-site' request. The SameSite attribute is an effective counter measure to cross-site request forgery, cross-site script inclusion, and timing attacks.</p>"
},
{
"count": "2",
"riskdesc": "Informational (Low)",
"name": "Loosely Scoped Cookie",
"reference": "<p>https://tools.ietf.org/html/rfc6265#section-4.1</p><p>https://www.owasp.org/index.php/Testing_for_cookies_attributes_(OTG-SESS-002)</p><p>http://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_cookies</p>",
"otherinfo": "<p>The origin domain used for comparison was: </p><p>goat</p><p>JSESSIONID=78EC2C9D7CE583610DCC7826EE416D7F</p><p></p>",
"sourceid": "3",
"confidence": "1",
"alert": "Loosely Scoped Cookie",
"instances": [
{
"uri": "http://goat:8080/WebGoat/login?logout",
"method": "GET"
},
{
"uri": "http://goat:8080/WebGoat/logout",
"method": "GET"
}
],
"pluginid": "90033",
"riskcode": "0",
"wascid": "15",
"solution": "<p>Always scope cookies to a FQDN (Fully Qualified Domain Name).</p>",
"cweid": "565",
"desc": "<p>Cookies can be scoped by domain or path. This check is only concerned with domain scope.The domain scope applied to a cookie determines which domains can access it. For example, a cookie can be scoped strictly to a subdomain e.g. www.nottrusted.com, or loosely scoped to a parent domain e.g. nottrusted.com. In the latter case, any subdomain of nottrusted.com can access the cookie. Loosely scoped cookies are common in mega-applications like google.com and live.com. Cookies set from a subdomain like app.foo.bar are transmitted only to that domain by the browser. However, cookies scoped to a parent-level domain may be transmitted to the parent, or any subdomain of the parent.</p>"
},
{
"count": "4",
"riskdesc": "Informational (Medium)",
"name": "Information Disclosure - Suspicious Comments",
"reference": "<p></p>",
"otherinfo": "<p><!--<button type=\"button\" id=\"admin-button\" class=\"btn btn-default right_nav_button\" title=\"Administrator\">--></p><p><!--<button type=\"button\" id=\"user-management\" class=\"btn btn-default right_nav_button\"--></p><p><!--title=\"User management\">--></p><p></p>",
"sourceid": "3",
"confidence": "2",
"alert": "Information Disclosure - Suspicious Comments",
"instances": [
{
"uri": "http://goat:8080/WebGoat/start.mvc",
"method": "GET"
},
{
"uri": "http://goat:8080/WebGoat/js/html5shiv.js",
"method": "GET"
},
{
"uri": "http://goat:8080/WebGoat/js/modernizr-2.6.2.min.js",
"method": "GET"
},
{
"uri": "http://goat:8080/WebGoat/js/respond.min.js",
"method": "GET"
}
],
"pluginid": "10027",
"riskcode": "0",
"wascid": "13",
"solution": "<p>Remove all comments that return information that may help an attacker and fix any underlying problems they refer to.</p>",
"cweid": "200",
"desc": "<p>The response appears to contain suspicious comments which may help an attacker.</p>"
},
{
"count": "5",
"riskdesc": "Informational (Low)",
"name": "Timestamp Disclosure - Unix",
"reference": "<p>https://www.owasp.org/index.php/Top_10_2013-A6-Sensitive_Data_Exposure</p><p>http://projects.webappsec.org/w/page/13246936/Information%20Leakage</p>",
"otherinfo": "<p>00000000, which evaluates to: 1970-01-01 00:00:00</p>",
"sourceid": "3",
"confidence": "1",
"alert": "Timestamp Disclosure - Unix",
"instances": [
{
"evidence": "00000000",
"uri": "http://goat:8080/WebGoat/plugins/bootstrap/css/bootstrap.min.css",
"method": "GET"
},
{
"evidence": "33333333",
"uri": "http://goat:8080/WebGoat/plugins/bootstrap/css/bootstrap.min.css",
"method": "GET"
},
{
"evidence": "42857143",
"uri": "http://goat:8080/WebGoat/plugins/bootstrap/css/bootstrap.min.css",
"method": "GET"
},
{
"evidence": "80000000",
"uri": "http://goat:8080/WebGoat/plugins/bootstrap/css/bootstrap.min.css",
"method": "GET"
},
{
"evidence": "66666667",
"uri": "http://goat:8080/WebGoat/plugins/bootstrap/css/bootstrap.min.css",
"method": "GET"
}
],
"pluginid": "10096",
"riskcode": "0",
"wascid": "13",
"solution": "<p>Manually confirm that the timestamp data is not sensitive, and that the data cannot be aggregated to disclose exploitable patterns.</p>",
"cweid": "200",
"desc": "<p>A timestamp was disclosed by the application/web server - Unix</p>"
},
{
"count": "2",
"riskdesc": "Low (Medium)",
"desc": "<p>The Anti-MIME-Sniffing header X-Content-Type-Options was not set to 'nosniff'. This allows older versions of Internet Explorer and Chrome to perform MIME-sniffing on the response body, potentially causing the response body to be interpreted and displayed as a content type other than the declared content type. Current (early 2014) and legacy versions of Firefox will use the declared content type (if one is set), rather than performing MIME-sniffing.</p>",
"name": "Cookie No HttpOnly Flag",
"reference": "<p>http://www.owasp.org/index.php/HttpOnly</p>",
"sourceid": "3",
"confidence": "2",
"alert": "Cookie No HttpOnly Flag",
"instances": [
{
"param": "X-Content-Type-Options",
"method": "GET",
"uri": "http://bikebilly-spring-auto-devops-review-feature-br-3y2gpb.35.192.176.43.xip.io"
"evidence": "Set-Cookie: JSESSIONID",
"uri": "http://goat:8080/WebGoat/login?logout",
"param": "JSESSIONID",
"method": "GET"
},
{
"param": "X-Content-Type-Options",
"method": "GET",
"uri": "http://bikebilly-spring-auto-devops-review-feature-br-3y2gpb.35.192.176.43.xip.io/"
"evidence": "Set-Cookie: JSESSIONID",
"uri": "http://goat:8080/WebGoat/logout",
"param": "JSESSIONID",
"method": "GET"
}
]
],
"pluginid": "10010",
"riskcode": "1",
"wascid": "13",
"solution": "<p>Ensure that the HttpOnly flag is set for all cookies.</p>",
"cweid": "16",
"desc": "<p>A cookie has been set without the HttpOnly flag, which means that the cookie can be accessed by JavaScript. If a malicious script can be run on this page then the cookie will be accessible and can be transmitted to another site. If this is a session cookie then session hijacking may be possible.</p>"
},
{
"count": "1",
"riskdesc": "Informational (Low)",
"name": "Charset Mismatch (Header Versus Meta Content-Type Charset)",
"reference": "<p>http://code.google.com/p/browsersec/wiki/Part2#Character_set_handling_and_detection</p>",
"otherinfo": "<p>There was a charset mismatch between the HTTP Header and the META content-type encoding declarations: [UTF-8] and [ISO-8859-1] do not match.</p>",
"sourceid": "3",
"confidence": "1",
"alert": "Charset Mismatch (Header Versus Meta Content-Type Charset)",
"instances": [
{
"uri": "http://goat:8080/WebGoat/start.mvc",
"method": "GET"
}
],
"pluginid": "90011",
"riskcode": "0",
"wascid": "15",
"solution": "<p>Force UTF-8 for all text content in both the HTTP header and meta tags in HTML or encoding declarations in XML.</p>",
"cweid": "16",
"desc": "<p>This check identifies responses where the HTTP Content-Type header declares a charset different from the charset defined by the body of the HTML or XML. When there's a charset mismatch between the HTTP header and content body Web browsers can be forced into an undesirable content-sniffing mode to determine the content's correct character set.</p><p></p><p>An attacker could manipulate content on the page to be interpreted in an encoding of their choice. For example, if an attacker can control content at the beginning of the page, they could inject script using UTF-7 encoded text and manipulate some browsers into interpreting that text.</p>"
}
],
"@ssl": "false",
"@port": "80",
"@host": "bikebilly-spring-auto-devops-review-feature-br-3y2gpb.35.192.176.43.xip.io",
"@name": "http://bikebilly-spring-auto-devops-review-feature-br-3y2gpb.35.192.176.43.xip.io"
"@ssl": "false"
}
],
"spider": {
"progress": "100",
"state": "FINISHED",
"result": {
"urlsIoError": [],
"urlsOutOfScope": [
"http://getbootstrap.com/",
"http://daneden.me/animate",
"http://fontawesome.io/",
"https://github.com/twbs/bootstrap/blob/master/LICENSE",
"https://github.com/nickpettit/glide",
"http://fontawesome.io/license"
],
"urlsInScope": [
{
"url": "http://goat:8080",
"statusReason": "",
"reasonNotProcessed": "Not Text",
"processed": "false",
"method": "GET",
"statusCode": "404"
},
{
"url": "http://goat:8080/robots.txt",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "404"
},
{
"url": "http://goat:8080/sitemap.xml",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "404"
},
{
"url": "http://goat:8080/WebGoat",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "302"
},
{
"url": "http://goat:8080/WebGoat/attack",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "302"
},
{
"url": "http://goat:8080/",
"statusReason": "",
"reasonNotProcessed": "Not Text",
"processed": "false",
"method": "GET",
"statusCode": "404"
},
{
"url": "http://goat:8080/WebGoat/",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "302"
},
{
"url": "http://goat:8080/WebGoat/start.mvc",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/welcome.mvc",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "302"
},
{
"url": "http://goat:8080/WebGoat/logout",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "302"
},
{
"url": "http://goat:8080/WebGoat/css/main.css",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/images/favicon.ico",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "404"
},
{
"url": "http://goat:8080/WebGoat/plugins/bootstrap/css/bootstrap.min.css",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/css/font-awesome.min.css",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/css/coderay.css",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/css/animate.css",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/js/modernizr-2.6.2.min.js",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/css/lessons.css",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/js/html5shiv.js",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/js/respond.min.js",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/js/libs/require.min.js",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/login?logout",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "302"
},
{
"url": "http://goat:8080/WebGoat/login",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/login",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "POST",
"statusCode": "302"
},
{
"url": "http://goat:8080/WebGoat/login?error",
"statusReason": "",
"reasonNotProcessed": "Max Depth",
"processed": "false",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/registration",
"statusReason": "",
"reasonNotProcessed": "",
"processed": "true",
"method": "GET",
"statusCode": "200"
},
{
"url": "http://goat:8080/WebGoat/register.mvc",
"statusReason": "",
"reasonNotProcessed": "Max Depth",
"processed": "false",
"method": "POST",
"statusCode": "200"
}
]
}
},
"@generated": "Fri, 13 Apr 2018 09:22:01",
"@version": "2.7.0"
}
......@@ -18,8 +18,8 @@ describe Gitlab::Ci::Parsers::Security::Dast do
end
it 'parses all identifiers and occurrences' do
expect(report.occurrences.length).to eq(2)
expect(report.identifiers.length).to eq(3)
expect(report.occurrences.length).to eq(24)
expect(report.identifiers.length).to eq(15)
expect(report.scanners.length).to eq(1)
end
......@@ -28,10 +28,9 @@ describe Gitlab::Ci::Parsers::Security::Dast do
expect(location).to be_a(::Gitlab::Ci::Reports::Security::Locations::Dast)
expect(location).to have_attributes(
hostname: 'http://bikebilly-spring-auto-devops-review-feature-br-3y2gpb.35.192.176.43.xip.io',
hostname: 'http://goat:8080',
method_name: 'GET',
param: 'X-Content-Type-Options',
path: ''
path: '/WebGoat/login?error'
)
end
......@@ -40,8 +39,8 @@ describe Gitlab::Ci::Parsers::Security::Dast do
where(:attribute, :value) do
:report_type | 'dast'
:severity | 'low'
:confidence | 'medium'
:severity | 'info'
:confidence | 'low'
end
with_them do
......
......@@ -16,7 +16,7 @@ describe Gitlab::Ci::Parsers::Security::Formatters::Dast do
describe '#format_vulnerability' do
let(:instance) { file_vulnerability['instances'][1] }
let(:hostname) { 'http://bikebilly-spring-auto-devops-review-feature-br-3y2gpb.35.192.176.43.xip.io' }
let(:hostname) { 'http://goat:8080' }
let(:sanitized_desc) { file_vulnerability['desc'].gsub('<p>', '').gsub('</p>', '') }
let(:sanitized_solution) { file_vulnerability['solution'].gsub('<p>', '').gsub('</p>', '') }
let(:version) { parsed_report['@version'] }
......@@ -25,38 +25,38 @@ describe Gitlab::Ci::Parsers::Security::Formatters::Dast do
data = formatter.format(instance, hostname)
expect(data['category']).to eq('dast')
expect(data['message']).to eq('X-Content-Type-Options Header Missing')
expect(data['message']).to eq('Anti CSRF Tokens Scanner')
expect(data['description']).to eq(sanitized_desc)
expect(data['cve']).to eq('10021')
expect(data['severity']).to eq('low')
expect(data['cve']).to eq('20012')
expect(data['severity']).to eq('high')
expect(data['confidence']).to eq('medium')
expect(data['solution']).to eq(sanitized_solution)
expect(data['scanner']).to eq({ 'id' => 'zaproxy', 'name' => 'ZAProxy' })
expect(data['links']).to eq([{ 'url' => 'http://msdn.microsoft.com/en-us/library/ie/gg622941%28v=vs.85%29.aspx' },
{ 'url' => 'https://www.owasp.org/index.php/List_of_useful_HTTP_headers' }])
expect(data['links']).to eq([{ 'url' => 'http://projects.webappsec.org/Cross-Site-Request-Forgery' },
{ 'url' => 'http://cwe.mitre.org/data/definitions/352.html' }])
expect(data['identifiers'][0]).to eq({
'type' => 'ZAProxy_PluginId',
'name' => 'X-Content-Type-Options Header Missing',
'value' => '10021',
'name' => 'Anti CSRF Tokens Scanner',
'value' => '20012',
'url' => "https://github.com/zaproxy/zaproxy/blob/w2019-01-14/docs/scanners.md"
})
expect(data['identifiers'][1]).to eq({
'type' => 'CWE',
'name' => "CWE-16",
'value' => '16',
'url' => "https://cwe.mitre.org/data/definitions/16.html"
'name' => "CWE-352",
'value' => '352',
'url' => "https://cwe.mitre.org/data/definitions/352.html"
})
expect(data['identifiers'][2]).to eq({
'type' => 'WASC',
'name' => "WASC-15",
'value' => '15',
'name' => "WASC-9",
'value' => '9',
'url' => "http://projects.webappsec.org/w/page/13246974/Threat%20Classification%20Reference%20Grid"
})
expect(data['location']).to eq({
'param' => 'X-Content-Type-Options',
'param' => nil,
'method' => 'GET',
'hostname' => hostname,
'path' => '/'
'path' => '/WebGoat/login'
})
end
end
......
......@@ -137,7 +137,7 @@ describe Ci::Build do
expect(security_reports.get_report('sast').occurrences.size).to eq(33)
expect(security_reports.get_report('dependency_scanning').occurrences.size).to eq(4)
expect(security_reports.get_report('container_scanning').occurrences.size).to eq(8)
expect(security_reports.get_report('dast').occurrences.size).to eq(2)
expect(security_reports.get_report('dast').occurrences.size).to eq(20)
end
end
......
......@@ -12,6 +12,7 @@ describe Security::MergeReportsService, '#execute' do
let(:identifier_2_primary) { build(:ci_reports_security_identifier, external_id: 'VULN-2', external_type: 'scanner-2') }
let(:identifier_2_cve) { build(:ci_reports_security_identifier, external_id: 'CVE-2019-456', external_type: 'cve') }
let(:identifier_cwe) { build(:ci_reports_security_identifier, external_id: '789', external_type: 'cwe') }
let(:identifier_wasc) { build(:ci_reports_security_identifier, external_id: '13', external_type: 'wasc') }
let(:occurrence_id_1) do
build(:ci_reports_security_occurrence,
......@@ -63,7 +64,23 @@ describe Security::MergeReportsService, '#execute' do
)
end
let(:report_1_occurrences) { [occurrence_id_1, occurrence_id_2_loc_1, occurrence_cwe_2] }
let(:occurrence_wasc_1) do
build(:ci_reports_security_occurrence,
identifiers: [identifier_wasc],
scanner: scanner_1,
severity: :medium
)
end
let(:occurrence_wasc_2) do
build(:ci_reports_security_occurrence,
identifiers: [identifier_wasc],
scanner: scanner_2,
severity: :critical
)
end
let(:report_1_occurrences) { [occurrence_id_1, occurrence_id_2_loc_1, occurrence_cwe_2, occurrence_wasc_1] }
let(:report_1) do
build(
......@@ -74,11 +91,13 @@ describe Security::MergeReportsService, '#execute' do
)
end
let(:report_2_occurrences) { [occurrence_id_2_loc_2, occurrence_wasc_2] }
let(:report_2) do
build(
:ci_reports_security_report,
scanners: [scanner_2],
occurrences: [occurrence_id_2_loc_2],
occurrences: report_2_occurrences,
identifiers: occurrence_id_2_loc_2.identifiers
)
end
......@@ -109,14 +128,23 @@ describe Security::MergeReportsService, '#execute' do
identifier_1_cve,
identifier_2_primary,
identifier_2_cve,
identifier_cwe
identifier_cwe,
identifier_wasc
)
)
end
it 'deduplicates and sorts the vulnerabilities by severity (desc) then by compare key' do
it 'deduplicates (except cwe and wasc) and sorts the vulnerabilities by severity (desc) then by compare key' do
expect(subject.occurrences).to(
eq([occurrence_cwe_2, occurrence_cwe_1, occurrence_id_2_loc_2, occurrence_id_2_loc_1, occurrence_id_1])
eq([
occurrence_cwe_2,
occurrence_wasc_2,
occurrence_cwe_1,
occurrence_id_2_loc_2,
occurrence_id_2_loc_1,
occurrence_wasc_1,
occurrence_id_1
])
)
end
end
......@@ -35,7 +35,7 @@ describe Security::SyncReportsToApprovalRulesService, '#execute' do
context 'when only low-severity vulnerabilities are present' do
before do
create(:ee_ci_build, :success, :dast, name: 'dast_job', pipeline: pipeline, project: project)
create(:ee_ci_build, :success, :low_severity_dast_report, name: 'dast_job', pipeline: pipeline, project: project)
end
it 'lowers approvals_required count to zero' do
......@@ -56,10 +56,6 @@ describe Security::SyncReportsToApprovalRulesService, '#execute' do
end
it "won't change approvals_required count" do
expect(
pipeline.security_reports.reports.values.all?(&:unsafe_severity?)
).to be false
expect { subject }
.not_to change { report_approver_rule.reload.approvals_required }
end
......@@ -119,7 +115,7 @@ describe Security::SyncReportsToApprovalRulesService, '#execute' do
context 'when only low-severity vulnerabilities are present' do
before do
create(:ee_ci_build, :success, :dast, name: 'dast_job', pipeline: pipeline, project: project)
create(:ee_ci_build, :success, :low_severity_dast_report, name: 'dast_job', pipeline: pipeline, project: project)
end
it 'lowers approvals_required count to zero' do
......
......@@ -5,14 +5,14 @@ require 'pathname'
module QA
context 'Secure', :docker do
let(:number_of_dependencies_in_fixture) { 1309 }
let(:total_vuln_count) { 52 }
let(:total_vuln_count) { 54 }
let(:dependency_scan_vuln_count) { 4 }
let(:dependency_scan_example_vuln) { 'jQuery before 3.4.0' }
let(:container_scan_vuln_count) { 8 }
let(:container_scan_example_vuln) { 'CVE-2017-18269 in glibc' }
let(:sast_scan_vuln_count) { 33 }
let(:sast_scan_example_vuln) { 'Cipher with no integrity' }
let(:dast_scan_vuln_count) { 7 }
let(:dast_scan_vuln_count) { 9 }
let(:dast_scan_example_vuln) { 'Cookie Without SameSite Attribute' }
describe 'Security Reports' do
......@@ -101,7 +101,7 @@ module QA
end
filter_report_and_perform(dashboard, "DAST") do
expect(dashboard).to have_low_vulnerability_count_of 6
expect(dashboard).to have_low_vulnerability_count_of 8
end
end
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment