Don't use weak hash algorithms (MD5, SHA1)
Matches methods calling MD5, SHA1, RIPEMD160 or HMACMD5 constructors, factories (MD5.Create()), one-shot helpers (SHA1.HashData()) or selecting them through HashAlgorithmName.MD5 / HashAlgorithmName.SHA1. Practical collision attacks exist against MD5 (since 2004) and SHA1 (SHAttered, 2017): https://shattered.io/ . NIST deprecated SHA1 for digital signatures in 2011 and plans its full retirement by 2030.
This is CWE-328 Use of Weak Hash.
Flagged Code
This is CWE-328 Use of Weak Hash.
Flagged Code
static string Fingerprint(byte[] data) {
using var md5 = MD5.Create(); // flagged: MD5
return Convert.ToHexString(md5.ComputeHash(data));
}
static byte[] Digest(byte[] data) => SHA1.HashData(data); // flagged: SHA1
Fixed Codestatic string Fingerprint(byte[] data) {
using var sha256 = SHA256.Create();
return Convert.ToHexString(sha256.ComputeHash(data));
}
static byte[] Digest(byte[] data) => SHA256.HashData(data);How to fix
Use SHA256 or stronger (SHA384, SHA512, SHA3_256) for integrity and signatures, and a dedicated password hashing function (Rfc2898DeriveBytes with SHA256, bcrypt, scrypt or Argon2) for passwords.
When the hash is not security-related (cache keys, ETags, deduplication of non-hostile data), prefer a fast non-cryptographic hash such as System.IO.Hashing.XxHash3 and suppress the issue.
When the hash is not security-related (cache keys, ETags, deduplication of non-hostile data), prefer a fast non-cryptographic hash such as System.IO.Hashing.XxHash3 and suppress the issue.
CQLinq source
This rule is written in CQLinq, C# LINQ over the NDepend code model. It ships with every new NDepend project: you can read it, adapt it, or use it as a starting point for your own custom rules.
// <Name>Don't use weak hash algorithms (MD5, SHA1)</Name>
// <Id>ND3109:DontUseWeakHashAlgorithms</Id>
warnif count > 0
// Third-party members are part of the code model only when the application uses them.
let weakHashTypes = ThirdParty.Types.WithFullNameIn(
"System.Security.Cryptography.MD5",
"System.Security.Cryptography.MD5CryptoServiceProvider",
"System.Security.Cryptography.MD5Cng",
"System.Security.Cryptography.SHA1",
"System.Security.Cryptography.SHA1Managed",
"System.Security.Cryptography.SHA1CryptoServiceProvider",
"System.Security.Cryptography.SHA1Cng",
"System.Security.Cryptography.RIPEMD160",
"System.Security.Cryptography.RIPEMD160Managed",
"System.Security.Cryptography.HMACMD5",
"System.Security.Cryptography.HMACRIPEMD160",
"System.Security.Cryptography.MACTripleDES")
// Constructors, factories and one-shot helpers: new MD5CryptoServiceProvider(), SHA1.Create(), MD5.HashData(bytes)...
let weakHashMembers = weakHashTypes.ChildMethods()
.Where(m => m.IsConstructor ||
(m.IsStatic && m.SimpleName.StartsWithAny("Create", "HashData", "TryHashData", "HashDataAsync")))
// HashAlgorithmName.MD5 / HashAlgorithmName.SHA1 select a weak algorithm in
// IncrementalHash, Rfc2898DeriveBytes, RSA.SignData(), ECDsa.SignData(), X509 requests...
.Concat(ThirdParty.Types.WithFullName("System.Security.Cryptography.HashAlgorithmName")
.ChildMethods().Where(m => m.SimpleNameEqualsAny("get_MD5", "get_SHA1")))
.ToHashSetEx()
where weakHashMembers.Any()
from m in Application.Methods.UsingAny(weakHashMembers)
let weakHashMembersUsed = m.MethodsCalled.Intersect(weakHashMembers).ToArray()
select new {
m,
weakHashMembersUsed,
Debt = (20 + 10 * weakHashMembersUsed.Length).ToMinutes().ToDebt(),
Severity = Severity.High
}
//<Expl>
// The *{0}* uses the weak hash algorithm(s) *{1}*.
// MD5 and SHA1 are vulnerable to collision attacks and must not protect
// passwords, signatures, tokens or integrity checks.
//</Expl>
//<Desc>
// Matches methods calling MD5, SHA1, RIPEMD160 or HMACMD5 constructors,
// factories (*MD5.Create()*), one-shot helpers (*SHA1.HashData()*) or
// selecting them through *HashAlgorithmName.MD5* / *HashAlgorithmName.SHA1*.
// Practical collision attacks exist against MD5 (since 2004) and SHA1
// (SHAttered, 2017): https://shattered.io/ . NIST deprecated SHA1 for
// digital signatures in 2011 and plans its full retirement by 2030.
//
// This is CWE-328 *Use of Weak Hash*.
//
// **Flagged Code**
// ```csharp
// static string Fingerprint(byte[] data) {
// using var md5 = MD5.Create(); // flagged: MD5
// return Convert.ToHexString(md5.ComputeHash(data));
// }
// static byte[] Digest(byte[] data) => SHA1.HashData(data); // flagged: SHA1
// ```
//
// **Fixed Code**
// ```csharp
// static string Fingerprint(byte[] data) {
// using var sha256 = SHA256.Create();
// return Convert.ToHexString(sha256.ComputeHash(data));
// }
// static byte[] Digest(byte[] data) => SHA256.HashData(data);
// ```
//</Desc>
//<HowToFix>
// Use *SHA256* or stronger (*SHA384*, *SHA512*, *SHA3_256*) for integrity
// and signatures, and a dedicated password hashing function (*Rfc2898DeriveBytes
// with SHA256*, *bcrypt*, *scrypt* or *Argon2*) for passwords.
//
// When the hash is not security-related (cache keys, ETags, deduplication
// of non-hostile data), prefer a fast non-cryptographic hash such as
// *System.IO.Hashing.XxHash3* and suppress the issue.
//</HowToFix>
Open in the interactive Rules Explorer · All default rules
Security: all 39 items
- Software Composition Analysis (SCA) ND3120
- Transitive Software Composition Analysis (SCA) ND3121
- Don't hard-code secrets in constants ND3114
- Review credentials built from hard-coded values ND3115
- Don't use insecure deserializers ND3110
- Don't use weak hash algorithms (MD5, SHA1) ND3109
- Don't use DES/3DES/RC2 weak cipher algorithms ND3102
- Don't use weak password-based key derivation ND3123
- Don't use the ECB encryption mode ND3132
- Don't disable certificate validation ND3103
- Don't hard-code TLS/SSL protocol versions ND3122
- Review commands vulnerable to SQL injection ND3107
- Review data adapters vulnerable to SQL injection ND3108
- Review raw SQL built from composed strings ND3128
- Review LDAP filters composed from strings ND3137
- Don't enable external XML entity resolution (XXE) ND3111
- Review processes started with a composed arguments string ND3124
- Review web endpoints building file paths from their parameters ND3129
- Review custom archive extraction (Zip Slip) ND3135
- Review assemblies and types loaded from runtime-provided names ND3125
- Review web endpoints without [Authorize] nor [AllowAnonymous] ND3118
- Review state-changing endpoints opened to anonymous callers ND3130
- Review state-changing MVC actions without anti-forgery validation ND3119
- Review HTML-encoding bypasses ND3133
- Review explicitly disabled request validation ND3134
- Review redirects to a URL that is not validated as local ND3126
- Review request-influenced outbound HTTP calls (SSRF) ND3136
- Review insecure ASP.NET Core CORS policies and unguarded developer exception page ND3116
- Review cookies created without HttpOnly and Secure flags ND3117
- Review regular expressions without a match timeout (ReDoS) ND3112
- Review secrets compared with non-constant-time equality ND3113
- Review secrets passed to logging methods ND3127
- Review security operations that log nothing ND3131
- Don't use System.Random for security purposes ND3101
- Don't use CoSetProxyBlanket and CoInitializeSecurity ND3100
- Review publicly visible event handlers ND3104
- Pointers should not be publicly visible ND3105
- Seal methods that satisfy non-public interfaces ND3106
- Restrict sensitive APIs to reviewed components ND3138