Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(python): add cwe-79 xss rules #406

Merged
merged 7 commits into from
May 22, 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
1 change: 1 addition & 0 deletions .github/workflows/canary_integration_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ jobs:
"php/lang",
"php/symfony",
"php/third_parties",
"python/django",
didroe marked this conversation as resolved.
Show resolved Hide resolved
"python/lang",
"go/gorilla",
"go/gosec",
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/integration_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ jobs:
"php/lang",
"php/symfony",
"php/third_parties",
"python/django",
"python/lang",
"go/lang",
"go/gosec",
Expand Down
73 changes: 73 additions & 0 deletions rules/python/django/response_using_user_input.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
imports:
- python_shared_common_html_user_input
- python_shared_django_http_response
- python_shared_lang_import2
patterns:
- pattern: $<CLASS>($<USER_INPUT>$<...>)
filters:
- variable: CLASS
detection: python_shared_lang_import2
scope: cursor
filters:
- variable: MODULE1
values: [django]
- variable: MODULE2
values: [http]
- variable: NAME
values: [HttpResponse]
- variable: USER_INPUT
detection: python_shared_common_html_user_input
scope: result
- pattern: $<RESPONSE>.content = $<USER_INPUT>
filters:
- variable: RESPONSE
detection: python_shared_django_http_response
scope: cursor
- variable: USER_INPUT
detection: python_shared_common_html_user_input
scope: result
- pattern: $<RESPONSE>.$<METHOD>($<USER_INPUT>)
filters:
- variable: RESPONSE
detection: python_shared_django_http_response
scope: cursor
- variable: METHOD
values:
- write
- writelines
- variable: USER_INPUT
detection: python_shared_common_html_user_input
scope: result
languages:
- python
metadata:
description: "Unsanitized user input in output stream (XSS)"
remediation_message: |-
## Description

Cross-site scripting (XSS) vulnerabilities occur when unsanitized user input is included in web page content. This flaw can lead to malicious scripts being executed in the context of the user's browser, compromising the security of user data and interactions with the application.

## Remediations

- **Do** use templating engines that automatically encode data based on its context.
- **Do** use an encoder to handle user input before incorporating it into the output stream. This step helps minimize the risk of XSS attacks by converting potentially dangerous characters into a safe format.
```python
user_input = request.GET["user"]
encoded_user_input = django.utils.html.escape(user_input)
response = HttpResponse(encoded_user_input)
```
- **Do** sanitize user input to remove or neutralize unwanted scripts. Sanitization goes beyond encoding by actively removing harmful content from user input before it is used in the output.
```python
user_input = request.GET["user"]
sanitized_user_input = django.utils.html.strip_tags(user_input)
response = HttpResponse(sanitized_user_input)
```

## References

- [OWASP XSS Prevention Cheatsheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html)
cwe_id:
- 79
id: "python_django_response_using_user_input"
documentation_url: https://docs.bearer.com/reference/rules/python_django_response_using_user_input
severity: high
50 changes: 50 additions & 0 deletions rules/python/django/template_injection.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
imports:
- python_shared_common_user_input
- python_shared_lang_import2
patterns:
- pattern: $<CLASS>($<USER_INPUT>)
filters:
- variable: CLASS
detection: python_shared_lang_import2
scope: cursor
filters:
- variable: MODULE1
values: [django]
- variable: MODULE2
values: [template]
- variable: NAME
values: [Template]
- variable: USER_INPUT
detection: python_shared_common_user_input
scope: result
languages:
- python
metadata:
description: "Unsanitized user input in web page generation (XSS)"
remediation_message: |-
## Description

Cross-Site Scripting (XSS) is a vulnerability that allows attackers to run malicious scripts in the context of a trusted web application. This can happen when an application includes untrusted data without proper validation or escaping. There are several contexts where XSS can occur, each requiring specific encoding strategies to mitigate the risk.

## Remediations

