From 95bf159c449eb55fe56ed489ea13ceee1b157527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Fabianski?= Date: Tue, 17 Oct 2023 11:56:01 +0200 Subject: [PATCH] feat(python): add weak encryption library for password --- rules/python/lang/weak_hash_md5.yml | 2 +- rules/python/lang/weak_hash_sha1.yml | 2 +- .../lang/weak_password_encryption_md5.yml | 58 ++++++++ .../lang/weak_password_encryption_sha1.yml | 58 ++++++++ .../__snapshots__/test.js.snap | 139 ++++++++++++++++++ .../lang/weak_password_encryption_md5/test.js | 16 ++ .../testdata/bad.py | 12 ++ .../testdata/ok.py | 12 ++ .../__snapshots__/test.js.snap | 139 ++++++++++++++++++ .../weak_password_encryption_sha1/test.js | 16 ++ .../testdata/bad.py | 12 ++ .../testdata/ok.py | 12 ++ 12 files changed, 476 insertions(+), 2 deletions(-) create mode 100644 rules/python/lang/weak_password_encryption_md5.yml create mode 100644 rules/python/lang/weak_password_encryption_sha1.yml create mode 100644 tests/python/lang/weak_password_encryption_md5/__snapshots__/test.js.snap create mode 100644 tests/python/lang/weak_password_encryption_md5/test.js create mode 100644 tests/python/lang/weak_password_encryption_md5/testdata/bad.py create mode 100644 tests/python/lang/weak_password_encryption_md5/testdata/ok.py create mode 100644 tests/python/lang/weak_password_encryption_sha1/__snapshots__/test.js.snap create mode 100644 tests/python/lang/weak_password_encryption_sha1/test.js create mode 100644 tests/python/lang/weak_password_encryption_sha1/testdata/bad.py create mode 100644 tests/python/lang/weak_password_encryption_sha1/testdata/ok.py diff --git a/rules/python/lang/weak_hash_md5.yml b/rules/python/lang/weak_hash_md5.yml index c7ba2be5c..89d64558a 100644 --- a/rules/python/lang/weak_hash_md5.yml +++ b/rules/python/lang/weak_hash_md5.yml @@ -30,7 +30,7 @@ languages: - python skip_data_types: - "Unique Identifier" - - "Passwords" # see python_lang_weak_password_hash_md5 + - "Passwords" # see python_lang_weak_password_encryption_md5 metadata: description: "Weak hashing library (MD5) detected." remediation_message: | diff --git a/rules/python/lang/weak_hash_sha1.yml b/rules/python/lang/weak_hash_sha1.yml index c610002d0..c1559d6ab 100644 --- a/rules/python/lang/weak_hash_sha1.yml +++ b/rules/python/lang/weak_hash_sha1.yml @@ -30,7 +30,7 @@ languages: - python skip_data_types: - "Unique Identifier" - - "Passwords" # see python_lang_weak_password_hash_sha1 + - "Passwords" # see python_lang_weak_password_encryption_sha1 metadata: description: "Weak hashing library (SHA1) detected." remediation_message: | diff --git a/rules/python/lang/weak_password_encryption_md5.yml b/rules/python/lang/weak_password_encryption_md5.yml new file mode 100644 index 000000000..58387446b --- /dev/null +++ b/rules/python/lang/weak_password_encryption_md5.yml @@ -0,0 +1,58 @@ +patterns: + - pattern: hashlib.md5($) + filters: + - either: + - variable: OPTIONAL_DATA_TYPE + detection: datatype + scope: result + - not: + variable: OPTIONAL_DATA_TYPE + detection: datatype + scope: result + - pattern: $.update($) + filters: + - variable: MD5_INIT + detection: python_lang_weak_hash_md5_init + scope: cursor + - either: + - variable: OPTIONAL_DATA_TYPE + detection: datatype + scope: result + - not: + variable: OPTIONAL_DATA_TYPE + detection: datatype + scope: result +auxiliary: + - id: python_lang_weak_hash_md5_init + patterns: + - hashlib.md5() +languages: + - python +only_data_types: + - "Passwords" +metadata: + description: "Weak encryption algorithm (MD5) used for password detected." + remediation_message: | + ## Description + + A weak hashing library can lead to data breaches and greater security risk. + + ## Remediations + According to [OWASP](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), MD5 and its predecessors are considered weak hash algorithms and therefore shouldn't be used. + + ❌ Do not use encryption for passwords, wherever possible: + + ```python + hashlib.md5(user.password).digest() + ``` + + ✅ Instead, we recommend using sha256: + + ```python + hashlib.sha256(user.password).digest() + ``` + cwe_id: + - 331 + - 328 + id: python_lang_weak_password_encryption_md5 + documentation_url: https://docs.bearer.com/reference/rules/python_lang_weak_password_encryption_md5 diff --git a/rules/python/lang/weak_password_encryption_sha1.yml b/rules/python/lang/weak_password_encryption_sha1.yml new file mode 100644 index 000000000..0e1737d04 --- /dev/null +++ b/rules/python/lang/weak_password_encryption_sha1.yml @@ -0,0 +1,58 @@ +patterns: + - pattern: hashlib.sha1($) + filters: + - either: + - variable: OPTIONAL_DATA_TYPE + detection: datatype + scope: result + - not: + variable: OPTIONAL_DATA_TYPE + detection: datatype + scope: result + - pattern: $.update($) + filters: + - variable: SHA1_INIT + detection: python_lang_weak_hash_sha1_init + scope: cursor + - either: + - variable: OPTIONAL_DATA_TYPE + detection: datatype + scope: result + - not: + variable: OPTIONAL_DATA_TYPE + detection: datatype + scope: result +auxiliary: + - id: python_lang_weak_hash_sha1_init + patterns: + - hashlib.sha1() +languages: + - python +only_data_types: + - "Passwords" +metadata: + description: "Weak encryption algorithm (SHA1) used for password detected." + remediation_message: | + ## Description + + A weak hashing library can lead to data breaches and greater security risk. + + ## Remediations + According to [OWASP](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), sha1 and its predecessors are considered weak hash algorithms and therefore shouldn't be used. + + ❌ Do not use encryption for passwords, wherever possible: + + ```python + hashlib.sha1(user.password).digest() + ``` + + ✅ Instead, we recommend using sha256: + + ```python + hashlib.sha256(user.password).digest() + ``` + cwe_id: + - 331 + - 328 + id: python_lang_weak_password_encryption_sha1 + documentation_url: https://docs.bearer.com/reference/rules/python_lang_weak_password_encryption_sha1 diff --git a/tests/python/lang/weak_password_encryption_md5/__snapshots__/test.js.snap b/tests/python/lang/weak_password_encryption_md5/__snapshots__/test.js.snap new file mode 100644 index 000000000..595a34036 --- /dev/null +++ b/tests/python/lang/weak_password_encryption_md5/__snapshots__/test.js.snap @@ -0,0 +1,139 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`python_lang_weak_password_encryption_md5 bad 1`] = ` +"{ + "high": [ + { + "cwe_ids": [ + "331", + "328" + ], + "id": "python_lang_weak_password_encryption_md5", + "title": "Weak encryption algorithm (MD5) used for password detected.", + "description": "## Description\\n\\nA weak hashing library can lead to data breaches and greater security risk.\\n\\n## Remediations\\nAccording to [OWASP](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), MD5 and its predecessors are considered weak hash algorithms and therefore shouldn't be used.\\n\\n❌ Do not use encryption for passwords, wherever possible:\\n\\n\`\`\`python\\nhashlib.md5(user.password).digest()\\n\`\`\`\\n\\n✅ Instead, we recommend using sha256:\\n\\n\`\`\`python\\nhashlib.sha256(user.password).digest()\\n\`\`\`\\n", + "documentation_url": "https://docs.bearer.com/reference/rules/python_lang_weak_password_encryption_md5", + "line_number": 4, + "full_filename": "/tmp/bearer-scan/bad.py", + "filename": ".", + "data_type": { + "category_uuid": "dd88aee5-9d40-4ad2-8983-0c791ddec47c", + "name": "Passwords" + }, + "category_groups": [ + "PII", + "Personal Data" + ], + "source": { + "start": 4, + "end": 4, + "column": { + "start": 15, + "end": 28 + } + }, + "sink": { + "start": 4, + "end": 4, + "column": { + "start": 1, + "end": 29 + }, + "content": "result.update(user.password)" + }, + "parent_line_number": 4, + "snippet": "result.update(user.password)", + "fingerprint": "31f32b01ee463426bea642b75fa25366_0", + "old_fingerprint": "f7ec1ec8f3cb22c75a2f7c5ace4b3b05_0", + "code_extract": "result.update(user.password)" + }, + { + "cwe_ids": [ + "331", + "328" + ], + "id": "python_lang_weak_password_encryption_md5", + "title": "Weak encryption algorithm (MD5) used for password detected.", + "description": "## Description\\n\\nA weak hashing library can lead to data breaches and greater security risk.\\n\\n## Remediations\\nAccording to [OWASP](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), MD5 and its predecessors are considered weak hash algorithms and therefore shouldn't be used.\\n\\n❌ Do not use encryption for passwords, wherever possible:\\n\\n\`\`\`python\\nhashlib.md5(user.password).digest()\\n\`\`\`\\n\\n✅ Instead, we recommend using sha256:\\n\\n\`\`\`python\\nhashlib.sha256(user.password).digest()\\n\`\`\`\\n", + "documentation_url": "https://docs.bearer.com/reference/rules/python_lang_weak_password_encryption_md5", + "line_number": 7, + "full_filename": "/tmp/bearer-scan/bad.py", + "filename": ".", + "data_type": { + "category_uuid": "dd88aee5-9d40-4ad2-8983-0c791ddec47c", + "name": "Passwords" + }, + "category_groups": [ + "PII", + "Personal Data" + ], + "source": { + "start": 7, + "end": 7, + "column": { + "start": 22, + "end": 35 + } + }, + "sink": { + "start": 7, + "end": 7, + "column": { + "start": 10, + "end": 36 + }, + "content": "hashlib.md5(user.password)" + }, + "parent_line_number": 7, + "snippet": "hashlib.md5(user.password)", + "fingerprint": "31f32b01ee463426bea642b75fa25366_1", + "old_fingerprint": "f7ec1ec8f3cb22c75a2f7c5ace4b3b05_1", + "code_extract": "result = hashlib.md5(user.password)" + }, + { + "cwe_ids": [ + "331", + "328" + ], + "id": "python_lang_weak_password_encryption_md5", + "title": "Weak encryption algorithm (MD5) used for password detected.", + "description": "## Description\\n\\nA weak hashing library can lead to data breaches and greater security risk.\\n\\n## Remediations\\nAccording to [OWASP](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), MD5 and its predecessors are considered weak hash algorithms and therefore shouldn't be used.\\n\\n❌ Do not use encryption for passwords, wherever possible:\\n\\n\`\`\`python\\nhashlib.md5(user.password).digest()\\n\`\`\`\\n\\n✅ Instead, we recommend using sha256:\\n\\n\`\`\`python\\nhashlib.sha256(user.password).digest()\\n\`\`\`\\n", + "documentation_url": "https://docs.bearer.com/reference/rules/python_lang_weak_password_encryption_md5", + "line_number": 10, + "full_filename": "/tmp/bearer-scan/bad.py", + "filename": ".", + "data_type": { + "category_uuid": "dd88aee5-9d40-4ad2-8983-0c791ddec47c", + "name": "Passwords" + }, + "category_groups": [ + "PII", + "Personal Data" + ], + "source": { + "start": 10, + "end": 10, + "column": { + "start": 12, + "end": 25 + } + }, + "sink": { + "start": 11, + "end": 11, + "column": { + "start": 10, + "end": 40 + }, + "content": "hashlib.md5(password.encode())" + }, + "parent_line_number": 11, + "snippet": "hashlib.md5(password.encode())", + "fingerprint": "31f32b01ee463426bea642b75fa25366_2", + "old_fingerprint": "f7ec1ec8f3cb22c75a2f7c5ace4b3b05_2", + "code_extract": "result = hashlib.md5(password.encode())" + } + ] +}" +`; + +exports[`python_lang_weak_password_encryption_md5 ok 1`] = `"{}"`; diff --git a/tests/python/lang/weak_password_encryption_md5/test.js b/tests/python/lang/weak_password_encryption_md5/test.js new file mode 100644 index 000000000..5cae02f5c --- /dev/null +++ b/tests/python/lang/weak_password_encryption_md5/test.js @@ -0,0 +1,16 @@ +const { createInvoker, getEnvironment } = require("../../../helper.js") +const { ruleId, ruleFile, testBase } = getEnvironment(__dirname) + +describe(ruleId, () => { + const invoke = createInvoker(ruleId, ruleFile, testBase) + + test("bad", () => { + const testCase = "bad.py" + expect(invoke(testCase)).toMatchSnapshot() + }) + + test("ok", () => { + const testCase = "ok.py" + expect(invoke(testCase)).toMatchSnapshot() + }) +}) diff --git a/tests/python/lang/weak_password_encryption_md5/testdata/bad.py b/tests/python/lang/weak_password_encryption_md5/testdata/bad.py new file mode 100644 index 000000000..b53dd157f --- /dev/null +++ b/tests/python/lang/weak_password_encryption_md5/testdata/bad.py @@ -0,0 +1,12 @@ +import hashlib + +result = hashlib.md5() +result.update(user.password) +result.digest() + +result = hashlib.md5(user.password) +result.digest() + +password = user.password +result = hashlib.md5(password.encode()) +result.hexdigest() \ No newline at end of file diff --git a/tests/python/lang/weak_password_encryption_md5/testdata/ok.py b/tests/python/lang/weak_password_encryption_md5/testdata/ok.py new file mode 100644 index 000000000..522f1fb76 --- /dev/null +++ b/tests/python/lang/weak_password_encryption_md5/testdata/ok.py @@ -0,0 +1,12 @@ +import hashlib + +result = hashlib.sha1() +result.update(user.password) +result.digest() + +result = hashlib.sha1(user.password) +result.digest() + +password = user.password +result = hashlib.sha1(password.encode()) +result.hexdigest() \ No newline at end of file diff --git a/tests/python/lang/weak_password_encryption_sha1/__snapshots__/test.js.snap b/tests/python/lang/weak_password_encryption_sha1/__snapshots__/test.js.snap new file mode 100644 index 000000000..c6f6394f3 --- /dev/null +++ b/tests/python/lang/weak_password_encryption_sha1/__snapshots__/test.js.snap @@ -0,0 +1,139 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`python_lang_weak_password_encryption_sha1 bad 1`] = ` +"{ + "high": [ + { + "cwe_ids": [ + "331", + "328" + ], + "id": "python_lang_weak_password_encryption_sha1", + "title": "Weak encryption algorithm (SHA1) used for password detected.", + "description": "## Description\\n\\nA weak hashing library can lead to data breaches and greater security risk.\\n\\n## Remediations\\nAccording to [OWASP](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), sha1 and its predecessors are considered weak hash algorithms and therefore shouldn't be used.\\n\\n❌ Do not use encryption for passwords, wherever possible:\\n\\n\`\`\`python\\nhashlib.sha1(user.password).digest()\\n\`\`\`\\n\\n✅ Instead, we recommend using sha256:\\n\\n\`\`\`python\\nhashlib.sha256(user.password).digest()\\n\`\`\`\\n", + "documentation_url": "https://docs.bearer.com/reference/rules/python_lang_weak_password_encryption_sha1", + "line_number": 4, + "full_filename": "/tmp/bearer-scan/bad.py", + "filename": ".", + "data_type": { + "category_uuid": "dd88aee5-9d40-4ad2-8983-0c791ddec47c", + "name": "Passwords" + }, + "category_groups": [ + "PII", + "Personal Data" + ], + "source": { + "start": 4, + "end": 4, + "column": { + "start": 15, + "end": 28 + } + }, + "sink": { + "start": 4, + "end": 4, + "column": { + "start": 1, + "end": 29 + }, + "content": "result.update(user.password)" + }, + "parent_line_number": 4, + "snippet": "result.update(user.password)", + "fingerprint": "6f318fa85d638da4930de2d64f16a4d2_0", + "old_fingerprint": "60f59b3c3856ac329dff2a88ed8988b6_0", + "code_extract": "result.update(user.password)" + }, + { + "cwe_ids": [ + "331", + "328" + ], + "id": "python_lang_weak_password_encryption_sha1", + "title": "Weak encryption algorithm (SHA1) used for password detected.", + "description": "## Description\\n\\nA weak hashing library can lead to data breaches and greater security risk.\\n\\n## Remediations\\nAccording to [OWASP](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), sha1 and its predecessors are considered weak hash algorithms and therefore shouldn't be used.\\n\\n❌ Do not use encryption for passwords, wherever possible:\\n\\n\`\`\`python\\nhashlib.sha1(user.password).digest()\\n\`\`\`\\n\\n✅ Instead, we recommend using sha256:\\n\\n\`\`\`python\\nhashlib.sha256(user.password).digest()\\n\`\`\`\\n", + "documentation_url": "https://docs.bearer.com/reference/rules/python_lang_weak_password_encryption_sha1", + "line_number": 7, + "full_filename": "/tmp/bearer-scan/bad.py", + "filename": ".", + "data_type": { + "category_uuid": "dd88aee5-9d40-4ad2-8983-0c791ddec47c", + "name": "Passwords" + }, + "category_groups": [ + "PII", + "Personal Data" + ], + "source": { + "start": 7, + "end": 7, + "column": { + "start": 23, + "end": 36 + } + }, + "sink": { + "start": 7, + "end": 7, + "column": { + "start": 10, + "end": 37 + }, + "content": "hashlib.sha1(user.password)" + }, + "parent_line_number": 7, + "snippet": "hashlib.sha1(user.password)", + "fingerprint": "6f318fa85d638da4930de2d64f16a4d2_1", + "old_fingerprint": "60f59b3c3856ac329dff2a88ed8988b6_1", + "code_extract": "result = hashlib.sha1(user.password)" + }, + { + "cwe_ids": [ + "331", + "328" + ], + "id": "python_lang_weak_password_encryption_sha1", + "title": "Weak encryption algorithm (SHA1) used for password detected.", + "description": "## Description\\n\\nA weak hashing library can lead to data breaches and greater security risk.\\n\\n## Remediations\\nAccording to [OWASP](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), sha1 and its predecessors are considered weak hash algorithms and therefore shouldn't be used.\\n\\n❌ Do not use encryption for passwords, wherever possible:\\n\\n\`\`\`python\\nhashlib.sha1(user.password).digest()\\n\`\`\`\\n\\n✅ Instead, we recommend using sha256:\\n\\n\`\`\`python\\nhashlib.sha256(user.password).digest()\\n\`\`\`\\n", + "documentation_url": "https://docs.bearer.com/reference/rules/python_lang_weak_password_encryption_sha1", + "line_number": 10, + "full_filename": "/tmp/bearer-scan/bad.py", + "filename": ".", + "data_type": { + "category_uuid": "dd88aee5-9d40-4ad2-8983-0c791ddec47c", + "name": "Passwords" + }, + "category_groups": [ + "PII", + "Personal Data" + ], + "source": { + "start": 10, + "end": 10, + "column": { + "start": 12, + "end": 25 + } + }, + "sink": { + "start": 11, + "end": 11, + "column": { + "start": 10, + "end": 41 + }, + "content": "hashlib.sha1(password.encode())" + }, + "parent_line_number": 11, + "snippet": "hashlib.sha1(password.encode())", + "fingerprint": "6f318fa85d638da4930de2d64f16a4d2_2", + "old_fingerprint": "60f59b3c3856ac329dff2a88ed8988b6_2", + "code_extract": "result = hashlib.sha1(password.encode())" + } + ] +}" +`; + +exports[`python_lang_weak_password_encryption_sha1 ok 1`] = `"{}"`; diff --git a/tests/python/lang/weak_password_encryption_sha1/test.js b/tests/python/lang/weak_password_encryption_sha1/test.js new file mode 100644 index 000000000..5cae02f5c --- /dev/null +++ b/tests/python/lang/weak_password_encryption_sha1/test.js @@ -0,0 +1,16 @@ +const { createInvoker, getEnvironment } = require("../../../helper.js") +const { ruleId, ruleFile, testBase } = getEnvironment(__dirname) + +describe(ruleId, () => { + const invoke = createInvoker(ruleId, ruleFile, testBase) + + test("bad", () => { + const testCase = "bad.py" + expect(invoke(testCase)).toMatchSnapshot() + }) + + test("ok", () => { + const testCase = "ok.py" + expect(invoke(testCase)).toMatchSnapshot() + }) +}) diff --git a/tests/python/lang/weak_password_encryption_sha1/testdata/bad.py b/tests/python/lang/weak_password_encryption_sha1/testdata/bad.py new file mode 100644 index 000000000..522f1fb76 --- /dev/null +++ b/tests/python/lang/weak_password_encryption_sha1/testdata/bad.py @@ -0,0 +1,12 @@ +import hashlib + +result = hashlib.sha1() +result.update(user.password) +result.digest() + +result = hashlib.sha1(user.password) +result.digest() + +password = user.password +result = hashlib.sha1(password.encode()) +result.hexdigest() \ No newline at end of file diff --git a/tests/python/lang/weak_password_encryption_sha1/testdata/ok.py b/tests/python/lang/weak_password_encryption_sha1/testdata/ok.py new file mode 100644 index 000000000..5cbe2a48c --- /dev/null +++ b/tests/python/lang/weak_password_encryption_sha1/testdata/ok.py @@ -0,0 +1,12 @@ +import hashlib + +result = hashlib.sha256() +result.update(user.password) +result.digest() + +result = hashlib.sha256(user.password) +result.digest() + +password = user.password +result = hashlib.sha256(password.encode()) +result.hexdigest() \ No newline at end of file