Safety of trying to login (preventing time-attack)

Safety of trying to login (preventing time-attack)

问题

I came across a security issue. Please have a look at the pseudocode below

public static bool TryLogin(string email, string password)
{
    if (UserExists(email)) // here is the problem
        return false;

    var hash = GetRealPasswordHash(email);
    var hash2 = GetHash(email, password);
    return SlowEquals(hash, hash2);
}

Some of you may already see the hole. An attacker may perform a time-attack over the network - detect how fast the answer is returned and based on that detect if there is a user in the database or not! Having known that, the attacker may now check various passwords for the user he already knows that exists!

A word of explanation if you don't see the problem or don't believe it to be a problem (this is for hashes, but analogical issue is here):

Comparing the hashes in "length-constant" time ensures that an attacker cannot extract the hash of a password in an on-line system using a timing attack, then crack it off-line.

The standard way to check if two sequences of bytes (strings) are the same is to compare the first byte, then the second, then the third, and so on. As soon as you find a byte that isn't the same for both strings, you know they are different and can return a negative response immediately. If you make it through both strings without finding any bytes that differ, you know the strings are the same and can return a positive result. This means that comparing two strings can take a different amount of time depending on how much of the strings match.

For example, a standard comparison of the strings "xyzabc" and "abcxyz" would immediately see that the first character is different and wouldn't bother to check the rest of the string. On the other hand, when the strings "aaaaaaaaaaB" and "aaaaaaaaaaZ" are compared, the comparison algorithm scans through the block of "a" before it determins the strings are unequal.

It might seem like it would be impossible to run a timing attack over a network. However, it has been done, and has been shown to be practical.

Here you can see the article

What should I do then, when I detect that a user does not exist? I definitely should perform some more calculations, but what is a good technique here? What do you guys use in such scenarios?

If this is of any significance, I am using C#.

 

Many systems already leak that there is a username taken through their "reset password" and similar portals. If you want to avoid the time attack anyway, you can make a dummy假的 user and run through the motions until the last step where you compare a known to be different value as the last step. However timing attacks against a user base are usually better solved by instead stopping repeated attempts as logins as the existence of a login is only valuable if I can brute force the password.
– Guvante
May 27, 2015 at 21:16
 
But what if the attacker has many computers or/and he changes their IP? He might use zombie computers for this purpose as well. May 27, 2015 at 21:21
 
That is why I said for a user, not for a source. Basically if a particular user name fails, remember that that user failed. Either increase the time between attempts or lock the user out eventually. That way knowledge of a user name has a smaller impact on your security.
– Guvante
May 27, 2015 at 21:23
 

 

回答1

The solution is easy, you follow the same code path whether the user exists or not.

public static bool TryLogin(string email, string password)
{
    bool userExists = UserExists(email);

    var hash = GetRealPasswordHash(email);
    var hash2 = GetHash(email, password);
    return SlowEquals(hash, hash2) && userExists;
}

Now you will need to make sure GetRealPasswordHash takes the same amount of time for a valid email and a non valid email and returns a "fake" hash for the non valid email (the "dummy" user's password hash Guvante was referring to in his comment).

This makes sure that GetHash and SlowEquals both still get called with valid data but you ignore their results due to userExists being false.

However I also agree with Guvante on his second point, any normal system will lock the user account after a number of invalid password attempts. This prevents brute force/dictionary attacks against a user's login. You only unlock the lock on the login until after a period of time has passed or the user calls in and verifies their identity.

 

 

 

作者:Chuck Lu    GitHub    
posted @   ChuckLu  阅读(45)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
历史上的今天:
2019-05-24 git分支回退以及目录回退
2019-05-24 6105 - deauth after EAPOL key exchange sequence
2017-05-24 nslookup
点击右上角即可分享
微信分享提示