python.lang.security.audit.md5-used-as-password.md5-used-as-password

Author
unknown
Download Count*
License
It looks like MD5 is used as a password hash. MD5 is not considered a secure password hash because it can be cracked by an attacker in a short amount of time. Use a suitable password hashing function such as scrypt. You can use hashlib.scrypt
.
Run Locally
Run in CI
Defintion
rules:
- id: md5-used-as-password
severity: WARNING
message: It looks like MD5 is used as a password hash. MD5 is not considered a
secure password hash because it can be cracked by an attacker in a short
amount of time. Use a suitable password hashing function such as scrypt.
You can use `hashlib.scrypt`.
languages:
- python
metadata:
cwe:
- "CWE-327: Use of a Broken or Risky Cryptographic Algorithm"
owasp:
- A03:2017 - Sensitive Data Exposure
- A02:2021 - Cryptographic Failures
references:
- https://tools.ietf.org/html/rfc6151
- https://crypto.stackexchange.com/questions/44151/how-does-the-flame-malware-take-advantage-of-md5-collision
- https://pycryptodome.readthedocs.io/en/latest/src/hash/sha3_256.html
- https://security.stackexchange.com/questions/211/how-to-securely-hash-passwords
- https://github.com/returntocorp/semgrep-rules/issues/1609
- https://docs.python.org/3/library/hashlib.html#hashlib.scrypt
category: security
technology:
- pycryptodome
- hashlib
- md5
subcategory:
- vuln
likelihood: HIGH
impact: LOW
confidence: MEDIUM
license: Commons Clause License Condition v1.0[LGPL-2.1-only]
mode: taint
pattern-sources:
- patterns:
- pattern-either:
- pattern: hashlib.md5
- pattern: hashlib.new(..., name="MD5", ...)
- pattern: Cryptodome.Hash.MD5
- pattern: Crypto.Hash.MD5
- pattern: cryptography.hazmat.primitives.hashes.MD5
pattern-sinks:
- patterns:
- pattern: $FUNCTION(...)
- metavariable-regex:
metavariable: $FUNCTION
regex: (?i)(.*password.*)
Examples
md5-used-as-password.py
import hashlib
from cryptography.hazmat.primitives import hashes
from Crypto.Hash import MD5, SHA256
#### True Positives ####
def ex1(user, pwtext):
md5 = hashlib.md5(pwtext).hexdigest()
# ruleid: md5-used-as-password
user.setPassword(md5)
def ex2(user, pwtext):
digest = hashes.Hash(hashes.MD5())
digest.update(bytes(pwtext))
# ruleid: md5-used-as-password
user.setPassword(digest.finalize())
def ex3(user, pwtext):
h = MD5.new()
h.update(bytes(pwtext))
# ruleid: md5-used-as-password
user.setPassword(h.hexdigest())
#### True Negatives ####
def ok1(user, pwtext):
sha = hashlib.sha256(pwtext).hexdigest()
# ok: md5-used-as-password
user.setPassword(sha)
def ok2(user, pwtext):
digest = hashes.Hash(hashes.SHA256())
digest.update(bytes(pwtext))
# ok: md5-used-as-password
user.setPassword(digest.finalize())
def ok3(user, pwtext):
h = SHA256.new()
h.update(bytes(pwtext))
# ok: md5-used-as-password
user.setPassword(h.hexdigest())
def ok4(user, pwtext):
h = MD5.new()
h.update(bytes(pwtext))
# ok: md5-used-as-password
user.updateSomethingElse(h.hexdigest())
Short Link: https://sg.run/5DwD