Use of a broken or weak cryptographic hashing algorithm on sensitive data¶
ID: rb/weak-sensitive-data-hashingKind: path-problemSecurity severity: 7.5Severity: warningPrecision: highTags: - security - external/cwe/cwe-327 - external/cwe/cwe-328 - external/cwe/cwe-916Query suites: - ruby-code-scanning.qls - ruby-security-extended.qls - ruby-security-and-quality.qls
Click to see the query in the CodeQL repository
Using a broken or weak cryptographic hash function can leave data vulnerable, and should not be used in security related code.
A strong cryptographic hash function should be resistant to:
pre-image attacks: if you know a hash value
h(x), you should not be able to easily find the inputx.collision attacks: if you know a hash value
h(x), you should not be able to easily find a different inputywith the same hash valueh(x)=h(y).In cases with a limited input space, such as for passwords, the hash function also needs to be computationally expensive to be resistant to brute-force attacks. Passwords should also have an unique salt applied before hashing, but that is not considered by this query.
As an example, both MD5 and SHA-1 are known to be vulnerable to collision attacks.
Since it’s OK to use a weak cryptographic hash function in a non-security context, this query only alerts when these are used to hash sensitive data (such as passwords, certificates, usernames).
Use of broken or weak cryptographic algorithms that are not hashing algorithms, is handled by therb/weak-cryptographic-algorithm query.
Recommendation¶
Ensure that you use a strong, modern cryptographic hash function:
such as Argon2, scrypt, bcrypt, or PBKDF2 for passwords and other data with limited input space.
such as SHA-2, or SHA-3 in other cases.
Example¶
The following example shows two functions for checking whether the hash of a certificate matches a known value – to prevent tampering. The first function uses MD5 that is known to be vulnerable to collision attacks. The second function uses SHA-256 that is a strong cryptographic hashing function.
require'openssl'defcertificate_matches_known_hash_bad(certificate,known_hash)hash=OpenSSL::Digest.new('SHA1').digestcertificatehash==known_hashenddefcertificate_matches_known_hash_good(certificate,known_hash)hash=OpenSSL::Digest.new('SHA256').digestcertificatehash==known_hashend
Example¶
The following example shows two functions for hashing passwords. The first function uses SHA-256 to hash passwords. Although SHA-256 is a strong cryptographic hash function, it is not suitable for password hashing since it is not computationally expensive.
require'openssl'defget_password_hash(password,salt)OpenSSL::Digest.new('SHA256').digest(password+salt)# BADend
The second function uses Argon2 (through theargon2 gem), which is a strong password hashing algorithm (and includes a per-password salt by default).
require'argon2'defget_initial_hash(password)Argon2::Password.create(password)enddefcheck_password(password,known_hash)Argon2::Password.verify_password(password,known_hash)end