Skip to content
This repository has been archived by the owner on Nov 4, 2024. It is now read-only.

Commit

Permalink
feat: deprecate x-xss-protection header (#520)
Browse files Browse the repository at this point in the history
update all scoring to 0, other than -5 for an invalid header
  • Loading branch information
LeoMcA authored Jan 24, 2024
1 parent a5d69d7 commit d55d484
Show file tree
Hide file tree
Showing 5 changed files with 20 additions and 40 deletions.
2 changes: 1 addition & 1 deletion httpobs/docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ Example:
"score_modifier": 0
},
"x-xss-protection": {
"expectation": "x-xss-protection-1-mode-block",
"expectation": "x-xss-protection-disabled",
"name": "x-xss-protection",
"output": {
"data": "1; mode=block"
Expand Down
7 changes: 3 additions & 4 deletions httpobs/docs/scoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,8 @@ x-frame-options-header-invalid | `X-Frame-Options` (XFO) header cannot be recogn

[X-XSS-Protection](https://infosec.mozilla.org/guidelines/web_security#x-xss-protection) | Description | Modifier
--- | --- | :---:
x-xss-protection-not-needed-due-to-csp | `X-XSS-Protection` header not needed due to strong Content Security Policy (CSP) header | 0
x-xss-protection-enabled-mode-block | `X-XSS-Protection` header set to `1; mode=block` | 0
x-xss-protection-enabled | `X-XSS-Protection` header set to `1` | 0
x-xss-protection-disabled | `X-XSS-Protection` header set to `0` (disabled) | -10
x-xss-protection-not-implemented | `X-XSS-Protection` header not implemented | -10
x-xss-protection-header-invalid | `X-XSS-Protection` header cannot be recognized | -10
x-xss-protection-disabled | `X-XSS-Protection` header set to `0` (disabled) | 0
x-xss-protection-not-implemented | `X-XSS-Protection` header not implemented | 0
x-xss-protection-header-invalid | `X-XSS-Protection` header cannot be recognized | -5
16 changes: 5 additions & 11 deletions httpobs/scanner/analyzer/headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -836,14 +836,13 @@ def x_frame_options(reqs: dict, expectation='x-frame-options-sameorigin-or-deny'


@scored_test
def x_xss_protection(reqs: dict, expectation='x-xss-protection-1-mode-block') -> dict:
def x_xss_protection(reqs: dict, expectation='x-xss-protection-disabled') -> dict:
"""
:param reqs: dictionary containing all the request and response objects
:param expectation: test expectation
x-xss-protection-enabled-mode-block: X-XSS-Protection set to "1; block" [default]
x-xss-protection-enabled-mode-block: X-XSS-Protection set to "1; block"
x-xss-protection-enabled: X-XSS-Protection set to "1"
x-xss-protection-not-needed-due-to-csp: no X-XSS-Protection header, but CSP blocks inline nonsense
x-xss-protection-disabled: X-XSS-Protection set to "0" (disabled)
x-xss-protection-disabled: X-XSS-Protection set to "0" (disabled) [default]
x-xss-protection-not-implemented: X-XSS-Protection header missing
x-xss-protection-header-invalid
:return: dictionary with:
Expand Down Expand Up @@ -908,15 +907,10 @@ def x_xss_protection(reqs: dict, expectation='x-xss-protection-1-mode-block') ->
output['pass'] = True
elif valid and not enabled:
output['result'] = 'x-xss-protection-disabled'
output['pass'] = True

else:
output['result'] = 'x-xss-protection-not-implemented'

# Allow sites to skip out of having X-XSS-Protection if they implement a strong CSP policy
# Note that having an invalid XXSSP setting will still trigger, even with a good CSP policy
if valid and output['pass'] is False:
if content_security_policy(reqs)['pass']:
output['pass'] = True
output['result'] = 'x-xss-protection-not-needed-due-to-csp'
output['pass'] = True

return output
22 changes: 9 additions & 13 deletions httpobs/scanner/grader/grade.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,28 +366,24 @@
},
# X-XSS-Protection
'x-xss-protection-enabled-mode-block': {
'description': 'X-XSS-Protection header set to "1; mode=block"',
'description': 'Deprecated X-XSS-Protection header set to "1; mode=block"',
'modifier': 0,
},
'x-xss-protection-enabled': {
'description': 'X-XSS-Protection header set to "1"',
'modifier': 0,
},
'x-xss-protection-not-needed-due-to-csp': {
'description': 'X-XSS-Protection header not needed due to strong Content Security Policy (CSP) header',
'description': 'Deprecated X-XSS-Protection header set to "1"',
'modifier': 0,
},
'x-xss-protection-disabled': {
'description': 'X-XSS-Protection header set to "0" (disabled)',
'modifier': -10,
'description': 'Deprecated X-XSS-Protection header set to "0" (disabled)',
'modifier': 0,
},
'x-xss-protection-not-implemented': {
'description': 'X-XSS-Protection header not implemented',
'modifier': -10,
'description': 'Deprecated X-XSS-Protection header not implemented',
'modifier': 0,
},
'x-xss-protection-header-invalid': {
'description': 'X-XSS-Protection header cannot be recognized',
'modifier': -10,
'description': 'Deprecated X-XSS-Protection header cannot be recognized',
'modifier': -5,
},
# Generic results
'html-not-parsable': {
Expand Down Expand Up @@ -424,7 +420,7 @@ def get_grade_and_likelihood_for_score(score: int) -> tuple:


def get_score_description(result) -> str:
return SCORE_TABLE[result]['description']
return SCORE_TABLE.get(result, {'description': ''})['description']


def get_score_modifier(result) -> int:
Expand Down
13 changes: 2 additions & 11 deletions httpobs/tests/unittests/test_headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1429,7 +1429,7 @@ def test_missing(self):
result = x_xss_protection(self.reqs)

self.assertEquals('x-xss-protection-not-implemented', result['result'])
self.assertFalse(result['pass'])
self.assertTrue(result['pass'])

def test_header_invalid(self):
for value in ('whimsy', '2; mode=block', '1; mode=block; mode=block', '1; mode=block, 1; mode=block'):
Expand All @@ -1446,7 +1446,7 @@ def test_disabled(self):
result = x_xss_protection(self.reqs)

self.assertEquals('x-xss-protection-disabled', result['result'])
self.assertFalse(result['pass'])
self.assertTrue(result['pass'])

def test_enabled_noblock(self):
for value in ('1', '1 '):
Expand All @@ -1464,12 +1464,3 @@ def test_enabled_block(self):

self.assertEquals('x-xss-protection-enabled-mode-block', result['result'])
self.assertTrue(result['pass'])

def test_enabled_via_csp(self):
reqs = empty_requests()
set_header(reqs['responses']['auto'], 'Content-Security-Policy', "object-src 'none'; script-src 'none'")

result = x_xss_protection(reqs)

self.assertEquals('x-xss-protection-not-needed-due-to-csp', result['result'])
self.assertTrue(result['pass'])

0 comments on commit d55d484

Please sign in to comment.