-
Notifications
You must be signed in to change notification settings - Fork 115
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
227 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,227 @@ | ||
metadata: | ||
language: v1-beta | ||
name: "Insecure Content-Security-Policy" | ||
description: "This BCheck checks for 'insecure', 'outdated', or 'missing' Content-Security-Policy header values." | ||
author: "Kyle Gilligan" | ||
|
||
run for each: | ||
# Looped array of known insecure Content-Security-Policy header values. | ||
insecure_value = | ||
" 'unsafe-inline'", | ||
" 'unsafe-eval'", | ||
" *", | ||
" data:", | ||
" http:", | ||
" https:;", | ||
"//www.google.com", | ||
"//ajax.googleapis.com", | ||
"plugin-types", | ||
"prefetch-src", | ||
"report-uri", | ||
"block-all-mixed-content" | ||
# Note: The deprecated "referrer" value was removed from insecure_value due to causing false positives from the Referrer-Policy header. | ||
|
||
define: | ||
# Interchangable regex. | ||
csp = `Content-Security-Policy` | ||
cspCol = `Content-Security-Policy:` | ||
cspVal = `Content-Security-Policy: {insecure_value}` | ||
defaultSrc = `default-src` | ||
scriptSrc = `script-src` | ||
objectSrc = `object-src` | ||
requireTrustedTypesFor = `require-trusted-types-for` | ||
|
||
# Issue details as individual string texts. | ||
issueDetailMissingHeader = `A {csp} header appears to be missing from this webpage's HTTP response.` | ||
issueDetailFound = `A {insecure_value} value was found in the {csp} header.` | ||
issueDetailMissingDirective_defaultSrc = `The '{defaultSrc}' CSP directive has not been declared in the {csp} header.` | ||
issueDetailMissingDirective_scriptSrc = `The '{scriptSrc}' CSP directive has not been declared in the {csp} header.` | ||
issueDetailMissingDirective_objectSrc = `The '{objectSrc}' CSP directive has not been declared in the {csp} header.` | ||
issueDetailMissingDirective_requireTrustedTypesFor = `The '{requireTrustedTypesFor}' CSP directive has not been declared in the {csp} header.` | ||
|
||
# Issue notes as individual string texts. | ||
issueNote_Inline = `\nNote that '{cspVal}' permits client-controlled scripting like XSS (CWE 87).` | ||
issueNote_Eval = `\nNote that '{cspVal}' permits client-controllable usage of the insecure eval() function (CWE 95).` | ||
issueNote_Wildcard = `\nNote that using {insecure_value} values in a {csp} header risks use of overly-permissive whitelisting (CWE 942).` | ||
issueNote_Data = `\nNote that whitelisting a {insecure_value} URI scheme risks in-line XSS attacks & fails to encrypt resources via SSL/TLS/HTTPS encryption (CWE 79, CWE 829, CWE 319, CWE 311).` | ||
issueNote_Http = `Note that whitelisting a {insecure_value} URI scheme risks accepting resources transmitted without SSL/TLS/HTTPS encryption (CWE 319, CWE 311).` | ||
issueNote_HttpsWildcard = `\nNote that whitelisting a {insecure_value} URI scheme without fully including a complete URL domain equates to usage of a wildcard value (CWE 942).` | ||
issueNote_googledotcom = `\nWhitelisting resources passed through https://www.google.com risks this CSP from becoming bypassed due to this URL being known for hosting overly-permissive JSONP endpoints (CWE 693).` | ||
issueNote_ajaxgoogledotcom = `\nWhitelisting resources passed through | ||
https://ajax.googleapis.com/ risks this CSP from becoming ignored due to this URL being known for hosting overly-permissive JSON endpoints & AngularJS libraries (CWE 693).` | ||
issueNote_Deprecated = `\nNote that {cspVal} is considered a deprecated functionality (CWE 477).` | ||
issueNote_Src = `\nNote that not explicitly setting a '-src' CSP directive equates to usage of a wildcard value (CWE 942).` | ||
issueNote_RequireTrustedTypesFor = `\nThis CSP directive helps limit what user input can be injected into a webpage's Document Object Model (DOM).` | ||
|
||
# Issue remediations (for a missing 'Content-Security-Policy' header) as individual string texts. | ||
issueRemediationMissingHeader01 = `Verify if this webpage's HTTP response should provide a {csp} header.\nPlease ensure only safe values become used.` | ||
issueRemediationMissingHeader02 = `\nNote that static file types will not need a {csp} header, so ensure this finding is not a false positive.` | ||
|
||
# Issue remediations (for discovery of insecure directives/values) as individual string texts. | ||
issueRemediationFound = `Inspect the {csp} header value of your response to ensure permissions appear safe.` | ||
issueRemediationInlineEval = `\nBest practice recommends deleting or replacing '{insecure_value}' in a Content-Security-Policy with nonces or hashes to ensure script safety.` | ||
issueRemediationWildcard = `\nTo deter attacker-controlled sources, best practice suggests whitelisting individual trusted sources rather than using {insecure_value} characters.` | ||
issueRemediationHTTPSNotEnforced = `\nBest practice suggests ensuring resource sources encrypt all transmitted content (via the 'HTTPS' URI scheme) to prevent Man-In-The-Middle (MITM) attacks from intercepting resource loads in plaintext.` | ||
issueRemediationSearchEngineURLs = `\nBest practice recommends against whitelisting search engine URLs.` | ||
|
||
# Issue remediations (for discovery if deprecated directives/values) as individual string texts. | ||
issueRemediationDeprecated01 = `You may wish to remove the {insecure_value} from this {csp} header.` | ||
issueRemediationDeprecated02 = `\nEnsure parallel functionalities remain maintained by the web application (or client web browsers).` | ||
|
||
# Issue remediations (for important missing directives) as fragmented string texts. | ||
missingDir01_src = `\nTo mitigate this issue,` | ||
missingDir01_objectSrc = `\nBecause web browsers no longer support browser plugins (the purpose of a <object> HTML tag),` | ||
missingDir01_trustedTypes = `\nTo deter DOM-controllable XSS surfaces from emerging,` | ||
missingDir02 = ` best practice recommends explictly including the ` | ||
missingDir03_src = ` directive (& restricting it to a 'none' value if unused).` | ||
missingDir03_trustedTypes = ` directive with a 'script' value.` | ||
|
||
# Issue remediations (for important missing directives) as individual string texts. | ||
issueRemediationMissingDirective_defaultSrc = `{missingDir01_src}{missingDir02}{defaultSrc}{missingDir03_src}` | ||
issueRemediationMissingDirective_scriptSrc = `{missingDir01_src}{missingDir02}{scriptSrc}{missingDir03_src}` | ||
issueRemediationMissingDirective_objectSrc = `{missingDir01_objectSrc}{missingDir02}{objectSrc}{missingDir03_src}` | ||
issueRemediationMissingDirective_trustedTypes = `{missingDir01_trustedTypes}{missingDir02}{requireTrustedTypesFor}{missingDir03_trustedTypes}` | ||
|
||
# Issue advice as individual string texts. | ||
issueAdviceCspCalculator = `\nUse the CSP Evaluator (https://csp-evaluator.withgoogle.com/). to evaluate the strength of your 'Content-Security-Header' headers.` | ||
|
||
given response then | ||
# Ensures static file types irrelevant to the Content-Security-Policy header do not get checked. | ||
if not({latest.response.url.file} matches "(\.apk|\.bmp|\.cgi|\.css|\.csv|\.db|\.dmg|\.do|\.doc|\.ico| | ||
\.ipa|\.env|\.eot|\.exe|\.gif|\.gz|\.jpg|\.jpeg|\.js|\.json|\.mp3|\.mp4|\.otf|\.pdf|\.png|\.ppt|\.rar| | ||
\.sqlite|\.svg|\.tar|\.tsv|\.ttf|\.txt|\.wav|\.webm|\.webp|\.woff|\.xls|\.xml|\.zip)") then | ||
|
||
# Creates an info-level finding to signify a missing Content-Security-Policy header & terminate the test. | ||
# Note: Deleted due to reconsiderations regarding this BCheck to report on insecure CSP values rather than missing CSP headers. | ||
# if not({cspCol} in {latest.response.headers}) then | ||
# report issue: | ||
# severity: info | ||
# confidence: firm | ||
# detail: `{issueDetailMissingHeader}` | ||
# remediation: `{issueRemediationMissingHeader01}{issueRemediationMissingHeader02}{issueAdviceCspCalculator}` | ||
|
||
# Creates a relative-level finding to signify an insecure value on a Content-Security-Policy header. | ||
if ({cspCol} in {latest.response.headers}) and ({insecure_value} in {to_lower(latest.response.headers)}) then | ||
|
||
# Specified remediations for a Content-Security-Header using an 'unsafe-inline' value. | ||
if (" 'unsafe-inline'" in {insecure_value}) and ({to_lower(latest.response.headers)} matches "(default-src|script-src|style-src)") then | ||
report issue: | ||
severity: low | ||
confidence: certain | ||
detail: `{issueDetailFound}{issueNote_Inline}` | ||
remediation: `{issueRemediationFound}{issueRemediationInlineEval}{issueAdviceCspCalculator}` | ||
end if | ||
|
||
# Specified remediations for a Content-Security-Header using an 'unsafe-eval' value. | ||
if (" 'unsafe-eval'" in {insecure_value}) and ({to_lower(latest.response.headers)} matches "(default-src|script-src)") then | ||
report issue: | ||
severity: low | ||
confidence: certain | ||
detail: `{issueDetailFound}\n{issueNote_Eval}` | ||
remediation: `{issueRemediationFound}{issueRemediationInlineEval}{issueAdviceCspCalculator}` | ||
end if | ||
|
||
# Specified remediations for a Content-Security-Header using a potentially permissive '*' value. | ||
if (" *" in {insecure_value}) and ({to_lower(latest.response.headers)} matches "(default-src|script-src|connect-src|img-src| | ||
style-src|font-src|media-src|object-src|frame-src|worker-src|manifest-src|prefetch-src|child-src|form-action|frame-ancestors|plugin-types|sandbox)") then | ||
report issue: | ||
severity: low | ||
confidence: certain | ||
detail: `{issueDetailFound}{issueNote_Wildcard}` | ||
remediation: `{issueRemediationFound}{issueRemediationWildcard}{issueAdviceCspCalculator}` | ||
end if | ||
|
||
# Specified remediations for a Content-Security-Header using a 'data:' URI scheme. | ||
if " data:" in {insecure_value} then | ||
report issue: | ||
severity: low | ||
confidence: certain | ||
detail: `{issueDetailFound}{issueNote_Data}` | ||
remediation: `{issueRemediationFound}{issueRemediationHTTPSNotEnforced}{issueAdviceCspCalculator}` | ||
end if | ||
|
||
# Specified remediations for a Content-Security-Header using an 'http:' URI scheme. | ||
if " http:" in {insecure_value} then | ||
report issue: | ||
severity: low | ||
confidence: certain | ||
detail: `{issueDetailFound}{issueNote_Http}` | ||
remediation: `{issueRemediationFound}{issueRemediationHTTPSNotEnforced}{issueAdviceCspCalculator}` | ||
end if | ||
|
||
# Specified remediations for a Content-Security-Header using an 'https:' URI scheme without a complete URL domain. | ||
if " https:;" in {insecure_value} then | ||
report issue: | ||
severity: low | ||
confidence: certain | ||
detail: `{issueDetailFound}{issueNote_HttpsWildcard}` | ||
remediation: `{issueRemediationFound}{issueRemediationWildcard}{issueAdviceCspCalculator}` | ||
end if | ||
|
||
# Specified remediations for a Content-Security-Header which whitelists the 'www.google.com' URL domain. | ||
if "//www.google.com" in {insecure_value} then | ||
report issue: | ||
severity: low | ||
confidence: certain | ||
detail: `{issueDetailFound}{issueNote_googledotcom}` | ||
remediation: `{issueRemediationFound}{issueRemediationSearchEngineURLs}{issueAdviceCspCalculator}` | ||
end if | ||
|
||
# Specified remediations for a Content-Security-Header which whitelists the 'ajax.googleapis.com' URL domain. | ||
if "//ajax.googleapis.com" in {insecure_value} then | ||
report issue: | ||
severity: low | ||
confidence: certain | ||
detail: `{issueDetailFound}{issueNote_ajaxgoogledotcom}` | ||
remediation: `{issueRemediationFound}{issueRemediationSearchEngineURLs}{issueAdviceCspCalculator}` | ||
end if | ||
|
||
# Specified remediations for a Content-Security-Header using a deprecated value. | ||
if ({insecure_value} matches "(plugin-types|prefetch-src|report-uri|block-all-mixed-content)") then | ||
report issue: | ||
severity: low | ||
confidence: certain | ||
detail: `{issueDetailFound}{issueNote_Deprecated}` | ||
remediation: `{issueRemediationDeprecated01}{issueRemediationDeprecated02}{issueAdviceCspCalculator}` | ||
end if | ||
|
||
# Creates a relative-level finding to signify an important directive is not set on a Content-Security-Policy header. | ||
else if ({cspCol} in {latest.response.headers}) and not({to_lower(latest.response.headers)} matches "(default-src|script-src|object-src|require-trusted-types-for)") then | ||
|
||
# Specified remediations for a Content-Security-Header missing a 'default-src' directive. | ||
if not("default-src" in {to_lower(latest.response.headers)}) then | ||
report issue: | ||
severity: low | ||
confidence: certain | ||
detail: `{issueDetailMissingDirective_defaultSrc}{issueNote_Src}` | ||
remediation: `{issueRemediationFound}{issueRemediationMissingDirective_defaultSrc}{issueAdviceCspCalculator}` | ||
end if | ||
|
||
# Specified remediations for a Content-Security-Header missing a 'script-src' directive. | ||
if not("script-src" in {to_lower(latest.response.headers)}) then | ||
report issue: | ||
severity: low | ||
confidence: certain | ||
detail: `{issueDetailMissingDirective_scriptSrc}{issueNote_Src}` | ||
remediation: `{issueRemediationFound}{issueRemediationMissingDirective_scriptSrc}{issueAdviceCspCalculator}` | ||
end if | ||
|
||
# Specified remediations for a Content-Security-Header missing a 'object-src' directive. | ||
if not("object-src" in {to_lower(latest.response.headers)}) then | ||
report issue: | ||
severity: low | ||
confidence: certain | ||
detail: `{issueDetailMissingDirective_objectSrc}{issueNote_Src}` | ||
remediation: `{issueRemediationFound}{issueRemediationMissingDirective_objectSrc}{issueAdviceCspCalculator}` | ||
end if | ||
|
||
# Specified remediations for a Content-Security-Header missing a 'require-trusted-types-for' directive. | ||
if not("require-trusted-types-for" in {to_lower(latest.response.headers)}) then | ||
report issue: | ||
severity: info | ||
confidence: certain | ||
detail: `{issueDetailMissingDirective_requireTrustedTypesFor}{issueNote_RequireTrustedTypesFor}` | ||
remediation: `{issueRemediationFound}{issueRemediationMissingDirective_trustedTypes}{issueAdviceCspCalculator}` | ||
end if | ||
end if | ||
end if |