|
1 | | -<p>In cryptography, "salt" is extra piece of data which is included in a hashing algorithm. It makes dictionary attacks more difficult. Using a |
2 | | -cryptographic hash function without an unpredictable salt increases the likelihood that an attacker will be able to successfully guess a hashed value |
3 | | -such as a password with a dictionary attack.</p> |
4 | | -<p>This rule raises an issue when a hashing function which has been specifically designed for hashing sensitive data, such as PBKDF2, is used with a |
5 | | -non-random, reused or too short salt value. It does not raise an issue on base hashing algorithms such as sha1 or md5 as these are often used for |
6 | | -other purposes.</p> |
| 1 | +<p>In cryptography, a "salt" is an extra piece of data which is included when hashing a password. This makes <code>rainbow-table attacks</code> more |
| 2 | +difficult. Using a cryptographic hash function without an unpredictable salt increases the likelihood that an attacker could successfully find the |
| 3 | +hash value in databases of precomputed hashes (called <code>rainbow-tables</code>).</p> |
| 4 | +<p>This rule raises an issue when a hashing function which has been specifically designed for hashing passwords, such as <code>PBKDF2</code>, is used |
| 5 | +with a non-random, reused or too short salt value. It does not raise an issue on base hashing algorithms such as <code>sha1</code> or <code>md5</code> |
| 6 | +as they should not be used to hash passwords.</p> |
7 | 7 | <h2>Recommended Secure Coding Practices</h2> |
8 | 8 | <ul> |
9 | | - <li> Use hashing functions generating their own salt or generate a long random salt of at least 32 bytes. </li> |
10 | | - <li> The salt is at least as long as the resulting hash value. </li> |
11 | | - <li> Provide the salt to a safe hashing function such as PBKDF2. </li> |
12 | | - <li> Save both the salt and the hashed value in the relevant database record; during future validation operations, the salt and hash can then be |
13 | | - retrieved from the database. The hash is recalculated with the stored salt and the value being validated, and the result compared to the stored |
14 | | - hash. </li> |
| 9 | + <li> Use hashing functions generating their own secure salt or generate a secure random value of at least 16 bytes. </li> |
| 10 | + <li> The salt should be unique by user password. </li> |
15 | 11 | </ul> |
16 | 12 | <h2>Noncompliant Code Example</h2> |
17 | | -<p>Below, the hashed password is not salted:</p> |
18 | | -<pre> |
19 | | -MessageDigest md = MessageDigest.getInstance("SHA-512"); |
20 | | -byte[] hashedPassword = md.digest(passwordToHash.getBytes(StandardCharsets.UTF_8)); // Noncompliant |
21 | | -</pre> |
22 | | -<pre> |
23 | | -MessageDigest md = MessageDigest.getInstance("SHA-512"); |
24 | | -md.update(passwordToHash.getBytes(StandardCharsets.UTF_8)); |
25 | | -byte[] hashedPassword = md.digest(); // Noncompliant, only one "update()" call and "digest()" without parameters |
26 | | -</pre> |
27 | | -<pre> |
28 | | -MessageDigest md = MessageDigest.getInstance("SHA-512"); |
29 | | -byte[] hashedPassword = md.digest(passwordToHash.getBytes(StandardCharsets.UTF_8)); // Noncompliant, no "update()" call |
30 | | -</pre> |
31 | | -<pre> |
32 | | -PBEKeySpec spec = new PBEKeySpec(chars); // Noncompliant, no salt as an argument |
33 | | -</pre> |
| 13 | +<p>Below, the hashed password use a predictable salt:</p> |
34 | 14 | <pre> |
35 | 15 | byte[] salt = "notrandom".getBytes(); |
36 | | -PBEKeySpec spec = new PBEKeySpec(chars, salt); // Noncompliant, predictable salt |
| 16 | + |
| 17 | +PBEParameterSpec cipherSpec = new PBEParameterSpec(salt, 10000); // Noncompliant, predictable salt |
| 18 | +PBEKeySpec spec = new PBEKeySpec(chars, salt, 10000, 256); // Noncompliant, predictable salt |
37 | 19 | </pre> |
38 | 20 | <h2>Compliant Solution</h2> |
39 | | -<p>Use <code>java.security.SecureRandom</code> to produce a unpredictable salt:</p> |
| 21 | +<p>Use <code>java.security.SecureRandom</code> to generate an unpredictable salt:</p> |
40 | 22 | <pre> |
41 | | -MessageDigest md = MessageDigest.getInstance("SHA-512"); |
42 | | - |
43 | 23 | SecureRandom random = new SecureRandom(); |
44 | 24 | byte[] salt = new byte[16]; |
45 | 25 | random.nextBytes(salt); |
46 | 26 |
|
47 | | -md.update(salt); |
48 | | - |
49 | | -byte[] hashedPassword = md.digest(passwordToHash.getBytes(StandardCharsets.UTF_8)); // Compliant |
50 | | -</pre> |
51 | | -<pre> |
52 | | -byte[] salt = this.secureSalt(); |
53 | | -PBEKeySpec spec = new PBEKeySpec(chars, salt); // Compliant |
| 27 | +PBEParameterSpec cipherSpec = new PBEParameterSpec(salt, 10000); // Compliant |
| 28 | +PBEKeySpec spec = new PBEKeySpec(chars, salt, 10000, 256); // Compliant |
54 | 29 | </pre> |
55 | 30 | <h2>See</h2> |
56 | 31 | <ul> |
|
0 commit comments