From d7b35abf46f8a84de9e717e27e7b831b6b55539a Mon Sep 17 00:00:00 2001 From: elsapet Date: Thu, 6 Jun 2024 14:25:48 +0200 Subject: [PATCH] feat(python/django): add cookie rules --- .../django/cookie_missing_http_only.yml | 50 +++++++++++++++++++ rules/python/django/cookie_missing_secure.yml | 50 +++++++++++++++++++ .../django/cookie_missing_http_only/test.js | 20 ++++++++ .../cookie_missing_http_only/testdata/main.py | 9 ++++ .../django/cookie_missing_secure/test.js | 20 ++++++++ .../cookie_missing_secure/testdata/main.py | 9 ++++ 6 files changed, 158 insertions(+) create mode 100644 rules/python/django/cookie_missing_http_only.yml create mode 100644 rules/python/django/cookie_missing_secure.yml create mode 100644 tests/python/django/cookie_missing_http_only/test.js create mode 100644 tests/python/django/cookie_missing_http_only/testdata/main.py create mode 100644 tests/python/django/cookie_missing_secure/test.js create mode 100644 tests/python/django/cookie_missing_secure/testdata/main.py diff --git a/rules/python/django/cookie_missing_http_only.yml b/rules/python/django/cookie_missing_http_only.yml new file mode 100644 index 00000000..eb89b8f1 --- /dev/null +++ b/rules/python/django/cookie_missing_http_only.yml @@ -0,0 +1,50 @@ +imports: + - python_shared_django_http_response +patterns: + - pattern: $ + filters: + - variable: SET_COOKIE + detection: python_django_cookie_missing_http_only_set_cookie_call + scope: cursor + - not: + variable: SET_COOKIE + detection: python_django_cookie_missing_http_only_set_cookie_http_only + scope: cursor +auxiliary: + - id: python_django_cookie_missing_http_only_set_cookie_call + patterns: + - pattern: $.set_cookie($<...>) + filters: + - variable: RESPONSE + detection: python_shared_django_http_response + scope: cursor + - id: python_django_cookie_missing_http_only_set_cookie_http_only + patterns: + - pattern: $<_>($<...>httponly=$) + filters: + - variable: "TRUE" + detection: python_django_cookie_missing_http_only_true + scope: cursor + - id: python_django_cookie_missing_http_only_true + patterns: + - "True" +languages: + - python +severity: medium +metadata: + description: Missing HTTP Only option in cookie configuration + remediation_message: |- + ## Description + + Not setting the HTTP Only attribute to "true" in cookie configurations leaves the cookie vulnerable to being accessed by client-side JavaScript. This oversight can lead to the exposure of cookie values, especially on websites susceptible to Cross-Site Scripting (XSS) attacks. Enabling HTTP Only is a critical step in preventing malicious scripts from reading the cookie values through JavaScript. + + ## Remediations + + - **Do** set the HTTP Only attribute to `true` for cookies to prevent them from being accessed by client-side JavaScript. This is a critical step in safeguarding your cookies against unauthorized access, especially in the context of XSS vulnerabilities. + ```python + response.set_cookie(httponly=True); + ``` + cwe_id: + - 1004 + id: python_django_cookie_missing_http_only + documentation_url: https://docs.bearer.com/reference/rules/python_django_cookie_missing_http_only diff --git a/rules/python/django/cookie_missing_secure.yml b/rules/python/django/cookie_missing_secure.yml new file mode 100644 index 00000000..ad206f04 --- /dev/null +++ b/rules/python/django/cookie_missing_secure.yml @@ -0,0 +1,50 @@ +imports: + - python_shared_django_http_response +patterns: + - pattern: $ + filters: + - variable: SET_COOKIE + detection: python_django_cookie_missing_secure_set_cookie_call + scope: cursor + - not: + variable: SET_COOKIE + detection: python_django_cookie_missing_secure_set_cookie_secure + scope: cursor +auxiliary: + - id: python_django_cookie_missing_secure_set_cookie_call + patterns: + - pattern: $.set_cookie($<...>) + filters: + - variable: RESPONSE + detection: python_shared_django_http_response + scope: cursor + - id: python_django_cookie_missing_secure_set_cookie_secure + patterns: + - pattern: $<_>($<...>secure=$) + filters: + - variable: "TRUE" + detection: python_django_cookie_missing_secure_true + scope: cursor + - id: python_django_cookie_missing_secure_true + patterns: + - "True" +languages: + - python +severity: medium +metadata: + description: Missing Secure option in cookie configuration + remediation_message: |- + ## Description + + Not setting the "Secure" attribute in cookie configuration can lead to unauthorized third-party access. This attribute, when enabled, ensures cookies are sent to the server only over HTTPS, enhancing security by preventing potential eavesdropping. + + ## Remediations + + - **Do** set the `secure` attribute to `true` to enforce the transmission of cookies over HTTPS only. + ```python + response.set_cookie(secure=True) + ``` + cwe_id: + - 614 + id: python_django_cookie_missing_secure + documentation_url: https://docs.bearer.com/reference/rules/python_django_cookie_missing_secure diff --git a/tests/python/django/cookie_missing_http_only/test.js b/tests/python/django/cookie_missing_http_only/test.js new file mode 100644 index 00000000..da6d64ba --- /dev/null +++ b/tests/python/django/cookie_missing_http_only/test.js @@ -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("cookie_missing_http_only", () => { + const testCase = "main.py" + + const results = invoke(testCase) + + expect(results).toEqual({ + Missing: [], + Extra: [] + }) + }) +}) \ No newline at end of file diff --git a/tests/python/django/cookie_missing_http_only/testdata/main.py b/tests/python/django/cookie_missing_http_only/testdata/main.py new file mode 100644 index 00000000..d022e204 --- /dev/null +++ b/tests/python/django/cookie_missing_http_only/testdata/main.py @@ -0,0 +1,9 @@ +def bad(request): + cookie = jwt.encode(payload, 'csrf_vulneribility', algorithm='HS256') + # bearer:expected python_django_cookie_missing_http_only + response.set_cookie('auth_cookie', cookie) + +def ok(request): + cookie = jwt.encode(payload, 'csrf_vulneribility', algorithm='HS256') + # ok + response.set_cookie('auth_cookie', cookie, httponly=True) \ No newline at end of file diff --git a/tests/python/django/cookie_missing_secure/test.js b/tests/python/django/cookie_missing_secure/test.js new file mode 100644 index 00000000..a1657275 --- /dev/null +++ b/tests/python/django/cookie_missing_secure/test.js @@ -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("cookie_missing_secure", () => { + const testCase = "main.py" + + const results = invoke(testCase) + + expect(results).toEqual({ + Missing: [], + Extra: [] + }) + }) +}) \ No newline at end of file diff --git a/tests/python/django/cookie_missing_secure/testdata/main.py b/tests/python/django/cookie_missing_secure/testdata/main.py new file mode 100644 index 00000000..b8d32773 --- /dev/null +++ b/tests/python/django/cookie_missing_secure/testdata/main.py @@ -0,0 +1,9 @@ +def bad(request): + cookie = jwt.encode(payload, 'csrf_vulneribility', algorithm='HS256') + # bearer:expected python_django_cookie_missing_secure + response.set_cookie('auth_cookie', cookie) + +def ok(request): + cookie = jwt.encode(payload, 'csrf_vulneribility', algorithm='HS256') + # ok + response.set_cookie('auth_cookie', cookie, secure=True) \ No newline at end of file