From a98519927be935eb6f331226c1fcc272822d4a68 Mon Sep 17 00:00:00 2001 From: Rajath Agasthya Date: Fri, 15 Sep 2017 18:25:55 -0700 Subject: [PATCH] Plugin to flag insecure hash functions created using hashlib.new() Currently, insecure hash function usage by calling hashlib.md5() is flagged in B303. But these hash functions can also be obtained using hashlib.new(), by passing 'md4' or 'md5' as an argument. This plugin checks such usage. Change-Id: I8d368aea287e1287e5f638b48c4297d355037839 Closes-Bug: #1708582 --- README.rst | 1 + .../plugins/hashlib_new_insecure_functions.py | 63 +++++++++++++++++++ examples/hashlib_new_insecure_functions.py | 16 +++++ setup.cfg | 3 + tests/functional/test_functional.py | 8 +++ 5 files changed, 91 insertions(+) create mode 100644 bandit/plugins/hashlib_new_insecure_functions.py create mode 100644 examples/hashlib_new_insecure_functions.py diff --git a/README.rst b/README.rst index 41aede1c..f53de9fa 100644 --- a/README.rst +++ b/README.rst @@ -174,6 +174,7 @@ Usage:: B321 ftplib B322 input B323 unverified_context + B324 hashlib_new_insecure_functions B401 import_telnetlib B402 import_ftplib B403 import_pickle diff --git a/bandit/plugins/hashlib_new_insecure_functions.py b/bandit/plugins/hashlib_new_insecure_functions.py new file mode 100644 index 00000000..46436c22 --- /dev/null +++ b/bandit/plugins/hashlib_new_insecure_functions.py @@ -0,0 +1,63 @@ +# -*- coding:utf-8 -*- +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +r""" +========================================================================== +B324: Test for use of insecure md4 and md5 hash functions in hashlib.new() +========================================================================== + +This plugin checks for the usage of the insecure MD4 and MD5 hash functions +in ``hashlib.new`` function. The ``hashlib.new`` function provides the ability +to construct a new hashing object using the named algorithm. This can be used +to create insecure hash functions like MD4 and MD5 if they are passed as +algorithm names to this function. + +This is similar to B303 blacklist check, except that this checks for insecure +hash functions created using ``hashlib.new`` function. + +:Example: + + >> Issue: [B324:hashlib_new] Use of insecure MD4 or MD5 hash function. + Severity: Medium Confidence: High + Location: examples/hashlib_new_insecure_funcs.py:3 + 2 + 3 md5_hash = hashlib.new('md5', string='test') + 4 print(md5_hash) + + +.. versionadded:: 1.5.0 + +""" + +import bandit +from bandit.core import test_properties as test + + +@test.test_id('B324') +@test.checks('Call') +def hashlib_new(context): + if isinstance(context.call_function_name_qual, str): + qualname_list = context.call_function_name_qual.split('.') + func = qualname_list[-1] + if 'hashlib' in qualname_list and func == 'new': + args = context.call_args + keywords = context.call_keywords + name = args[0] if args else keywords['name'] + if name.lower() in ('md4', 'md5'): + return bandit.Issue( + severity=bandit.MEDIUM, + confidence=bandit.HIGH, + text="Use of insecure MD4 or MD5 hash function.", + lineno=context.node.lineno, + ) diff --git a/examples/hashlib_new_insecure_functions.py b/examples/hashlib_new_insecure_functions.py new file mode 100644 index 00000000..eeddccac --- /dev/null +++ b/examples/hashlib_new_insecure_functions.py @@ -0,0 +1,16 @@ +import hashlib + +hashlib.new('md5') + +hashlib.new('md4', 'test') + +hashlib.new(name='md5', string='test') + +hashlib.new('MD4', string='test') + +hashlib.new(string='test', name='MD5') + +# Test that plugin does not flag valid hash functions. +hashlib.new('sha256') + +hashlib.new('SHA512') diff --git a/setup.cfg b/setup.cfg index cb3aad64..a8fdbbb1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -81,6 +81,9 @@ bandit.plugins = # bandit/plugins/injection_sql.py hardcoded_sql_expressions = bandit.plugins.injection_sql:hardcoded_sql_expressions + # bandit/plugins/hashlib_new_insecure_functions.py + hashlib_new_insecure_functions = bandit.plugins.hashlib_new_insecure_functions:hashlib_new + # bandit/plugins/injection_wildcard.py linux_commands_wildcard_injection = bandit.plugins.injection_wildcard:linux_commands_wildcard_injection diff --git a/tests/functional/test_functional.py b/tests/functional/test_functional.py index db6e3db2..60dd5851 100644 --- a/tests/functional/test_functional.py +++ b/tests/functional/test_functional.py @@ -697,3 +697,11 @@ class FunctionalTests(testtools.TestCase): 'CONFIDENCE': {'UNDEFINED': 0, 'LOW': 0, 'MEDIUM': 0, 'HIGH': 1} } self.check_example('unverified_context.py', expect) + + def test_hashlib_new_insecure_functions(self): + '''Test insecure hash functions created by `hashlib.new`.''' + expect = { + 'SEVERITY': {'UNDEFINED': 0, 'LOW': 0, 'MEDIUM': 5, 'HIGH': 0}, + 'CONFIDENCE': {'UNDEFINED': 0, 'LOW': 0, 'MEDIUM': 0, 'HIGH': 5} + } + self.check_example('hashlib_new_insecure_functions.py', expect)