Asked  5 Months ago    Answers:  5   Viewed   136 times

I'm deploying a classic hashing protection for user passwords. The submitted password on login is salted, hashed, and then compared to the already stored hash in the database.

But instead of using a PHP function call to compare the now hashed user input and the stored hash, the comparison is done in database - more precisely, using a WHERE clause (NOTE: the salt is already known for various reasons at the time this comparison begins, but the password is not).

Since usernames are unique, the following query effectively tells if the username + password pair is a match or not:

SELECT * FROM `users` WHERE `password`='$password_hash' AND `username`='$username';

Is this approach vulnerable to timing attacks?


EDIT: SQL injection is not a concern, it is taken care of.

 Answers

54

Yes, the string comparison (and/or index lookup) may, in principle, leak how many identical leading bytes the password hash stored in the database and the one computed from the entered password share.

In principle, an attacker could use this to iteratively learn a prefix of the password hash, byte by byte: first they find a hash that shares its first byte with the hash in the database, then one that shares its first two bytes, and so on.

No, this will almost certainly not matter.

Why? Well, for a number of reasons:

  1. A timing attack may allow the attacker to learn a part of the user's password hash. A well-designed password hashing scheme (using a salt and key stretching), however, should remain secure (assuming, of course, that the passwords themselves are not easily guessable) even if the attacker knows the entire password hash. Thus, even if the timing attack succeeds, the passwords themselves will be safe.

  2. To carry out the attack, the attacker must submit passwords whose hash value they know. The hash value depends on the salt. Thus, unless the attacker somehow already knows the salt, this attack is not possible.

    (It is true that, in most security analyses of password hashing schemes, the salt is assumed to be public information. However, this is only because such analyses assume the worst-case scenario mentioned above, where the attacker has already obtained a copy of the entire user database, salts and hashes and all. If the attacker doesn't yet know the hash, there's no reason to assume they would know the salt.)

  3. Even if the attacker knows the salt, in order to carry out the iterative attack described above, they'll need to generate passwords that hash to a value with a desired prefix. For any secure hash function, the only practical way to do this is by trial an error, which means that the time needed to do so scales exponentially with the length of the prefix.

    What this means in practice is that, in order to extract sufficiently many bits of the hash to be able to carry out an offline brute force attack against it (which need not be all of them; just more than the effective amount of entropy in the password), the attacker needs to carry out about as much computation as required to crack the password itself. For a well designed password hashing scheme, and a securely chosen password, this is not feasible.

  4. What the iterative attack can give the attacker, in principle, is the ability to do most of the brute force computation locally at their end, while only submitting a fairly small number of passwords to your system. However, even this only holds if they receive detailed and reliable timing information back from each password submitted. In practice, real timing attacks are extremely inefficient, and require many (often thousands or millions) queries to yield any useful information at all. This will very likely cancel out any potential performance advantage that the timing attack could provide for the attacker.

    This point is amplified you use a proper key-stretching password hashing scheme, since such schemes are deliberately designed to be slow. Thus, the string comparison in the database will likely take a negligible amount of time compared to hashing the password in the first place, and any timing variations caused by it will thus be lost in the noise.

Saturday, May 29, 2021
 
sohum
answered 5 Months ago
19

I think you need to take a look into how mysqli_ works. This should get you in the right direction.

if(isset($_POST['submit'])){
    $username = $_POST['username'];
    $password = md5($_POST['password']);
    $user_id = 0;
    $status = ""

    $stmt = $con->prepare("SELECT user_id, username, password, status FROM users WHERE username=? AND password=? LIMIT 1");
    $stmt->bind_param('ss', $username, $password);
    $stmt->execute();
    $stmt->bind_result($user_id, $username, $password, $status);
    $stmt->store_result();
    if($stmt->num_rows == 1)  //To check if the row exists
        {
            if($stmt->fetch()) //fetching the contents of the row
            {
               if ($status == 'd') {
                   echo "YOUR account has been DEACTIVATED.";
                   exit();
               } else {
                   $_SESSION['Logged'] = 1;
                   $_SESSION['user_id'] = $user_id;
                   $_SESSION['username'] = $username;
                   echo 'Success!';
                   exit();
               }
           }

    }
    else {
        echo "INVALID USERNAME/PASSWORD Combination!";
    }
    $stmt->close();
}
else 
{   

}
$con->close();
Wednesday, March 31, 2021
 
Sidarta
answered 7 Months ago
53

The collation has nothing to do with the storage. You need to set the charset to determine the storage encoding. The collation governs how comparison and sorting should happen. The collation must be charset aware, but otherwise it has nothing to do with the charset.

To answer your question, you can use iconv to translitter the text, and then compare it. For example:

function compare($s1, $s2) {
  return strcmp(
    iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $s1),
    iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $s2));
}

This is basically what MySql will do for you, although it's probably faster and it may have a slightly different collation-table than ISO-8859-1//TRANSLIT. Not entirely sure about that.

Would probably be easier to use the database though, as others have already suggested.

Saturday, May 29, 2021
 
kmunky
answered 5 Months ago
37

An attacker is "allowed" to know the salt - your security must be designed in a way that even with the knowledge of the salt it is still secure.

What does the salt do ?

Salt aids in defending against brute-force attacks using pre-computed "rainbow-tables".
Salt makes brute-force much more expensive (in time/memory terms) for the attacker.
Calculating such a table is expensive and usually only done when it can be used for more than one attack/password.
IF you use the same salt for all password an attacker could pre-compute such a table and then brute-force your passwords into cleartext...
As long as you generate a new (best cryptogrpahically strong) random salt for every password you want to store the hash of there is no problem.

IF you want to strengthen the security further
You could calculate the hash several times over (hash the hash etc.) - this doesn't cost you much but it makes a brute-force attack / calculating "rainbow-tables" even more expensive... please don't invent yourself - there are proven standard methods to do so, see for example http://en.wikipedia.org/wiki/PBKDF2 and http://www.itnewb.com/tutorial/Encrypting-Passwords-with-PHP-for-Storage-Using-the-RSA-PBKDF2-Standard

NOTE:

Using such a mechanism is these days mandatrory since "CPU time" (usable for attacks like rainbow tables/brute force etc.) is getting more and more widely available (see for example the fact that Amazon's Cloud service is among the top 50 of fastest supercomuters worldwide and can be used by anyone for a comparatively small amount)!

Monday, June 14, 2021
 
KingCrunch
answered 5 Months ago
61

You could use the DATE function:

SELECT col1, col2, ..., coln
FROM order_table
WHERE date(order_date) = '2012-05-03'

But this is more efficient, if your table is large and you have an index on order date:

SELECT col1, col2, ..., coln
FROM order_table
WHERE order_date >= '2012-05-03'
AND order_date < '2012-05-04'
Monday, August 9, 2021
 
ysquared
answered 3 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :