This repository has been archived by the owner on Jan 19, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add the ability to test for XSS vulnerabilities.
TNL-4107
- Loading branch information
1 parent
244844f
commit a3a1145
Showing
7 changed files
with
250 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
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,100 @@ | ||
Performing XSS Vulnerability Audits | ||
=================================== | ||
|
||
The bok-choy framework includes the ability to perform XSS (cross-site scripting) audits on | ||
web pages using a short XSS locator defined in | ||
https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#XSS_Locator. | ||
|
||
Trigger XSS Vulnerability Audits in Existing Tests | ||
-------------------------------------------------- | ||
|
||
You might already have some bok-choy tests written for your web application. To | ||
leverage existing bok-choy tests and have them fail on finding XSS vulnerabilities, | ||
follow these steps. | ||
|
||
1. Insert the ``XSS_INJECTION`` string defined in ``bok_choy.page_object`` into your page content. | ||
2. Set the ``VERIFY_XSS`` environment variable to ``True``. | ||
|
||
:: | ||
|
||
export VERIFY_XSS=True | ||
|
||
|
||
With this environment variable set, an XSS audit is triggered whenever a page object's ``q`` | ||
method is called. The audit will detect improper escaping both in HTML and in Javascript | ||
that is embedded within HTML. | ||
|
||
If errors are found on the page, an XSSExposureError is raised. | ||
|
||
Here is an example of a bok-choy test that will check for XSS vulnerabilities. | ||
It clicks a button on the page, and the user's name is inserted into the page. | ||
If the user name is not properly escaped, the display | ||
of the name (which is data provided by the user and thus potentially malicious) can cause | ||
XSS issues. | ||
|
||
In the case of the ``test_button_click_output`` test case in the example below, | ||
an audit will be done in the ``click_button()``, ``output()``, and ``visit()`` method calls, | ||
as each of those will call out to ``q``. | ||
|
||
If any XSS errors are found, then the test case will fail with an | ||
XSSExposureError. | ||
|
||
.. code-block:: python | ||
from bok_choy.page_object import PageObject, XSS_INJECTION | ||
class MyPage(PageObject): | ||
def url(self): | ||
return 'https://www.mysite.com/page' | ||
def is_browser_on_page(self): | ||
return self.q(css='div#fixture button').present | ||
def click_button(self): | ||
""" | ||
Click on the button element (id="button"). | ||
On my example page this will trigger an ajax call | ||
that updates the #output div with the user's name. | ||
""" | ||
self.q(css='div#fixture button').first.click() | ||
self.wait_for_ajax() | ||
@property | ||
def output(self): | ||
""" | ||
Return the contents of the "#output" div on the page. | ||
In the example page, it will contain the user's name after being | ||
updated by the ajax call that is triggered by clicking the button. | ||
""" | ||
text_list = self.q(css='#output').text | ||
if len(text_list) < 1: | ||
return None | ||
else: | ||
return text_list[0] | ||
class MyPageTest(WebAppTest): | ||
def setUp(self): | ||
""" | ||
Log in as a particular user. | ||
""" | ||
super(MyPageTest, self).setUp() | ||
self.user_name = XSS_INJECTION | ||
self.log_in_as_user(self.user_name) | ||
def test_button_click_output(self): | ||
page = MyPage(self.browser) | ||
page.visit() | ||
page.click_button() | ||
self.assertEqual(page.output, self.user_name) | ||
def log_in_as_user(self, user_name): | ||
""" | ||
Would be implemented to log in as a particular user | ||
with a potentially malicious, user-provided name. | ||
""" | ||
pass | ||
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,12 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>XSS HTML</title> | ||
</head> | ||
<body> | ||
<div id="fixture"> | ||
<div class="unescaped">'';!--\"<XSS>=&{()}</div> | ||
<div>'';!--\"<XSS>=&{()}</div> | ||
</div> | ||
</body> | ||
</html> |
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,12 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>XSS JS</title> | ||
</head> | ||
<body> | ||
<script> | ||
window.unescaped = "'';!--"<XSS>=&{()}"; | ||
</script> | ||
<div id="fixture"/> | ||
</body> | ||
</html> |
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,13 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>XSS Mixed</title> | ||
</head> | ||
<body> | ||
<div id="fixture"> | ||
<div class="unescaped">'';!--\"<XSS>=&{()}</div> | ||
<div>'';!--\"<XSS>=&{()}</div> | ||
<div class="escaped">'';!--"<XSS>=&{()}</div> | ||
</div> | ||
</body> | ||
</html> |
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,15 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>XSS Safe</title> | ||
</head> | ||
<body> | ||
<script> | ||
window.escaped = "\u0027\u0027\u003B!\u002D\u002D\u0022\u003CXSS\u003E\u003D\u0026{()}"; | ||
</script> | ||
<div id="fixture"> | ||
<div class="escaped">'';!--"<XSS>=&{()}</div> | ||
<input type="text" value="'';!--"<XSS>=&{()}"> | ||
</div> | ||
</body> | ||
</html> |
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,53 @@ | ||
""" | ||
Tests for identifying XSS vulnerabilities. | ||
This is currently done when the "q" method is called. | ||
""" | ||
|
||
import os | ||
from mock import patch | ||
|
||
from bok_choy.web_app_test import WebAppTest | ||
from .pages import SitePage | ||
from bok_choy.page_object import XSSExposureError | ||
|
||
|
||
class XSSExposureTest(WebAppTest): | ||
""" | ||
Tests for identifying XSS vulnerabilities. | ||
""" | ||
def _visit_page(self, page_name): | ||
self.site_page = SitePage(self.browser) | ||
self.site_page.name = page_name | ||
self.site_page.visit() | ||
|
||
@patch.dict(os.environ, {'VERIFY_XSS': 'True'}) | ||
def test_html_exposure(self): | ||
self._visit_page("xss_html") | ||
with self.assertRaisesRegexp(XSSExposureError, "2 XSS issue"): | ||
self.site_page.q(css='.unescaped') | ||
|
||
@patch.dict(os.environ, {'VERIFY_XSS': 'True'}) | ||
def test_js_exposure(self): | ||
self._visit_page("xss_js") | ||
with self.assertRaisesRegexp(XSSExposureError, "1 XSS issue"): | ||
self.site_page.q(css='.unescaped') | ||
|
||
@patch.dict(os.environ, {'VERIFY_XSS': 'True'}) | ||
def test_mixed_exposure(self): | ||
self._visit_page("xss_mixed") | ||
with self.assertRaisesRegexp(XSSExposureError, "2 XSS issue"): | ||
self.site_page.q(css='.unescaped') | ||
|
||
@patch.dict(os.environ, {'VERIFY_XSS': 'True'}) | ||
def test_escaped(self): | ||
self._visit_page("xss_safe") | ||
self.site_page.q(css='.escaped') | ||
|
||
@patch.dict(os.environ, {'VERIFY_XSS': 'False'}) | ||
def test_xss_testing_disabled_explicitly(self): | ||
self._visit_page("xss_html") | ||
self.site_page.q(css='.unescaped') | ||
|
||
def test_xss_testing_disabled_by_default(self): | ||
self._visit_page("xss_html") | ||
self.site_page.q(css='.unescaped') |