mirror of
https://github.com/django-helpdesk/django-helpdesk.git
synced 2025-06-20 01:27:44 +02:00
Merge pull request #1269 from django-helpdesk/fix_markdown_javascript_injection_prevention
Fix markdown javascript injection prevention
This commit is contained in:
commit
8bdf3ce525
@ -38,22 +38,31 @@ class EscapeHtml(Extension):
|
|||||||
|
|
||||||
|
|
||||||
def get_markdown(text):
|
def get_markdown(text):
|
||||||
|
"""
|
||||||
|
This algorithm will check for illegal schemes used in markdown clickable links
|
||||||
|
and remove the scheme. It does an iterative retry until no replacements done to
|
||||||
|
account for embedded schemes in the replacement text.
|
||||||
|
It will then do markdown processing to ensure safe markdown and return the safe string.
|
||||||
|
"""
|
||||||
if not text:
|
if not text:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
pattern = r"([\[\s\S\]]*?)\(([\s\S]*?):([\s\S]*?)\)"
|
# Search for markdown that creates a clickable link and remove the undesirable ones
|
||||||
# Regex check
|
pattern = re.compile(r"(\[[\s\S]*?\])\(([\w]*?):([\s\S]*?)\)", flags=re.MULTILINE)
|
||||||
if re.match(pattern, text):
|
rerun_scheme_check = (
|
||||||
# get get value of group regex
|
True # Used to decide if a re-check should be done after last pass
|
||||||
scheme = re.search(pattern, text, re.IGNORECASE).group(2)
|
)
|
||||||
# scheme check
|
while rerun_scheme_check:
|
||||||
if scheme in helpdesk_settings.ALLOWED_URL_SCHEMES:
|
has_illegal_scheme = False
|
||||||
replacement = "\\1(\\2:\\3)"
|
for m in re.finditer(pattern, text):
|
||||||
else:
|
# check if scheme is allowed
|
||||||
replacement = "\\1(\\3)"
|
if m.group(2).lower() in helpdesk_settings.ALLOWED_URL_SCHEMES:
|
||||||
|
# Considered safe so don't change it.
|
||||||
text = re.sub(pattern, replacement, text, flags=re.IGNORECASE)
|
continue
|
||||||
|
# Remove the scheme and leave the rest
|
||||||
|
text = text.replace(m.group(0), f"{m.group(1)}({m.group(3)})")
|
||||||
|
has_illegal_scheme = True
|
||||||
|
rerun_scheme_check = has_illegal_scheme
|
||||||
return mark_safe(
|
return mark_safe(
|
||||||
markdown(
|
markdown(
|
||||||
text,
|
text,
|
||||||
|
@ -31,14 +31,34 @@ class MarkDown(SimpleTestCase):
|
|||||||
output_value = get_markdown(input_value)
|
output_value = get_markdown(input_value)
|
||||||
self.assertEqual(output_value, expected_value)
|
self.assertEqual(output_value, expected_value)
|
||||||
|
|
||||||
def test_markdown_link_correct_protokol(self):
|
def test_markdown_link_correct_protocol(self):
|
||||||
expected_value = '<p><a href="http://www.yahoo.ru">www.google.com</a></p>'
|
expected_value = '<p><a href="http://www.yahoo.ru">www.google.com</a></p>'
|
||||||
input_value = "[www.google.com](http://www.yahoo.ru)"
|
input_value = "[www.google.com](http://www.yahoo.ru)"
|
||||||
output_value = get_markdown(input_value)
|
output_value = get_markdown(input_value)
|
||||||
self.assertEqual(output_value, expected_value)
|
self.assertEqual(output_value, expected_value)
|
||||||
|
|
||||||
def test_markdown_link_not_correct_protokol(self):
|
def test_markdown_link_not_correct_protocol(self):
|
||||||
expected_value = '<p><a href="//www.yahoo.ru">www.google.com</a></p>'
|
expected_value = '<p><a href="//www.yahoo.ru">www.google.com</a></p>'
|
||||||
input_value = "[www.google.com](aaaa://www.yahoo.ru)"
|
input_value = "[www.google.com](aaaa://www.yahoo.ru)"
|
||||||
output_value = get_markdown(input_value)
|
output_value = get_markdown(input_value)
|
||||||
self.assertEqual(output_value, expected_value)
|
self.assertEqual(output_value, expected_value)
|
||||||
|
|
||||||
|
def test_multiline_markdown_link_with_correct_and_incorrect_protocol(self):
|
||||||
|
expected_value = '<p>This<a href="http://alert.javascript.test">XSS</a></p>\n<p>Line 2: <a href="alert(document.domain);">TEST</a></p>'
|
||||||
|
input_value = "This[XSS](http://alert.javascript.test)\n\nLine 2: [TEST](javascript:alert(document.domain);)"
|
||||||
|
output_value = get_markdown(input_value)
|
||||||
|
self.assertEqual(output_value, expected_value)
|
||||||
|
|
||||||
|
def test_multiline_markdown_link_with_correct_and_incorrect_protocol_twice_declared(
|
||||||
|
self,
|
||||||
|
):
|
||||||
|
expected_value = '<p>This<a href="http://alert.javascript.test">XSS</a></p>\n<p>FAKE IT TILL YOU MAKE IT: <a href="alert(document.domain);">TEST</a></p>'
|
||||||
|
input_value = "This[XSS](http://alert.javascript.test)\n\nFAKE IT TILL YOU MAKE IT: [TEST](javascript:javascript:alert(document.domain);)"
|
||||||
|
output_value = get_markdown(input_value)
|
||||||
|
self.assertEqual(output_value, expected_value)
|
||||||
|
|
||||||
|
def test_markdown_link_with__multiple_incorrect_protocols(self):
|
||||||
|
expected_value = '<p>First one:<a href="alert(document.domain);">XSS1</a> ...try again: <a href="alert(document.domain);">XSS2</a></p>'
|
||||||
|
input_value = "First one:[XSS1](javascript:alert(document.domain);) ...try again: [XSS2](javascript:javascript:alert(document.domain);)"
|
||||||
|
output_value = get_markdown(input_value)
|
||||||
|
self.assertEqual(output_value, expected_value)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user