- **Do** encode user input based on the context it is used in, such as HTML content, HTML attributes, JavaScript, and CSS contexts. This helps prevent malicious scripts from being executed.
```python
django.utils.html.escape(user_input)
```
- **Do** use templating engines like Django that automatically encode data based on its context.
- **Do** sanitize data using libraries or functions specifically designed for this purpose, especially when inserting content into a web page.
- **Do** separate data from code by avoiding inline scripting and event handlers. Use separate JavaScript files for event handling to minimize script injection risks.
- **Do not** mix server-side and client-side templating systems, as server-side systems may not escape output safely for client-side use.
- **Do not** encode user input before storing it in a database. Any encoding should be applied when the data is output, not before storage, to ensure that it is encoded appropriately for its context.

## References

- [OWASP XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html)
- [Django templates Documentation](https://docs.djangoproject.com/en/5.0/ref/templates/)

cwe_id:
- 79
id: python_django_template_injection
documentation_url: https://docs.bearer.com/reference/rules/python_django_template_injection
severity: high
65 changes: 65 additions & 0 deletions rules/python/lang/http_response_splitting.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
imports:
- python_shared_common_user_input
- python_shared_lang_instance
- python_shared_lang_import2
patterns:
- pattern: $<HANDLER>.send_header($<...>$<USER_INPUT>$<...>)
filters:
- variable: HANDLER
detection: python_shared_lang_instance
scope: cursor
filters:
- variable: CLASS
detection: python_shared_lang_import2
scope: cursor
filters:
- variable: MODULE1
values: [http]
- variable: MODULE2
values: [server]
- variable: NAME
values: [BaseHTTPRequestHandler]
- variable: USER_INPUT
detection: python_lang_http_response_splitting_user_input
scope: result
auxiliary:
- id: python_lang_http_response_splitting_user_input
sanitizer: python_lang_http_response_splitting_sanitizer
patterns:
- pattern: $<UNSANITIZED_USER_INPUT>
filters:
- variable: UNSANITIZED_USER_INPUT
detection: python_shared_common_user_input
scope: cursor
- id: python_lang_http_response_splitting_sanitizer
patterns:
- pattern: $<_>.replace($<SOURCE>, $<REPLACEMENT>)
filters:
- variable: SOURCE
string_regex: "\\r\\n|\\\\r\\\\n"
- not:
variable: REPLACEMENT
string_regex: "\\r\\n|\\\\r\\\\n"
languages:
- python
severity: high
metadata:
description: "Unsanitized user input in HTTP response (XSS)"
remediation_message: |-
## Description

Including unsanitized user input in a HTTP response could allow an attacker inject Carriage Return Line Feed (CRLF) characters into the response. An entirely attacker-controlled response can then be returned, creating a cross-site scripting (XSS) vulnerability.

## Remediations

- **Do not** include user input in cookies or other HTTP headers without proper sanitization. This can prevent attackers from exploiting the input to manipulate the response.
- **Do** remove CRLF sequences from user input to mitigate the risk of response splitting and XSS attacks. Use the following code snippet as a reference for sanitizing input in Java:
didroe marked this conversation as resolved.
Show resolved Hide resolved
```python
input = request.getParameter("data");
var sanitized = input.replaceAll("\r\n", "");
cookie.setValue(sanitized);
```
cwe_id:
- 79
id: python_lang_http_response_splitting
documentation_url: https://docs.bearer.com/reference/rules/python_lang_http_response_splitting
43 changes: 43 additions & 0 deletions rules/python/lang/manual_html_sanitization.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
patterns:
- pattern: |
$<_>.$<METHOD>($<_>, $<REPLACEMENT>)
filters:
- variable: METHOD
values:
- replace
- variable: REPLACEMENT
string_regex: "&(lt|gt|apos|quot|amp);"
languages:
- python
severity: high
metadata:
description: "Usage of manual HTML sanitization (XSS)"
remediation_message: |-
## Description

Manually sanitizing HTML is prone to mistakes and can lead to Cross-Site Scripting (XSS) vulnerabilities. This occurs when user input is not properly sanitized, allowing attackers to inject malicious scripts into web pages viewed by other users.

## Remediations

- **Do not** manually escape HTML to sanitize user input. This method is unreliable and can easily miss certain exploits.
```python
sanitized_value = user_input.replace('<', '&lt;').replace('>', '&gt;'); # unsafe
html = f"<strong>{sanitized_value}</strong>"
```
- **Do** use a trusted HTML sanitization library to handle user input safely. Libraries designed for sanitization are more reliable as they cover a wide range of XSS attack vectors.
```python
from html_sanitizer import Sanitizer

sanitizer = Sanitizer()
sanitized_value = sanitizer.sanitize(user_input)

html = f"<strong>{sanitized_value}</strong>"
```

## References

- [OWASP XSS explained](https://owasp.org/www-community/attacks/xss/)
cwe_id:
- 79
id: python_lang_manual_html_sanitization
documentation_url: https://docs.bearer.com/reference/rules/python_lang_manual_html_sanitization
43 changes: 43 additions & 0 deletions rules/python/lang/raw_html_using_user_input.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
imports:
- python_shared_common_html_user_input
patterns:
- pattern: $<STRING>
filters:
- variable: STRING
string_regex: <\w+(\s[^>]*)?>
- variable: STRING
detection: python_shared_common_html_user_input
scope: result
languages:
- python
severity: high
metadata:
description: "Unsanitized user input in raw HTML strings (XSS)"
remediation_message: |-
## Description

Including unsanitized user input in HTML exposes your application to cross-site scripting (XSS) attacks. This vulnerability allows attackers to inject malicious scripts into web pages viewed by other users.

## Remediations

- **Do not** include user input directly in HTML strings. This practice can lead to XSS vulnerabilities.
```python
html = f"<h1>{user_input}</h1>" # unsafe
```
- **Do** use a framework or templating language that automatically handles the encoding and sanitization of user input when constructing HTML. This approach minimizes the risk of XSS attacks.
- **Do** sanitize user input if you must use HTML strings directly. Utilize libraries designed for input sanitization to ensure that user input does not contain malicious content.
```python
from html_sanitizer import Sanitizer

sanitizer = Sanitizer()
sanitized_value = sanitizer.sanitize(user_input)
html = f"<h1>{sanitized_value}</h1>"
```

## References

- [OWASP Cross-Site Scripting (XSS) Cheatsheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html)
cwe_id:
- 79
id: python_lang_raw_html_using_user_input
documentation_url: https://docs.bearer.com/reference/rules/python_lang_raw_html_using_user_input
40 changes: 40 additions & 0 deletions rules/python/shared/common/html_user_input.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
type: shared
languages:
- python
imports:
- python_shared_lang_import1
- python_shared_lang_instance
- python_shared_common_user_input
- python_shared_django_html_sanitizer
sanitizer: python_shared_common_html_user_input_sanitizer
patterns:
- pattern: $<USER_INPUT>
filters:
- variable: USER_INPUT
detection: python_shared_common_user_input
scope: cursor
auxiliary:
- id: python_shared_common_html_user_input_sanitizer
patterns:
- pattern: $<DJANGO_SANITIZER>
filters:
- variable: DJANGO_SANITIZER
detection: python_shared_django_html_sanitizer
scope: cursor_strict
- pattern: $<SANITIZER>.sanitize($<_>)
filters:
- variable: SANITIZER
detection: python_shared_lang_instance
scope: cursor
filters:
- variable: CLASS
detection: python_shared_lang_import1
scope: cursor
filters:
- variable: MODULE1
values: [html_sanitizer]
- variable: NAME
values: [Sanitizer]
metadata:
description: "Python HTML user input."
id: python_shared_common_html_user_input
25 changes: 25 additions & 0 deletions rules/python/shared/django/html_sanitizer.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
type: shared
languages:
- python
imports:
- python_shared_lang_import3
patterns:
- pattern: $<FUNCTION>($<_>)
filters:
- variable: FUNCTION
detection: python_shared_lang_import3
scope: cursor
filters:
- variable: MODULE1
values: [django]
- variable: MODULE2
values: [utils]
- variable: MODULE3
values: [http]
- variable: NAME
values:
- escape
- strip_tags
metadata:
description: "Django HTML sanitizer."
id: python_shared_django_html_sanitizer
Loading
Loading