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

feat: deprecate x-xss-protection header #520

Merged
merged 1 commit into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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'])