关于密码:PHP最强的单向加密/散列方法

PHP Strongest one way encryption/hashing method

本问题已经有最佳答案,请猛点这里访问。

我有一个网站,人们可以注册,我需要加密他们的密码。我已经研究过了,但是我找不到任何方法可以不被现代GPU的力量打败。

所以我来问StackOverflow的好人,什么是最强大的加密方法,我已经尽了最大的努力阻止人们接触数据库,但我想尽可能确保如果数据库被偷了,他们的数据会很好。

我想知道的其他事情是,将密码中的字符随机化会更安全吗?但在某种程度上,您可以再次随机化它们以便登录?

编辑:我使用了Andrew Moore的Bcrypt实现(如何使用Bcrypt在PHP中散列密码?)然后想出这个:

1
2
3
4
5
public static function Encrypt($Str,$Salt)
{
    $bcrypt = new \bcrypt();
    return $bcrypt->hash(SERVER_SALT . md5($Str) . $Salt);
}

如果有人发现它有任何问题或弱点,请告诉我。


对于密码,您不能打败bcrypt。这里有一个关于so的链接:如何使用bcrypt在php中散列密码?.它的主要优点:天生速度慢(而且安全)。虽然一个普通的用户会使用它一次,并且不会注意到十分之一秒和百万分之一秒之间的差别,但是一个破解者会发现,他现在需要十二个世纪(除了强迫河豚即使每秒一百万次尝试也不需要四天:除非实施在错误和尚未预见到的加密突破上,宇宙的热死仍将排在第一位)。好的。

对于数据,我将依赖数据库引擎本身;MySQL支持AES,这很好。是的,有了足够的GPU,一个人就可以打败它,而且由于要在本世纪内破解代码,一个人需要大约40亿个GPU,他可能也会得到很好的数量折扣。但我不担心。好的。

至于密码的"随机化",它将毫无用处。如果有人想用暴力破解你的密码,他同样有可能找到随机序列或非随机序列。如果一个人使用字典攻击(也就是说,不是尝试从aaaa到zzz的所有东西,而是尝试亚伯拉罕,手风琴,……)可能会有所帮助。直到,比如,合子)。但是即使这样,对服务器的攻击也不会改变任何东西(服务器接收到非随机密码!)对存储的哈希的攻击最好通过salting来消除,这是bcrypt自动做到的:即存储76x.j美元的哈希,而不是存储MickeyMouse的哈希,以及处理额外输入的76x.j美元所需的开销。虽然随机化必须是固定的,但每写一次,76x.j:序列是完全不同的——祝你好运!好的。腌制

如果您自己实现了salting(如上所示,使用EDOCX1[0]您不需要),您可以通过生成一个唯一的随机序列并将其存储在密码字段或第二个字段中来实现。例如好的。

1
2
user    password
alice   d9c06f88:6c14d6d313d7cbcb132b5c63650682c4

然后,在Alice("MickeyMouse")收到密码后,您将在数据库中查看是否存在名为alice的用户。如果有的话,把盐(这里是d9c06f88)和土豆泥收回来。如果没有,则设置一个"坏"标志并获取一个固定的盐和哈希(例如12345678:0000000...)。好的。

在mysql中,可以使用union来完成:好的。

1
2
3
4
5
6
SELECT password_fields FROM users WHERE user=? AND hash=?
UNION SELECT
    '12345789' as salt,
    'ffffffffffffffffffffffff' as hash,
    'fake' as user
LIMIT 1;

将在大致相同的时间内检索正确的数据或不正确的集合(这可以防止有人猜测哪些名称存在,哪些名称不存在,通过计时回答"错误的用户或密码"所需的时间)。好的。

然后连接salt和密码,生成EDOCX1的散列值(0)。如果不匹配,或者设置了"bad"标志,则拒绝密码(而不是使用"bad"标志,您可以重复MySQL已经进行的用户匹配测试:您可以通过将最后一个字符替换为无效字符来初始化用户名,以确保它永远不会匹配真正的用户)。好的。非信息安全

选择固定字符串的附加扭曲非常有用,因为您希望"用户不存在"、"用户存在但密码不正确"和"用户存在且密码正确"这三种情况尽可能相似(复杂性相同,计算费用相同)。好的。

