尝试登录的安全性(防止时间攻击)

时间:2015-05-27 21:06:16

标签: c# .net security hash login

我遇到了一个安全问题。请看下面的伪代码

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);
}

你们中的一些人可能已经看到了这个洞。攻击者可能会通过网络执行时间攻击 - 检测答案返回的速度,并根据检测数据库中是否有用户进行检测!知道了这一点后,攻击者现在可以检查他已经知道存在的用户的各种密码!

如果您没有看到问题或者不相信它是一个问题(这是针对哈希,但类比问题在这里),请解释一下:

  

比较"长度常数"中的哈希值时间确保了   攻击者无法在在线系统中提取密码的哈希值   使用定时攻击,然后将其破解。

     

检查两个字节序列(字符串)的标准方法   同样是比较第一个字节,然后是第二个字节,然后是第三个字节,   等等。一旦找到两个字节都不相同的字节   字符串,你知道它们是不同的,可以返回负数   立即回应。如果你没有通过两个字符串   找到任何不同的字节,你知道字符串是相同的   可以返回一个积极的结果。这意味着比较两个字符串   取决于多少时间可以花费不同的时间   字符串匹配。

     

例如,字符串的标准比较" xyzabc"和   " abcxyz"会马上看到第一个角色是不同的   并且不会费心去检查其余的字符串。在另一   手,当字符串" aaaaaaaaaaB"和" aaaaaaaaaaZ"比较,   比较算法扫描" a"在它之前   确定字符串是不相等的。

     

似乎不可能进行定时攻击   一个网络。但是,它已经完成,并且已经shown to be practical

     

Here you can see the article

当我发现用户不存在时,我该怎么办??我绝对应该进行更多的计算,但这里有什么好的技巧?你们在这种场景中使用了什么?

如果这有任何意义,我正在使用C#。

1 个答案:

答案 0 :(得分:2)

解决方案很简单,无论用户是否存在,都遵循相同的代码路径。

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;
}

现在,您需要确保GetRealPasswordHash花费相同的时间用于有效的电子邮件和无效的电子邮件,并为无效的电子邮件返回“假”哈希(“虚拟”用户的密码哈希Guvante指的是in his comment)。

这可以确保GetHashSlowEquals仍然使用有效数据进行调用,但由于userExists为假,您会忽略其结果。

但是我也同意Guvante的第二点,任何正常的系统都会在尝试多次无效密码后锁定用户帐户。这可以防止对用户登录的暴力/字典攻击。您只能解锁登录锁定,直到一段时间过后或用户呼入并验证其身份。