hashlib_insecure_functions.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. #
  2. # SPDX-License-Identifier: Apache-2.0
  3. r"""
  4. ======================================================================
  5. B324: Test use of insecure md4, md5, or sha1 hash functions in hashlib
  6. ======================================================================
  7. This plugin checks for the usage of the insecure MD4, MD5, or SHA1 hash
  8. functions in ``hashlib``. The ``hashlib.new`` function provides
  9. the ability to construct a new hashing object using the named algorithm. This
  10. can be used to create insecure hash functions like MD4 and MD5 if they are
  11. passed as algorithm names to this function.
  12. For Python versions prior to 3.9, this check is similar to B303 blacklist
  13. except that this checks for insecure hash functions created using
  14. ``hashlib.new`` function. For Python version 3.9 and later, this check
  15. does additional checking for usage of keyword usedforsecurity on all
  16. function variations of hashlib.
  17. :Example:
  18. .. code-block:: none
  19. >> Issue: [B324:hashlib] Use of weak MD4, MD5, or SHA1 hash for
  20. security. Consider usedforsecurity=False
  21. Severity: High Confidence: High
  22. CWE: CWE-327 (https://cwe.mitre.org/data/definitions/327.html)
  23. Location: examples/hashlib_new_insecure_functions.py:3:0
  24. More Info: https://bandit.readthedocs.io/en/latest/plugins/b324_hashlib.html
  25. 2
  26. 3 hashlib.new('md5')
  27. 4
  28. .. seealso::
  29. - https://cwe.mitre.org/data/definitions/327.html
  30. .. versionadded:: 1.5.0
  31. .. versionchanged:: 1.7.3
  32. CWE information added
  33. """ # noqa: E501
  34. import sys
  35. import bandit
  36. from bandit.core import issue
  37. from bandit.core import test_properties as test
  38. WEAK_HASHES = ("md4", "md5", "sha", "sha1")
  39. def _hashlib_func(context):
  40. if isinstance(context.call_function_name_qual, str):
  41. qualname_list = context.call_function_name_qual.split(".")
  42. if "hashlib" in qualname_list:
  43. func = qualname_list[-1]
  44. keywords = context.call_keywords
  45. if func in WEAK_HASHES:
  46. if keywords.get("usedforsecurity", "True") == "True":
  47. return bandit.Issue(
  48. severity=bandit.HIGH,
  49. confidence=bandit.HIGH,
  50. cwe=issue.Cwe.BROKEN_CRYPTO,
  51. text=f"Use of weak {func.upper()} hash for security. "
  52. "Consider usedforsecurity=False",
  53. lineno=context.node.lineno,
  54. )
  55. elif func == "new":
  56. args = context.call_args
  57. name = args[0] if args else keywords.get("name", None)
  58. if isinstance(name, str) and name.lower() in WEAK_HASHES:
  59. if keywords.get("usedforsecurity", "True") == "True":
  60. return bandit.Issue(
  61. severity=bandit.HIGH,
  62. confidence=bandit.HIGH,
  63. cwe=issue.Cwe.BROKEN_CRYPTO,
  64. text=f"Use of weak {name.upper()} hash for "
  65. "security. Consider usedforsecurity=False",
  66. lineno=context.node.lineno,
  67. )
  68. def _hashlib_new(context):
  69. if isinstance(context.call_function_name_qual, str):
  70. qualname_list = context.call_function_name_qual.split(".")
  71. func = qualname_list[-1]
  72. if "hashlib" in qualname_list and func == "new":
  73. args = context.call_args
  74. keywords = context.call_keywords
  75. name = args[0] if args else keywords.get("name", None)
  76. if isinstance(name, str) and name.lower() in WEAK_HASHES:
  77. return bandit.Issue(
  78. severity=bandit.MEDIUM,
  79. confidence=bandit.HIGH,
  80. cwe=issue.Cwe.BROKEN_CRYPTO,
  81. text=f"Use of insecure {name.upper()} hash function.",
  82. lineno=context.node.lineno,
  83. )
  84. @test.test_id("B324")
  85. @test.checks("Call")
  86. def hashlib(context):
  87. if sys.version_info >= (3, 9):
  88. return _hashlib_func(context)
  89. else:
  90. return _hashlib_new(context)