这样,攻击者就不太可能知道发生了什么:用户是否不正确?密码错误吗?等等。如果时间足够不同(比如对有效用户进行两次查询,对无效用户进行一次查询),则具有谨慎、时间和良好秒表的攻击者可以统计确定给定用户名是否存在。好的。

对于用户,即使名称比较好的。

1
2
 johnsmith     against   johnsmith            if johnsmith exists
 johnsmith     against   johnsmit?            if johnsmith does not exist

因此,说出从HTTP连接的另一端发生的事情并不容易。好的。

出于同样的原因,对于"坏用户"和"坏密码",您不会返回两个不同的错误,而是始终返回一个"坏用户或密码";对于用户,可以选择接收一封发送到他/她的注册电子邮件的电子邮件,以提醒他/她用户名。当然,你希望系统在24小时内不发送类似的电子邮件给同一个用户,以防止系统被利用来用虚假的"恢复电子邮件"骚扰某人。好的。

如果您确实发送了电子邮件,您将等待到预设时间到期(例如,3秒),然后通知用户如果用户名存在,那么他们应该检查其收件箱(以及垃圾邮件文件夹以获得良好的度量)。好的。有一段时间会有这样的密码

提高服务器安全性的一个方便方法是在密码验证上实现延迟,并且(如果您真的很偏执的话)在尝试了X次错误的尝试之后,可能会进行验证码锁定。好的。

您不想在第一次尝试时验证,因为用户对验证码的看法很模糊。好的。

延迟锁定通常使用sleep或等效工具实现,或使用"锁定,直到管理员手动重置"策略。这两种方法都不好。锁定功能可用于创建拒绝服务攻击,方法是锁定用户,或创建许多在"密码验证延迟"状态下停止的服务器线程(它们将不使用CPU,但仍将使用内存、套接字和其他资源)。好的。

在某些情况下,这可能是无意中发生的。似乎有个白痴在使用我的银行,每隔几个月我就会收到一条短信,上面写着"在你的家庭银行系统中输入了错误的密码"。然后我必须从我的手机登录,重置失败的尝试计数器;因为如果白痴没有意识到他不能进入他的帐户,因为他输入了我的帐号,三次,这是我的帐户被锁定,我必须亲自去银行,求他们重置我的访问权限。让我告诉你,这是下一个地区的一大痛苦,即使知道这不是他们的错,我仍然怨恨我的银行。你不想在你的用户中产生这样的感觉。好的。

最好是减轻客户的负担:好的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
(very pseudo code)
login = FAIL
if in SECURITY LOCKOUT MODE for this account
    if a session is open and contains a last-attempt time
        if at least DELAY seconds have elapsed since last-attempt
            check the password
            if it is correct
                login = OK
                zero password counter, exit lockout mode.
                # An"innocent" user enters with no lockout! Yay!
           end
        else
            #"Early knocker". Either a bruteforcing robot
           # or a too clever user in a hurry. But we can't
           # tell them apart.
       end
    else
        # No session. Either a sessionless bruteforcing robot
       # or a unaware, innocent user. Again we can't tell them
       # apart. So we bounce both.

        # But a genuine user will assume he has mistyped the password,
       # or anyway will read the warning page, and will login after ONE
       # round of delay.

        # Users with password saved in browser will just click
       #"login" again and be logged in.

        # A robot will find itself delayed and ALL ITS PASSWORDS IGNORED
       # every single time. Even if it finds the right password... it will
       # not work.
   end
else
    check the password
    if it is correct
        # Good user, first attempt, fast login.
       login = OK
    else
        # Beginning to doubt this is a good user...
       increase password counter
        if it is > MAX_ATTEMPTS
            enter SECURITY LOCKOUT MODE for this account
        end
    end
end
if login is not OK
    generate a page with HTTP_REFRESH time of DELAY+1 seconds
    and a session ID, saying"User or password unknown,
    or you tried to login before HH:MM:SS (DELAY seconds).
    The page might also contain a Javascript timer, just in
    case. The delay is 1s more than necessary as a safety
    margin.
end

好啊。


AES256位加密非常"强大",这意味着它是最新的加密标准之一,很难破解。我读到过,如果你用暴力破解它,你将需要世界上所有的计算能力。

退房:

如何在PHP中进行AES256解密?

还有:

http://en.wikipedia.org/wiki/advanced_encryption_标准http://www.andrew-kirkpatrick.com/2013/01/aes-encryption-with-php-256-bit-using-iv/

希望有帮助。