Skip to content

Commit

Permalink
feat(python): sensitive data in cookie rule (CWE-315) (#391)
Browse files Browse the repository at this point in the history
  • Loading branch information
elsapet authored May 16, 2024
1 parent 9866e76 commit 0dfba82
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 0 deletions.
43 changes: 43 additions & 0 deletions rules/python/django/cookies.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
imports:
- python_shared_lang_datatype
- python_shared_django_http_response
patterns:
- pattern: |
$<RESPONSE>.set_cookie($<KEY>, $<VALUE>$<...>)
filters:
- variable: RESPONSE
detection: python_shared_django_http_response
- either:
- variable: KEY
detection: python_shared_lang_datatype
scope: result
- variable: VALUE
detection: python_shared_lang_datatype
scope: result
languages:
- python
severity: high
metadata:
description: Leakage of sensitive data in cookie
remediation_message: |-
## Description
Storing sensitive data in cookies can lead to a data breach. This vulnerability occurs when sensitive information is stored in browser cookies, putting it at risk of unauthorized access.
## Remediations
- **Do not** store sensitive data in unencrypted cookies. This practice can expose sensitive information to potential security threats.
```python
HttpResponse.set_cookie("user", "[email protected]", ...) # unsafe
```
- **Do** use encrypted cookies to protect sensitive data stored in cookies.
```python
HttpResponse.set_signed_cookie("user", "[email protected]", ...)
```
## References
- [Django set_signed_cookie documentation](https://docs.djangoproject.com/en/5.0/ref/request-response/#django.http.HttpResponse.set_signed_cookie)
cwe_id:
- 315
id: python_django_cookies
documentation_url: https://docs.bearer.com/reference/rules/python_django_cookies
60 changes: 60 additions & 0 deletions rules/python/lang/cookies.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
imports:
- python_shared_lang_datatype
- python_shared_lang_import2
patterns:
- pattern: $<COOKIE_INIT>[$<_>] = $<DATA_TYPE>
filters:
- variable: COOKIE_INIT
detection: python_lang_cookies_init
scope: cursor
- variable: DATA_TYPE
detection: python_shared_lang_datatype
scope: result
auxiliary:
- id: python_lang_cookies_init
patterns:
- pattern: $<COOKIE>()
filters:
- variable: COOKIE
detection: python_lang_cookies_cookie_class
scope: result
- id: python_lang_cookies_cookie_class
patterns:
- pattern: $<COOKIE_CLASS>
filters:
- variable: COOKIE_CLASS
detection: python_shared_lang_import2
scope: cursor
filters:
- variable: MODULE1
values: [http]
- variable: MODULE2
values: [cookies]
- variable: NAME
values:
- BaseCookie
- SimpleCookie
languages:
- python
severity: high
metadata:
description: Leakage of sensitive data in cookie
remediation_message: |-
## Description
Storing sensitive data in cookies can lead to a data breach. This vulnerability occurs when sensitive information is stored in browser cookies, putting it at risk of unauthorized access.
## Remediations
- **Do not** store sensitive data in unencrypted cookies. This practice can expose sensitive information to potential security threats.
```python
HttpResponse.set_cookie("user", "[email protected]", ...) # unsafe
```
- **Do** use encrypted cookies to protect sensitive data stored in cookies.
```python
HttpResponse.set_signed_cookie("user", "[email protected]", ...)
```
cwe_id:
- 315
id: python_lang_cookies
documentation_url: https://docs.bearer.com/reference/rules/python_lang_cookies
1 change: 1 addition & 0 deletions rules/python/lang/logger.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ patterns:
- error
- variable: DATA_TYPE
detection: python_shared_lang_datatype
scope: result
languages:
- python
skip_data_types:
Expand Down
26 changes: 26 additions & 0 deletions rules/python/shared/django/http_response.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
type: shared
imports:
- python_shared_lang_instance
- python_shared_lang_import2
languages:
- python
patterns:
- pattern: $<HTTP_RESPONSE>
filters:
- variable: HTTP_RESPONSE
detection: python_shared_lang_instance
scope: cursor_strict
filters:
- variable: CLASS
detection: python_shared_lang_import2
scope: cursor
filters:
- variable: MODULE1
values: [django]
- variable: MODULE2
values: [http]
- variable: NAME
values: [HttpResponse]
metadata:
description: "Python Django HTTP Response instance."
id: python_shared_django_http_response
20 changes: 20 additions & 0 deletions tests/python/django/cookies/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const {
createNewInvoker,
getEnvironment,
} = require("../../../helper.js")
const { ruleId, ruleFile, testBase } = getEnvironment(__dirname)

describe(ruleId, () => {
const invoke = createNewInvoker(ruleId, ruleFile, testBase)

test("cookies", () => {
const testCase = "main.py"

const results = invoke(testCase)

expect(results).toEqual({
Missing: [],
Extra: []
})
})
})
16 changes: 16 additions & 0 deletions tests/python/django/cookies/testdata/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from django.shortcuts import render
from django.http import HttpResponse

def bad(user):
response = HttpResponse()
# bearer:expected python_django_cookies
response.set_cookie('user', user.email)

def bad2(customer):
resp = HttpResponse("Set User")
# bearer:expected python_django_cookies
resp.set_cookie('logged customer', customer.email)

def ok(user)
response = HttpResponse("Set User")
response.set_signed_cookie('user', user.email) # still bad but not by this rule
20 changes: 20 additions & 0 deletions tests/python/lang/cookies/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const {
createNewInvoker,
getEnvironment,
} = require("../../../helper.js")
const { ruleId, ruleFile, testBase } = getEnvironment(__dirname)

describe(ruleId, () => {
const invoke = createNewInvoker(ruleId, ruleFile, testBase)

test("cookies", () => {
const testCase = "main.py"

const results = invoke(testCase)

expect(results).toEqual({
Missing: [],
Extra: []
})
})
})
16 changes: 16 additions & 0 deletions tests/python/lang/cookies/testdata/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from http import cookies

def bad(user):
myCookie = cookies.SimpleCookie()
# bearer:expected python_lang_cookies
myCookie["user"] = user.email

def bad2(customer):
myBasicCookie = cookies.BaseCookie()
# bearer:expected python_lang_cookies
myBasicCookie["logged customer"] = customer.email

def ok(user):
safeCookie = cookies.SimpleCookie()
safeCookie["user"] = "current"

0 comments on commit 0dfba82

Please sign in to comment.