From e43f6ab56916ae4c0153781857aea87cea358428 Mon Sep 17 00:00:00 2001 From: David Roe Date: Wed, 29 May 2024 10:12:34 +0100 Subject: [PATCH] feat(python): add cwe-327 broken/risky crypto algorithm rules (#424) --- rules/python/django/jwt_weak_encryption.yml | 45 +++++++++++ rules/python/lang/jwt_weak_encryption.yml | 60 ++++++++++++++ .../python/lang/weak_encryption_blowfish.yml | 63 +++++++++++++++ rules/python/lang/weak_encryption_des.yml | 65 +++++++++++++++ .../python/lang/weak_encryption_ecb_mode.yml | 43 ++++++++++ rules/python/lang/weak_encryption_rc4.yml | 63 +++++++++++++++ rules/python/lang/weak_encryption_rsa.yml | 80 +++++++++++++++++++ rules/python/lang/weak_random.yml | 63 +++++++++++++++ rules/python/lang/weak_tls_version.yml | 61 ++++++++++++++ .../python/django/jwt_weak_encryption/test.js | 20 +++++ .../jwt_weak_encryption/testdata/settings.py | 19 +++++ tests/python/lang/jwt_weak_encryption/test.js | 20 +++++ .../lang/jwt_weak_encryption/testdata/main.py | 13 +++ .../lang/weak_encryption_blowfish/test.js | 20 +++++ .../weak_encryption_blowfish/testdata/main.py | 8 ++ tests/python/lang/weak_encryption_des/test.js | 20 +++++ .../lang/weak_encryption_des/testdata/main.py | 9 +++ .../lang/weak_encryption_ecb_mode/test.js | 20 +++++ .../weak_encryption_ecb_mode/testdata/main.py | 5 ++ tests/python/lang/weak_encryption_rc4/test.js | 20 +++++ .../lang/weak_encryption_rc4/testdata/main.py | 9 +++ tests/python/lang/weak_encryption_rsa/test.js | 20 +++++ .../lang/weak_encryption_rsa/testdata/main.py | 15 ++++ tests/python/lang/weak_random/test.js | 20 +++++ .../python/lang/weak_random/testdata/main.py | 12 +++ tests/python/lang/weak_tls_version/test.js | 20 +++++ .../lang/weak_tls_version/testdata/main.py | 15 ++++ 27 files changed, 828 insertions(+) create mode 100644 rules/python/django/jwt_weak_encryption.yml create mode 100644 rules/python/lang/jwt_weak_encryption.yml create mode 100644 rules/python/lang/weak_encryption_blowfish.yml create mode 100644 rules/python/lang/weak_encryption_des.yml create mode 100644 rules/python/lang/weak_encryption_ecb_mode.yml create mode 100644 rules/python/lang/weak_encryption_rc4.yml create mode 100644 rules/python/lang/weak_encryption_rsa.yml create mode 100644 rules/python/lang/weak_random.yml create mode 100644 rules/python/lang/weak_tls_version.yml create mode 100644 tests/python/django/jwt_weak_encryption/test.js create mode 100644 tests/python/django/jwt_weak_encryption/testdata/settings.py create mode 100644 tests/python/lang/jwt_weak_encryption/test.js create mode 100644 tests/python/lang/jwt_weak_encryption/testdata/main.py create mode 100644 tests/python/lang/weak_encryption_blowfish/test.js create mode 100644 tests/python/lang/weak_encryption_blowfish/testdata/main.py create mode 100644 tests/python/lang/weak_encryption_des/test.js create mode 100644 tests/python/lang/weak_encryption_des/testdata/main.py create mode 100644 tests/python/lang/weak_encryption_ecb_mode/test.js create mode 100644 tests/python/lang/weak_encryption_ecb_mode/testdata/main.py create mode 100644 tests/python/lang/weak_encryption_rc4/test.js create mode 100644 tests/python/lang/weak_encryption_rc4/testdata/main.py create mode 100644 tests/python/lang/weak_encryption_rsa/test.js create mode 100644 tests/python/lang/weak_encryption_rsa/testdata/main.py create mode 100644 tests/python/lang/weak_random/test.js create mode 100644 tests/python/lang/weak_random/testdata/main.py create mode 100644 tests/python/lang/weak_tls_version/test.js create mode 100644 tests/python/lang/weak_tls_version/testdata/main.py diff --git a/rules/python/django/jwt_weak_encryption.yml b/rules/python/django/jwt_weak_encryption.yml new file mode 100644 index 00000000..d5db1bf3 --- /dev/null +++ b/rules/python/django/jwt_weak_encryption.yml @@ -0,0 +1,45 @@ +patterns: + - pattern: | + SIMPLE_JWT = { $<...>$: $$<...> } + focus: ALGORITHM + filters: + - variable: KEY + string_regex: \AALGORITHM\z + - variable: ALGORITHM + detection: python_django_jwt_weak_encryption_none + scope: cursor +auxiliary: + - id: python_django_jwt_weak_encryption_none + patterns: + - pattern: $ + filters: + - variable: NONE + string_regex: (?i)\Anone\z + - None +languages: + - python +metadata: + description: Usage of weak encryption algorithm in JWT + remediation_message: |- + ## Description + + Implementing weak encryption algorithms in JWT (JSON Web Tokens) compromises the security of the tokens. This vulnerability occurs when an encryption algorithm that does not offer sufficient security strength is used, making the tokens susceptible to attacks. + + ## Remediations + + - **Do** use robust encryption algorithms recommended for JWT. HS256 (HMAC with SHA-256) is a secure choice for signing JWTs. + ```python + SIMPLE_JWT = { + "ALGORITHM": "HS256" + } + ``` + + ## References + + - [OWASP weak encryption](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/09-Testing_for_Weak_Cryptography/04-Testing_for_Weak_Encryption) + cwe_id: + - 327 + id: python_django_jwt_weak_encryption + documentation_url: https://docs.bearer.com/reference/rules/python_django_jwt_weak_encryption + cloud_code_suggestions: true +severity: high diff --git a/rules/python/lang/jwt_weak_encryption.yml b/rules/python/lang/jwt_weak_encryption.yml new file mode 100644 index 00000000..9cf355ac --- /dev/null +++ b/rules/python/lang/jwt_weak_encryption.yml @@ -0,0 +1,60 @@ +imports: + - python_shared_lang_import1 +patterns: + - pattern: $($<_>, $<_>, $$<...>) + filters: + - variable: ENCODE + detection: python_shared_lang_import1 + filters: + - variable: MODULE1 + values: [jwt] + - variable: NAME + values: [encode] + - variable: ALGORITHM + detection: python_lang_jwt_weak_encryption_none + scope: cursor + - pattern: $($<...>algorithm=$$<...>) + filters: + - variable: ENCODE + detection: python_shared_lang_import1 + filters: + - variable: MODULE1 + values: [jwt] + - variable: NAME + values: [encode] + - variable: ALGORITHM + detection: python_lang_jwt_weak_encryption_none + scope: cursor +auxiliary: + - id: python_lang_jwt_weak_encryption_none + patterns: + - pattern: $ + filters: + - variable: NONE + string_regex: (?i)\Anone\z + - None +languages: + - python +metadata: + description: Usage of weak encryption algorithm in JWT + remediation_message: |- + ## Description + + Implementing weak encryption algorithms in JWT (JSON Web Tokens) compromises the security of the tokens. This vulnerability occurs when an encryption algorithm that does not offer sufficient security strength is used, making the tokens susceptible to attacks. + + ## Remediations + + - **Do** use robust encryption algorithms recommended for JWT. HS256 (HMAC with SHA-256) is a secure choice for signing JWTs. + ```python + jwt.encode(payload, secret, algorithm="HS256") + ``` + + ## References + + - [OWASP weak encryption](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/09-Testing_for_Weak_Cryptography/04-Testing_for_Weak_Encryption) + cwe_id: + - 327 + id: python_lang_jwt_weak_encryption + documentation_url: https://docs.bearer.com/reference/rules/python_lang_jwt_weak_encryption + cloud_code_suggestions: true +severity: high diff --git a/rules/python/lang/weak_encryption_blowfish.yml b/rules/python/lang/weak_encryption_blowfish.yml new file mode 100644 index 00000000..b70c676d --- /dev/null +++ b/rules/python/lang/weak_encryption_blowfish.yml @@ -0,0 +1,63 @@ +imports: + - python_shared_lang_datatype + - python_shared_lang_import2 +patterns: + - pattern: $.encrypt($$<...>) + filters: + - variable: CIPHER + detection: python_lang_weak_encryption_blowfish_instance + scope: cursor + - either: + - variable: OPTIONAL_DATA_TYPE + detection: python_shared_lang_datatype + scope: result + - not: + variable: OPTIONAL_DATA_TYPE + detection: python_shared_lang_datatype + scope: result +auxiliary: + - id: python_lang_weak_encryption_blowfish_instance + patterns: + - pattern: $.new($<...>) + filters: + - variable: BLOWFISH + detection: python_shared_lang_import2 + scope: cursor + filters: + - variable: MODULE1 + values: [Crypto] + - variable: MODULE2 + values: [Cipher] + - variable: NAME + values: [Blowfish] +languages: + - python +skip_data_types: + - Passwords # see python_lang_weak_password_encryption_blowfish +metadata: + description: "Usage of weak encryption algorithm (Blowfish)" + remediation_message: |- + ## Description + + Your code is at risk due to the use of Blowfish, a weak encryption algorithm. This vulnerability can lead to data breaches and compromises your security measures. + + ## Remediations + + - **Do not** use Blowfish as it is outdated and vulnerable to attacks. Its use can significantly weaken your application's security. + - **Do** use stronger encryption algorithms to enhance data security. AES (Advanced Encryption Standard) is a recommended choice. + ```python + from Crypto.Cipher import AES + + cipher = AES.new(aes_key, AES.MODE_OCB) + ciphertext, tag = cipher.encrypt_and_digest(plaintext) + ``` + + ## References + + - [PyCryptodome modern ciphers](https://pycryptodome.readthedocs.io/en/latest/src/cipher/modern.html) + cwe_id: + - 327 + id: python_lang_weak_encryption_blowfish + documentation_url: https://docs.bearer.com/reference/rules/python_lang_weak_encryption_blowfish + cloud_code_suggestions: true +severity: high diff --git a/rules/python/lang/weak_encryption_des.yml b/rules/python/lang/weak_encryption_des.yml new file mode 100644 index 00000000..c2b3ea87 --- /dev/null +++ b/rules/python/lang/weak_encryption_des.yml @@ -0,0 +1,65 @@ +imports: + - python_shared_lang_datatype + - python_shared_lang_import2 +patterns: + - pattern: $.encrypt($$<...>) + filters: + - variable: CIPHER + detection: python_lang_weak_encryption_des_instance + scope: cursor + - either: + - variable: OPTIONAL_DATA_TYPE + detection: python_shared_lang_datatype + scope: result + - not: + variable: OPTIONAL_DATA_TYPE + detection: python_shared_lang_datatype + scope: result +auxiliary: + - id: python_lang_weak_encryption_des_instance + patterns: + - pattern: $.new($<...>) + filters: + - variable: DES + detection: python_shared_lang_import2 + scope: cursor + filters: + - variable: MODULE1 + values: [Crypto] + - variable: MODULE2 + values: [Cipher] + - variable: NAME + values: + - DES + - DES3 +languages: + - python +skip_data_types: + - Passwords # see python_lang_weak_password_encryption_des +metadata: + description: "Usage of weak encryption algorithm (DES)" + remediation_message: |- + ## Description + + Your code is at risk due to the use of DES (Data Encryption Standard), a weak encryption algorithm. This vulnerability can lead to data breaches and compromises your security measures. + + ## Remediations + + - **Do not** use DES as it is outdated and vulnerable to attacks. Its use can significantly weaken your application's security. + - **Do** use stronger encryption algorithms to enhance data security. AES (Advanced Encryption Standard) is a recommended choice. + ```python + from Crypto.Cipher import AES + + cipher = AES.new(aes_key, AES.MODE_OCB) + ciphertext, tag = cipher.encrypt_and_digest(plaintext) + ``` + + ## References + + - [PyCryptodome modern ciphers](https://pycryptodome.readthedocs.io/en/latest/src/cipher/modern.html) + cwe_id: + - 327 + id: python_lang_weak_encryption_des + documentation_url: https://docs.bearer.com/reference/rules/python_lang_weak_encryption_des + cloud_code_suggestions: true +severity: high diff --git a/rules/python/lang/weak_encryption_ecb_mode.yml b/rules/python/lang/weak_encryption_ecb_mode.yml new file mode 100644 index 00000000..5061d5da --- /dev/null +++ b/rules/python/lang/weak_encryption_ecb_mode.yml @@ -0,0 +1,43 @@ +imports: + - python_shared_lang_import2 +patterns: + - pattern: $.MODE_ECB + filters: + - variable: AES + detection: python_shared_lang_import2 + scope: cursor + filters: + - variable: MODULE1 + values: [Crypto] + - variable: MODULE2 + values: [Cipher] + - variable: NAME + values: [AES] +languages: + - python +metadata: + description: Usage of ECB cipher mode + remediation_message: |- + ## Description + + The ECB (Electronic Codebook) cipher mode is recognized as insecure and is not recommended for use in cryptographic protocols. This mode does not provide adequate data protection because it encrypts identical plaintext blocks into identical ciphertext blocks, making it vulnerable to pattern analysis. For stronger security, it's essential to use encryption algorithms that have built-in message integrity and do not require a mode of operation to be configured, such as ChaCha20-Poly1305 or, for older applications that do not support this, AES-256-GCM. + + ## Remediations + + - **Do** choose ChaCha20-Poly1305 or AES-256-GCM for encryption. These algorithms include built-in message integrity, offering a more secure alternative to ECB mode. + ```python + from Crypto.Cipher import ChaCha20_Poly1305 + + cipher = ChaCha20_Poly1305.new(key) + ciphertext, tag = cipher.encrypt_and_digest(plaintext) + ``` + + ## References + + - [PyCryptodome modern ciphers](https://pycryptodome.readthedocs.io/en/latest/src/cipher/modern.html) + cwe_id: + - 327 + id: python_lang_weak_encryption_ecb_mode + documentation_url: https://docs.bearer.com/reference/rules/python_lang_weak_encryption_ecb_mode + cloud_code_suggestions: true +severity: high diff --git a/rules/python/lang/weak_encryption_rc4.yml b/rules/python/lang/weak_encryption_rc4.yml new file mode 100644 index 00000000..b66c1f73 --- /dev/null +++ b/rules/python/lang/weak_encryption_rc4.yml @@ -0,0 +1,63 @@ +imports: + - python_shared_lang_datatype + - python_shared_lang_import2 +patterns: + - pattern: $.encrypt($$<...>) + filters: + - variable: CIPHER + detection: python_lang_weak_encryption_rc4_instance + scope: cursor + - either: + - variable: OPTIONAL_DATA_TYPE + detection: python_shared_lang_datatype + scope: result + - not: + variable: OPTIONAL_DATA_TYPE + detection: python_shared_lang_datatype + scope: result +auxiliary: + - id: python_lang_weak_encryption_rc4_instance + patterns: + - pattern: $.new($<...>) + filters: + - variable: RC4 + detection: python_shared_lang_import2 + scope: cursor + filters: + - variable: MODULE1 + values: [Crypto] + - variable: MODULE2 + values: [Cipher] + - variable: NAME + values: [ARC4] +languages: + - python +skip_data_types: + - Passwords # see python_lang_weak_password_encryption_rc4 +metadata: + description: "Usage of weak encryption algorithm (RC4)" + remediation_message: |- + ## Description + + Your code is at risk due to the use of RC4 (Rivest's Cipher version 4), a weak encryption algorithm. This vulnerability can lead to data breaches and compromises your security measures. + + ## Remediations + + - **Do not** use RC4 as it is outdated and vulnerable to attacks. Its use can significantly weaken your application's security. + - **Do** use stronger encryption algorithms to enhance data security. AES (Advanced Encryption Standard) is a recommended choice. + ```python + from Crypto.Cipher import AES + + cipher = AES.new(aes_key, AES.MODE_OCB) + ciphertext, tag = cipher.encrypt_and_digest(plaintext) + ``` + + ## References + + - [PyCryptodome modern ciphers](https://pycryptodome.readthedocs.io/en/latest/src/cipher/modern.html) + cwe_id: + - 327 + id: python_lang_weak_encryption_rc4 + documentation_url: https://docs.bearer.com/reference/rules/python_lang_weak_encryption_rc4 + cloud_code_suggestions: true +severity: high diff --git a/rules/python/lang/weak_encryption_rsa.yml b/rules/python/lang/weak_encryption_rsa.yml new file mode 100644 index 00000000..a4bb6279 --- /dev/null +++ b/rules/python/lang/weak_encryption_rsa.yml @@ -0,0 +1,80 @@ +imports: + - python_shared_lang_datatype + - python_shared_lang_import2 +patterns: + - pattern: $.encrypt($$<...>) + filters: + - variable: INSTANCE + detection: python_lang_weak_encryption_rsa_instance + scope: cursor + - either: + - variable: OPTIONAL_DATA_TYPE + detection: python_shared_lang_datatype + scope: result + - not: + variable: OPTIONAL_DATA_TYPE + detection: python_shared_lang_datatype + scope: result +auxiliary: + - id: python_lang_weak_encryption_rsa_instance + patterns: + - pattern: $<_>.new($$<...>) + filters: + - variable: KEY + detection: python_lang_weak_encryption_rsa_weak_key + scope: cursor + - pattern: $<_>.new($<...>key=$$<...>) + filters: + - variable: KEY + detection: python_lang_weak_encryption_rsa_weak_key + scope: cursor + - id: python_lang_weak_encryption_rsa_weak_key + patterns: + - pattern: $.generate($$<...>) + filters: + - variable: RSA + detection: python_shared_lang_import2 + scope: cursor + filters: + - variable: MODULE1 + values: [Crypto] + - variable: MODULE2 + values: [PublicKey] + - variable: NAME + values: [RSA] + - variable: LENGTH + less_than: 2048 +languages: + - python +skip_data_types: + - Passwords # see python_lang_weak_password_encryption_rsa +metadata: + description: "Usage of weak encryption algorithm (RSA)" + remediation_message: |- + ## Description + + Using a weak encryption algorithm, specifically 1024-bit RSA, compromises data security. This vulnerability can lead to unauthorized access to sensitive information. + + ## Remediations + + - **Do not** use 1024-bit RSA for encryption. It is no longer considered secure. + ```python + RSA.generate(1024) # unsafe + ``` + - **Do** use stronger encryption algorithms to enhance data security. AES (Advanced Encryption Standard) is a recommended choice. + ```python + from Crypto.Cipher import AES + + cipher = AES.new(aes_key, AES.MODE_OCB) + ciphertext, tag = cipher.encrypt_and_digest(plaintext) + ``` + + ## References + + - [PyCryptodome modern ciphers](https://pycryptodome.readthedocs.io/en/latest/src/cipher/modern.html) + cwe_id: + - 327 + id: python_lang_weak_encryption_rsa + documentation_url: https://docs.bearer.com/reference/rules/python_lang_weak_encryption_rsa + cloud_code_suggestions: true +severity: high diff --git a/rules/python/lang/weak_random.yml b/rules/python/lang/weak_random.yml new file mode 100644 index 00000000..a83f9961 --- /dev/null +++ b/rules/python/lang/weak_random.yml @@ -0,0 +1,63 @@ +imports: + - python_shared_lang_instance + - python_shared_lang_import1 +patterns: + - pattern: $($<...>) + filters: + - variable: FUNCTION + detection: python_shared_lang_import1 + scope: cursor + filters: + - variable: MODULE1 + values: [random] + - not: + variable: NAME + values: + - seed + - getstate + - setstate + - Random + - SystemRandom + - pattern: $.$($<...>) + filters: + - variable: RANDOM + detection: python_shared_lang_instance + scope: cursor + filters: + - variable: CLASS + detection: python_shared_lang_import1 + filters: + - variable: MODULE1 + values: [random] + - variable: NAME + values: [Random] + - not: + variable: METHOD + values: + - seed + - getstate + - setstate +languages: + - python +metadata: + description: "Usage of weak Pseudo-Random Number Generator (PRNG)" + remediation_message: |- + ## Description + + The `random` module in Python generates pseudorandom numbers that are not secure for cryptographic purposes. These numbers can be predicted if the seed is known, posing a risk to the security of applications that use them for generating secrets, tokens, or other security-sensitive elements. + + ## Remediations + + - **Do** use `secrets` instead of `random` for generating random numbers in contexts where security is crucial. This ensures the randomness is cryptographically secure and unpredictable. + - **Do not** use `random` for generating random numbers in cryptographic applications, including but not limited to key generation, authentication tokens, or security challenges. + - **Do not** initialize `random` with predictable seeds, such as timestamps or other easily guessable values, if it is required to use `random`. + + ## References + + - [secrets module documentation](https://docs.python.org/3/library/secrets.html) + + cwe_id: + - 327 + id: python_lang_weak_random + documentation_url: https://docs.bearer.com/reference/rules/python_lang_weak_random +severity: high diff --git a/rules/python/lang/weak_tls_version.yml b/rules/python/lang/weak_tls_version.yml new file mode 100644 index 00000000..3714d03f --- /dev/null +++ b/rules/python/lang/weak_tls_version.yml @@ -0,0 +1,61 @@ +imports: + - python_shared_lang_import1 +patterns: + - pattern: $ + filters: + - variable: PROTOCOL_VERSION + detection: python_shared_lang_import1 + scope: cursor + filters: + - variable: MODULE1 + values: [ssl] + - variable: NAME + values: + - PROTOCOL_SSLv3 + - PROTOCOL_TLSv1 + - PROTOCOL_TLSv1_1 + - pattern: $.$ + filters: + - variable: TLS_VERSION + detection: python_shared_lang_import1 + scope: cursor + filters: + - variable: MODULE1 + values: [ssl] + - variable: NAME + values: [TLSVersion] + - variable: NAME + values: + - SSLv3 + - TLSv1 + - TLSv1_1 +languages: + - python +metadata: + description: "Usage of deprecated TLS version" + remediation_message: |- + ## Description + + TLS (Transport Layer Security) versions 1.0 and 1.1 have known vulnerabilities and using them introduces security risks to your application. These outdated TLS versions can lead to the interception and compromise of sensitive data during transmission. + + ## Remediations + + - **Do** enforce the use of TLS 1.3 when configuring SSL. TLS 1.3 offers significant security improvements, helping to protect data from known vulnerabilities present in older versions. + ```python + context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) + context.minimum_version = ssl.TLSVersion.TLSv1_3 + ``` + - **Do** utilize configurations that support Perfect Forward Secrecy (PFS) with TLS 1.3. PFS enhances security by ensuring that past communications remain secure even if future session keys are compromised. + - **Do not** configure your server to accept TLS versions 1.0 or 1.1. Removing these options from your TLS configuration is crucial to prevent downgrade attacks. + + ## References + + - [IETF's Deprecation of TLS 1.0 and 1.1](https://tools.ietf.org/html/rfc8996) + - [OWASP TLS Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Security_Cheat_Sheet.html) + - [Python `ssl` module documentation](https://docs.python.org/3/library/ssl.html) + + cwe_id: + - 327 + id: python_lang_weak_tls_version + documentation_url: https://docs.bearer.com/reference/rules/python_lang_weak_tls_version +severity: high diff --git a/tests/python/django/jwt_weak_encryption/test.js b/tests/python/django/jwt_weak_encryption/test.js new file mode 100644 index 00000000..b99552ed --- /dev/null +++ b/tests/python/django/jwt_weak_encryption/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("jwt_weak_encryption", () => { + const testCase = "settings.py" + + const results = invoke(testCase) + + expect(results).toEqual({ + Missing: [], + Extra: [] + }) + }) +}) \ No newline at end of file diff --git a/tests/python/django/jwt_weak_encryption/testdata/settings.py b/tests/python/django/jwt_weak_encryption/testdata/settings.py new file mode 100644 index 00000000..128a86b5 --- /dev/null +++ b/tests/python/django/jwt_weak_encryption/testdata/settings.py @@ -0,0 +1,19 @@ +SIMPLE_JWT = { + "ACCESS_TOKEN_LIFETIME": timedelta(minutes=5), + # bearer:expected python_django_jwt_weak_encryption + "ALGORITHM": None, + "OTHER": "none" +} + +SIMPLE_JWT = { + "ACCESS_TOKEN_LIFETIME": timedelta(minutes=5), + # bearer:expected python_django_jwt_weak_encryption + "ALGORITHM": "none", + "OTHER": "none" +} + +SIMPLE_JWT = { + "ACCESS_TOKEN_LIFETIME": timedelta(minutes=5), + "ALGORITHM": "HS256", + "OTHER": "none" +} diff --git a/tests/python/lang/jwt_weak_encryption/test.js b/tests/python/lang/jwt_weak_encryption/test.js new file mode 100644 index 00000000..0d881fca --- /dev/null +++ b/tests/python/lang/jwt_weak_encryption/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("jwt_weak_encryption", () => { + const testCase = "main.py" + + const results = invoke(testCase) + + expect(results).toEqual({ + Missing: [], + Extra: [] + }) + }) +}) \ No newline at end of file diff --git a/tests/python/lang/jwt_weak_encryption/testdata/main.py b/tests/python/lang/jwt_weak_encryption/testdata/main.py new file mode 100644 index 00000000..978a02c0 --- /dev/null +++ b/tests/python/lang/jwt_weak_encryption/testdata/main.py @@ -0,0 +1,13 @@ +import jwt + +jwt.encode(payload, secret, "HS256") +# bearer:expected python_lang_jwt_weak_encryption +jwt.encode(payload, secret, "none") +# bearer:expected python_lang_jwt_weak_encryption +jwt.encode(payload, secret, None) + +jwt.encode(payload, secret, algorithm="HS256") +# bearer:expected python_lang_jwt_weak_encryption +jwt.encode(payload, secret, algorithm="none") +# bearer:expected python_lang_jwt_weak_encryption +jwt.encode(payload, secret, algorithm=None) \ No newline at end of file diff --git a/tests/python/lang/weak_encryption_blowfish/test.js b/tests/python/lang/weak_encryption_blowfish/test.js new file mode 100644 index 00000000..dcb17a36 --- /dev/null +++ b/tests/python/lang/weak_encryption_blowfish/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("weak_encryption_blowfish", () => { + const testCase = "main.py" + + const results = invoke(testCase) + + expect(results).toEqual({ + Missing: [], + Extra: [] + }) + }) +}) \ No newline at end of file diff --git a/tests/python/lang/weak_encryption_blowfish/testdata/main.py b/tests/python/lang/weak_encryption_blowfish/testdata/main.py new file mode 100644 index 00000000..752554c2 --- /dev/null +++ b/tests/python/lang/weak_encryption_blowfish/testdata/main.py @@ -0,0 +1,8 @@ +password = user.password + +from Crypto.Cipher import Blowfish + +cipher = Blowfish.new(key, Blowfish.MODE_CBC) +cipher.encrypt(password.encode()) +# bearer:expected python_lang_weak_encryption_blowfish +cipher.encrypt(text.encode()) \ No newline at end of file diff --git a/tests/python/lang/weak_encryption_des/test.js b/tests/python/lang/weak_encryption_des/test.js new file mode 100644 index 00000000..153fc578 --- /dev/null +++ b/tests/python/lang/weak_encryption_des/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("weak_encryption_des", () => { + const testCase = "main.py" + + const results = invoke(testCase) + + expect(results).toEqual({ + Missing: [], + Extra: [] + }) + }) +}) \ No newline at end of file diff --git a/tests/python/lang/weak_encryption_des/testdata/main.py b/tests/python/lang/weak_encryption_des/testdata/main.py new file mode 100644 index 00000000..202daddf --- /dev/null +++ b/tests/python/lang/weak_encryption_des/testdata/main.py @@ -0,0 +1,9 @@ +password = user.password + +from Crypto.Cipher import DES + +cipher = DES.new(key, DES.MODE_ECB) + +cipher.encrypt(password.encode()) +# bearer:expected python_lang_weak_encryption_des +cipher.encrypt(text.encode()) diff --git a/tests/python/lang/weak_encryption_ecb_mode/test.js b/tests/python/lang/weak_encryption_ecb_mode/test.js new file mode 100644 index 00000000..e6fc7d0e --- /dev/null +++ b/tests/python/lang/weak_encryption_ecb_mode/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("weak_encryption_ecb_mode", () => { + const testCase = "main.py" + + const results = invoke(testCase) + + expect(results).toEqual({ + Missing: [], + Extra: [] + }) + }) +}) \ No newline at end of file diff --git a/tests/python/lang/weak_encryption_ecb_mode/testdata/main.py b/tests/python/lang/weak_encryption_ecb_mode/testdata/main.py new file mode 100644 index 00000000..7852949c --- /dev/null +++ b/tests/python/lang/weak_encryption_ecb_mode/testdata/main.py @@ -0,0 +1,5 @@ +from Crypto.Cipher import AES + +cipher = AES.new(key, AES.MODE_EAX) +# bearer:expected python_lang_weak_encryption_ecb_mode +cipher = AES.new(key, AES.MODE_ECB) \ No newline at end of file diff --git a/tests/python/lang/weak_encryption_rc4/test.js b/tests/python/lang/weak_encryption_rc4/test.js new file mode 100644 index 00000000..32fd1d12 --- /dev/null +++ b/tests/python/lang/weak_encryption_rc4/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("weak_encryption_rc4", () => { + const testCase = "main.py" + + const results = invoke(testCase) + + expect(results).toEqual({ + Missing: [], + Extra: [] + }) + }) +}) \ No newline at end of file diff --git a/tests/python/lang/weak_encryption_rc4/testdata/main.py b/tests/python/lang/weak_encryption_rc4/testdata/main.py new file mode 100644 index 00000000..8a90339d --- /dev/null +++ b/tests/python/lang/weak_encryption_rc4/testdata/main.py @@ -0,0 +1,9 @@ +password = user.password + +from Crypto.Cipher import ARC4 + +cipher = ARC4.new(key) + +cipher.encrypt(password.encode()) +# bearer:expected python_lang_weak_encryption_rc4 +cipher.encrypt(text.encode()) \ No newline at end of file diff --git a/tests/python/lang/weak_encryption_rsa/test.js b/tests/python/lang/weak_encryption_rsa/test.js new file mode 100644 index 00000000..c1e33d56 --- /dev/null +++ b/tests/python/lang/weak_encryption_rsa/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("weak_encryption_rsa", () => { + const testCase = "main.py" + + const results = invoke(testCase) + + expect(results).toEqual({ + Missing: [], + Extra: [] + }) + }) +}) \ No newline at end of file diff --git a/tests/python/lang/weak_encryption_rsa/testdata/main.py b/tests/python/lang/weak_encryption_rsa/testdata/main.py new file mode 100644 index 00000000..6594c682 --- /dev/null +++ b/tests/python/lang/weak_encryption_rsa/testdata/main.py @@ -0,0 +1,15 @@ +password = user.password + +from Crypto.Cipher import PKCS1_OAEP +from Crypto.PublicKey import RSA + +weak_key = RSA.generate(1048) +strong_key = RSA.generate(2048) + +weak_cipher = PKCS1_OAEP.new(weak_key) +strong_cipher = PKCS1_OAEP.new(strong_key) + +strong_cipher.encrypt(text.encode()) +weak_cipher.encrypt(password.encode()) +# bearer:expected python_lang_weak_encryption_rsa +weak_cipher.encrypt(text.encode()) diff --git a/tests/python/lang/weak_random/test.js b/tests/python/lang/weak_random/test.js new file mode 100644 index 00000000..1af85d52 --- /dev/null +++ b/tests/python/lang/weak_random/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("weak_random", () => { + const testCase = "main.py" + + const results = invoke(testCase) + + expect(results).toEqual({ + Missing: [], + Extra: [] + }) + }) +}) \ No newline at end of file diff --git a/tests/python/lang/weak_random/testdata/main.py b/tests/python/lang/weak_random/testdata/main.py new file mode 100644 index 00000000..9296cf73 --- /dev/null +++ b/tests/python/lang/weak_random/testdata/main.py @@ -0,0 +1,12 @@ +import random + +random.setstate(state) + +# bearer:expected python_lang_weak_random +range = random.randrange(100) + +rng = random.Random() +rng.setstate(state) + +# bearer:expected python_lang_weak_random +range = rng.randrange(100) \ No newline at end of file diff --git a/tests/python/lang/weak_tls_version/test.js b/tests/python/lang/weak_tls_version/test.js new file mode 100644 index 00000000..5da60f55 --- /dev/null +++ b/tests/python/lang/weak_tls_version/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("weak_tls_version", () => { + const testCase = "main.py" + + const results = invoke(testCase) + + expect(results).toEqual({ + Missing: [], + Extra: [] + }) + }) +}) \ No newline at end of file diff --git a/tests/python/lang/weak_tls_version/testdata/main.py b/tests/python/lang/weak_tls_version/testdata/main.py new file mode 100644 index 00000000..fffff3b1 --- /dev/null +++ b/tests/python/lang/weak_tls_version/testdata/main.py @@ -0,0 +1,15 @@ +import ssl + +context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) + +context.minimum_version = ssl.TLSVersion.TLSv1_3 +# bearer:expected python_lang_weak_tls_version +context.minimum_version = ssl.TLSVersion.TLSv1_1 + +context.maximum_version = ssl.TLSVersion.TLSv1_3 +# bearer:expected python_lang_weak_tls_version +context.maximum_version = ssl.TLSVersion.SSLv3 + +context2 = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) +# bearer:expected python_lang_weak_tls_version +context2 = ssl.SSLContext(ssl.PROTOCOL_TLSv1_1) \ No newline at end of file