From af10f655b14c42718d1c41c8043b7f7c565a793f Mon Sep 17 00:00:00 2001 From: victor_torre Date: Thu, 20 Sep 2018 17:24:22 +0200 Subject: [PATCH 1/8] Proposed solution for #386 --- bandit/plugins/general_hardcoded_password.py | 14 +++++++------- examples/hardcoded-passwords.py | 3 +++ tests/functional/test_functional.py | 4 ++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/bandit/plugins/general_hardcoded_password.py b/bandit/plugins/general_hardcoded_password.py index e9f7c3a51..127694e85 100644 --- a/bandit/plugins/general_hardcoded_password.py +++ b/bandit/plugins/general_hardcoded_password.py @@ -16,13 +16,13 @@ import ast import sys +import re import bandit from bandit.core import test_properties as test -CANDIDATES = set(["password", "pass", "passwd", "pwd", "secret", "token", - "secrete"]) +RE_CANDIDATES = re.compile('pass|pwd|secret|token', re.IGNORECASE) def _report(value): @@ -84,10 +84,10 @@ def hardcoded_password_string(context): if isinstance(node.parent, ast.Assign): # looks for "candidate='some_string'" for targ in node.parent.targets: - if isinstance(targ, ast.Name) and targ.id in CANDIDATES: + if isinstance(targ, ast.Name) and RE_CANDIDATES.findall(targ.id): return _report(node.s) - elif isinstance(node.parent, ast.Index) and node.s in CANDIDATES: + elif isinstance(node.parent, ast.Index) and RE_CANDIDATES.findall(node.s): # looks for "dict[candidate]='some_string'" # assign -> subscript -> index -> string assign = node.parent.parent.parent @@ -98,7 +98,7 @@ def hardcoded_password_string(context): elif isinstance(node.parent, ast.Compare): # looks for "candidate == 'some_string'" comp = node.parent - if isinstance(comp.left, ast.Name) and comp.left.id in CANDIDATES: + if isinstance(comp.left, ast.Name) and RE_CANDIDATES.findall(comp.left.id): if isinstance(comp.comparators[0], ast.Str): return _report(comp.comparators[0].s) @@ -150,7 +150,7 @@ def hardcoded_password_funcarg(context): """ # looks for "function(candidate='some_string')" for kw in context.node.keywords: - if isinstance(kw.value, ast.Str) and kw.arg in CANDIDATES: + if isinstance(kw.value, ast.Str) and RE_CANDIDATES.findall(kw.arg): return _report(kw.value.s) @@ -211,5 +211,5 @@ def hardcoded_password_default(context): for key, val in zip(context.node.args.args, defs): if isinstance(key, ast.Name) or isinstance(key, ast.arg): check = key.arg if sys.version_info.major > 2 else key.id # Py3 - if isinstance(val, ast.Str) and check in CANDIDATES: + if isinstance(val, ast.Str) and RE_CANDIDATES.findall(check): return _report(val.s) diff --git a/examples/hardcoded-passwords.py b/examples/hardcoded-passwords.py index 221c8f448..bf35a9cb0 100644 --- a/examples/hardcoded-passwords.py +++ b/examples/hardcoded-passwords.py @@ -22,3 +22,6 @@ def NoMatch3(a, b): doLogin(password="blerg") password = "blerg" d["password"] = "blerg" + +EMAIL_PASSWORD = "secret" +email_pwd = 'emails_secret' diff --git a/tests/functional/test_functional.py b/tests/functional/test_functional.py index 0a7af9619..6a3b60509 100644 --- a/tests/functional/test_functional.py +++ b/tests/functional/test_functional.py @@ -179,8 +179,8 @@ def test_exec(self): def test_hardcoded_passwords(self): '''Test for hard-coded passwords.''' expect = { - 'SEVERITY': {'UNDEFINED': 0, 'LOW': 8, 'MEDIUM': 0, 'HIGH': 0}, - 'CONFIDENCE': {'UNDEFINED': 0, 'LOW': 0, 'MEDIUM': 8, 'HIGH': 0} + 'SEVERITY': {'UNDEFINED': 0, 'LOW': 10, 'MEDIUM': 0, 'HIGH': 0}, + 'CONFIDENCE': {'UNDEFINED': 0, 'LOW': 0, 'MEDIUM': 10, 'HIGH': 0} } self.check_example('hardcoded-passwords.py', expect) From 49dc3a5800e40ea73160e1c1b06972af9dc125c6 Mon Sep 17 00:00:00 2001 From: victor_torre Date: Thu, 20 Sep 2018 17:28:04 +0200 Subject: [PATCH 2/8] Fix pep8 Issue #386 --- bandit/plugins/general_hardcoded_password.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bandit/plugins/general_hardcoded_password.py b/bandit/plugins/general_hardcoded_password.py index 127694e85..38cb68f55 100644 --- a/bandit/plugins/general_hardcoded_password.py +++ b/bandit/plugins/general_hardcoded_password.py @@ -15,13 +15,12 @@ # under the License. import ast -import sys import re +import sys import bandit from bandit.core import test_properties as test - RE_CANDIDATES = re.compile('pass|pwd|secret|token', re.IGNORECASE) From be011b167077f66ee14223b6346b3dd4decbf510 Mon Sep 17 00:00:00 2001 From: victor_torre Date: Thu, 20 Sep 2018 17:38:57 +0200 Subject: [PATCH 3/8] Fix line max chars --- bandit/plugins/general_hardcoded_password.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bandit/plugins/general_hardcoded_password.py b/bandit/plugins/general_hardcoded_password.py index 38cb68f55..1f97f5cfa 100644 --- a/bandit/plugins/general_hardcoded_password.py +++ b/bandit/plugins/general_hardcoded_password.py @@ -97,9 +97,10 @@ def hardcoded_password_string(context): elif isinstance(node.parent, ast.Compare): # looks for "candidate == 'some_string'" comp = node.parent - if isinstance(comp.left, ast.Name) and RE_CANDIDATES.findall(comp.left.id): - if isinstance(comp.comparators[0], ast.Str): - return _report(comp.comparators[0].s) + if isinstance(comp.left, ast.Name): + if RE_CANDIDATES.findall(comp.left.id): + if isinstance(comp.comparators[0], ast.Str): + return _report(comp.comparators[0].s) @test.checks('Call') From 07972ec86ca671769d6db08283ee5e2062dd5ae1 Mon Sep 17 00:00:00 2001 From: ehooo Date: Thu, 27 Sep 2018 11:38:03 +0200 Subject: [PATCH 4/8] fix comments on #387 --- bandit/plugins/general_hardcoded_password.py | 14 ++++++++------ examples/hardcoded-passwords.py | 1 + tests/functional/test_functional.py | 4 ++-- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/bandit/plugins/general_hardcoded_password.py b/bandit/plugins/general_hardcoded_password.py index 1f97f5cfa..855499447 100644 --- a/bandit/plugins/general_hardcoded_password.py +++ b/bandit/plugins/general_hardcoded_password.py @@ -21,7 +21,9 @@ import bandit from bandit.core import test_properties as test -RE_CANDIDATES = re.compile('pass|pwd|secret|token', re.IGNORECASE) + +RE_WORDS = "(pas+wo?r?d|pass|pwd|token|secrete?)" +RE_CANDIDATES = re.compile('(^{0}$|_{0}_|^{0}_|_{0}$)'.format(RE_WORDS), re.IGNORECASE) def _report(value): @@ -83,10 +85,10 @@ def hardcoded_password_string(context): if isinstance(node.parent, ast.Assign): # looks for "candidate='some_string'" for targ in node.parent.targets: - if isinstance(targ, ast.Name) and RE_CANDIDATES.findall(targ.id): + if isinstance(targ, ast.Name) and RE_CANDIDATES.search(targ.id): return _report(node.s) - elif isinstance(node.parent, ast.Index) and RE_CANDIDATES.findall(node.s): + elif isinstance(node.parent, ast.Index) and RE_CANDIDATES.search(node.s): # looks for "dict[candidate]='some_string'" # assign -> subscript -> index -> string assign = node.parent.parent.parent @@ -98,7 +100,7 @@ def hardcoded_password_string(context): # looks for "candidate == 'some_string'" comp = node.parent if isinstance(comp.left, ast.Name): - if RE_CANDIDATES.findall(comp.left.id): + if RE_CANDIDATES.search(comp.left.id): if isinstance(comp.comparators[0], ast.Str): return _report(comp.comparators[0].s) @@ -150,7 +152,7 @@ def hardcoded_password_funcarg(context): """ # looks for "function(candidate='some_string')" for kw in context.node.keywords: - if isinstance(kw.value, ast.Str) and RE_CANDIDATES.findall(kw.arg): + if isinstance(kw.value, ast.Str) and RE_CANDIDATES.search(kw.arg): return _report(kw.value.s) @@ -211,5 +213,5 @@ def hardcoded_password_default(context): for key, val in zip(context.node.args.args, defs): if isinstance(key, ast.Name) or isinstance(key, ast.arg): check = key.arg if sys.version_info.major > 2 else key.id # Py3 - if isinstance(val, ast.Str) and RE_CANDIDATES.findall(check): + if isinstance(val, ast.Str) and RE_CANDIDATES.search(check): return _report(val.s) diff --git a/examples/hardcoded-passwords.py b/examples/hardcoded-passwords.py index bf35a9cb0..f9ff91074 100644 --- a/examples/hardcoded-passwords.py +++ b/examples/hardcoded-passwords.py @@ -25,3 +25,4 @@ def NoMatch3(a, b): EMAIL_PASSWORD = "secret" email_pwd = 'emails_secret' +my_secret_password_for_email = 'd6s$f9g!j8mg7hw?n&2' diff --git a/tests/functional/test_functional.py b/tests/functional/test_functional.py index 6a3b60509..0656c435c 100644 --- a/tests/functional/test_functional.py +++ b/tests/functional/test_functional.py @@ -179,8 +179,8 @@ def test_exec(self): def test_hardcoded_passwords(self): '''Test for hard-coded passwords.''' expect = { - 'SEVERITY': {'UNDEFINED': 0, 'LOW': 10, 'MEDIUM': 0, 'HIGH': 0}, - 'CONFIDENCE': {'UNDEFINED': 0, 'LOW': 0, 'MEDIUM': 10, 'HIGH': 0} + 'SEVERITY': {'UNDEFINED': 0, 'LOW': 11, 'MEDIUM': 0, 'HIGH': 0}, + 'CONFIDENCE': {'UNDEFINED': 0, 'LOW': 0, 'MEDIUM': 11, 'HIGH': 0} } self.check_example('hardcoded-passwords.py', expect) From 4dd85ae01945b0f2c84a0a8813c5814c88ae6180 Mon Sep 17 00:00:00 2001 From: ehooo Date: Thu, 27 Sep 2018 11:44:14 +0200 Subject: [PATCH 5/8] fix pep8 --- bandit/plugins/general_hardcoded_password.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bandit/plugins/general_hardcoded_password.py b/bandit/plugins/general_hardcoded_password.py index 855499447..5df9ca15d 100644 --- a/bandit/plugins/general_hardcoded_password.py +++ b/bandit/plugins/general_hardcoded_password.py @@ -23,7 +23,10 @@ RE_WORDS = "(pas+wo?r?d|pass|pwd|token|secrete?)" -RE_CANDIDATES = re.compile('(^{0}$|_{0}_|^{0}_|_{0}$)'.format(RE_WORDS), re.IGNORECASE) +RE_CANDIDATES = re.compile( + '(^{0}$|_{0}_|^{0}_|_{0}$)'.format(RE_WORDS), + re.IGNORECASE +) def _report(value): From b6f017cdacc0deb647e599e7d522cfba85e5ba90 Mon Sep 17 00:00:00 2001 From: victor_torre Date: Mon, 12 Nov 2018 12:10:59 +0100 Subject: [PATCH 6/8] Add passphrase as password detection --- bandit/plugins/general_hardcoded_password.py | 2 +- examples/hardcoded-passwords.py | 1 + tests/functional/test_functional.py | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/bandit/plugins/general_hardcoded_password.py b/bandit/plugins/general_hardcoded_password.py index 5df9ca15d..88bd511fd 100644 --- a/bandit/plugins/general_hardcoded_password.py +++ b/bandit/plugins/general_hardcoded_password.py @@ -22,7 +22,7 @@ from bandit.core import test_properties as test -RE_WORDS = "(pas+wo?r?d|pass|pwd|token|secrete?)" +RE_WORDS = "(pas+wo?r?d|pass(phrase)?|pwd|token|secrete?)" RE_CANDIDATES = re.compile( '(^{0}$|_{0}_|^{0}_|_{0}$)'.format(RE_WORDS), re.IGNORECASE diff --git a/examples/hardcoded-passwords.py b/examples/hardcoded-passwords.py index f9ff91074..8225d4551 100644 --- a/examples/hardcoded-passwords.py +++ b/examples/hardcoded-passwords.py @@ -26,3 +26,4 @@ def NoMatch3(a, b): EMAIL_PASSWORD = "secret" email_pwd = 'emails_secret' my_secret_password_for_email = 'd6s$f9g!j8mg7hw?n&2' +passphrase='1234' diff --git a/tests/functional/test_functional.py b/tests/functional/test_functional.py index 0656c435c..0a7dc4d9d 100644 --- a/tests/functional/test_functional.py +++ b/tests/functional/test_functional.py @@ -179,8 +179,8 @@ def test_exec(self): def test_hardcoded_passwords(self): '''Test for hard-coded passwords.''' expect = { - 'SEVERITY': {'UNDEFINED': 0, 'LOW': 11, 'MEDIUM': 0, 'HIGH': 0}, - 'CONFIDENCE': {'UNDEFINED': 0, 'LOW': 0, 'MEDIUM': 11, 'HIGH': 0} + 'SEVERITY': {'UNDEFINED': 0, 'LOW': 12, 'MEDIUM': 0, 'HIGH': 0}, + 'CONFIDENCE': {'UNDEFINED': 0, 'LOW': 0, 'MEDIUM': 12, 'HIGH': 0} } self.check_example('hardcoded-passwords.py', expect) From d90eecfc2695aedc939cf9c195c5df7f9d1fae10 Mon Sep 17 00:00:00 2001 From: ehooo Date: Fri, 16 Nov 2018 13:33:12 +0100 Subject: [PATCH 7/8] Fix ast.arg check on python2 --- bandit/plugins/general_hardcoded_password.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bandit/plugins/general_hardcoded_password.py b/bandit/plugins/general_hardcoded_password.py index 88bd511fd..a10132d34 100644 --- a/bandit/plugins/general_hardcoded_password.py +++ b/bandit/plugins/general_hardcoded_password.py @@ -214,7 +214,8 @@ def hardcoded_password_default(context): # go through all (param, value)s and look for candidates for key, val in zip(context.node.args.args, defs): - if isinstance(key, ast.Name) or isinstance(key, ast.arg): + py3_is_arg = isinstance(key, ast.arg) if sys.version_info.major > 2 else True # Py3 + if isinstance(key, ast.Name) or py3_is_arg: check = key.arg if sys.version_info.major > 2 else key.id # Py3 if isinstance(val, ast.Str) and RE_CANDIDATES.search(check): return _report(val.s) From 3ed22667afda2583c4acb7dce3c57daba2053f99 Mon Sep 17 00:00:00 2001 From: ehooo Date: Fri, 16 Nov 2018 13:38:44 +0100 Subject: [PATCH 8/8] Fix pep8 --- bandit/plugins/general_hardcoded_password.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bandit/plugins/general_hardcoded_password.py b/bandit/plugins/general_hardcoded_password.py index a10132d34..56f821405 100644 --- a/bandit/plugins/general_hardcoded_password.py +++ b/bandit/plugins/general_hardcoded_password.py @@ -214,7 +214,9 @@ def hardcoded_password_default(context): # go through all (param, value)s and look for candidates for key, val in zip(context.node.args.args, defs): - py3_is_arg = isinstance(key, ast.arg) if sys.version_info.major > 2 else True # Py3 + py3_is_arg = True + if sys.version_info.major > 2: + py3_is_arg = isinstance(key, ast.arg) if isinstance(key, ast.Name) or py3_is_arg: check = key.arg if sys.version_info.major > 2 else key.id # Py3 if isinstance(val, ast.Str) and RE_CANDIDATES.search(check):