Fix issues with xss linters
Improve accuracy of javascript-escape linter: Previously this would match on FOOescape() and FOO.escape calls, but neither are the global escape function we are worried about. The regex probably isn't 100% accurate; there may be still false positives (javascript allows a large range of characters in identifiers, some of which may not be covered by [\w.$]). The main thing is to avoid false negatives here though - this will definitely catch any use of `escape()` or `window.escape()`. Also remove javascript-interpolate lint - this was deemed unecessary. StringUtils.interpolate is not in fact safe (it does no html escaping), so the results of this lint are misleading.
This commit is contained in:
@@ -403,27 +403,19 @@ class TestJavaScriptLinter(TestLinter):
|
||||
linter.check_javascript_file_is_safe(data['template'], results)
|
||||
self._validate_data_rules(data, results)
|
||||
|
||||
@data(
|
||||
{'template': 'StringUtils.interpolate()', 'rule': None},
|
||||
{'template': 'HtmlUtils.interpolateHtml()', 'rule': None},
|
||||
{'template': 'interpolate(anything)', 'rule': JAVASCRIPT_LINTER_RULESET.javascript_interpolate},
|
||||
)
|
||||
def test_javascript_interpolate(self, data):
|
||||
"""
|
||||
Test check_javascript_file_is_safe with interpolate()
|
||||
"""
|
||||
linter = _build_javascript_linter()
|
||||
results = FileResults('')
|
||||
|
||||
linter.check_javascript_file_is_safe(data['template'], results)
|
||||
|
||||
self._validate_data_rules(data, results)
|
||||
|
||||
@data(
|
||||
{'template': '_.escape(message)', 'rule': None},
|
||||
{'template': 'anything.escape(message)', 'rule': JAVASCRIPT_LINTER_RULESET.javascript_escape},
|
||||
{'template': 'anything.escape(message)', 'rule': None},
|
||||
{'template': 'anythingescape(message)', 'rule': None},
|
||||
{'template': '$escape(message)', 'rule': None},
|
||||
{'template': '_escape(message)', 'rule': None},
|
||||
{'template': 'escape(message)', 'rule': JAVASCRIPT_LINTER_RULESET.javascript_escape},
|
||||
{'template': '(escape(message))', 'rule': JAVASCRIPT_LINTER_RULESET.javascript_escape},
|
||||
{'template': ' escape(message))', 'rule': JAVASCRIPT_LINTER_RULESET.javascript_escape},
|
||||
{'template': 'window.escape(message)', 'rule': JAVASCRIPT_LINTER_RULESET.javascript_escape},
|
||||
{'template': '(window.escape(message)', 'rule': JAVASCRIPT_LINTER_RULESET.javascript_escape},
|
||||
)
|
||||
def test_javascript_interpolate(self, data):
|
||||
def test_javascript_escape(self, data):
|
||||
"""
|
||||
Test check_javascript_file_is_safe with interpolate()
|
||||
"""
|
||||
|
||||
@@ -329,7 +329,6 @@ class JavaScriptLinter(BaseLinter):
|
||||
javascript_jquery_html='javascript-jquery-html',
|
||||
javascript_concat_html='javascript-concat-html',
|
||||
javascript_escape='javascript-escape',
|
||||
javascript_interpolate='javascript-interpolate',
|
||||
)
|
||||
|
||||
def __init__(self, underscore_linter, javascript_skip_dirs=None):
|
||||
@@ -401,7 +400,6 @@ class JavaScriptLinter(BaseLinter):
|
||||
file_contents, "html", self.ruleset.javascript_jquery_html, no_caller_check,
|
||||
self._is_jquery_html_argument_safe, results
|
||||
)
|
||||
self._check_javascript_interpolate(file_contents, results)
|
||||
self._check_javascript_escape(file_contents, results)
|
||||
self._check_concat_with_html(file_contents, self.ruleset.javascript_concat_html, results)
|
||||
self.underscore_linter.check_underscore_file_is_safe(file_contents, results)
|
||||
@@ -435,37 +433,18 @@ class JavaScriptLinter(BaseLinter):
|
||||
expression = Expression(start_index)
|
||||
return expression
|
||||
|
||||
def _check_javascript_interpolate(self, file_contents, results):
|
||||
"""
|
||||
Checks that interpolate() calls are safe.
|
||||
|
||||
Only use of StringUtils.interpolate() or HtmlUtils.interpolateText()
|
||||
are safe.
|
||||
|
||||
Arguments:
|
||||
file_contents: The contents of the JavaScript file.
|
||||
results: A file results objects to which violations will be added.
|
||||
|
||||
"""
|
||||
# Ignores calls starting with "StringUtils.", because those are safe
|
||||
regex = re.compile(r"(?<!StringUtils).interpolate\(")
|
||||
for function_match in regex.finditer(file_contents):
|
||||
expression = self._get_expression_for_function(file_contents, function_match)
|
||||
results.violations.append(ExpressionRuleViolation(self.ruleset.javascript_interpolate, expression))
|
||||
|
||||
def _check_javascript_escape(self, file_contents, results):
|
||||
"""
|
||||
Checks that only necessary escape() are used.
|
||||
|
||||
Allows for _.escape(), although this shouldn't be the recommendation.
|
||||
Checks that escape() is not used. escape() is not recommended.
|
||||
ref. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/escape
|
||||
|
||||
Arguments:
|
||||
file_contents: The contents of the JavaScript file.
|
||||
results: A file results objects to which violations will be added.
|
||||
|
||||
"""
|
||||
# Ignores calls starting with "_.", because those are safe
|
||||
regex = regex = re.compile(r"(?<!_).escape\(")
|
||||
# Regex to match uses of escape() or window.escape().
|
||||
regex = re.compile(r"(?:^|(?<=window\.)|(?<![\w.$]))escape\(")
|
||||
for function_match in regex.finditer(file_contents):
|
||||
expression = self._get_expression_for_function(file_contents, function_match)
|
||||
results.violations.append(ExpressionRuleViolation(self.ruleset.javascript_escape, expression))
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
"rules": {
|
||||
"javascript-concat-html": 142,
|
||||
"javascript-escape": 7,
|
||||
"javascript-interpolate": 23,
|
||||
"javascript-jquery-append": 68,
|
||||
"javascript-jquery-html": 146,
|
||||
"javascript-jquery-insert-into-target": 18,
|
||||
|
||||
Reference in New Issue
Block a user