关于安全性:“双重哈希”密码的安全性是否比仅对其进行一次哈希更安全?

Is “double hashing” a password less secure than just hashing it once?

在存储之前对密码进行两次散列是否比只进行一次散列更安全?

我要说的是这样做:

1
$hashed_password = hash(hash($plaintext_password));

而不仅仅是这个:

1
$hashed_password = hash($plaintext_password);

如果不太安全,您能提供一个很好的解释(或链接到一个)?

另外,使用的哈希函数有什么不同吗?如果混合MD5和SHA1(例如)而不是重复相同的哈希函数,会有什么不同吗?

注1:当我说"双重散列"时,我指的是对密码进行两次散列,以使其更加模糊。我不是在说解决碰撞的技术。

注2:我知道我需要添加一个随机的盐来真正保证它的安全。问题是使用相同算法进行两次散列是否有助于或损害散列。


将密码散列一次是不安全的

不,多个哈希不安全;它们是安全密码使用的重要组成部分。

迭代散列会增加攻击者尝试候选列表中每个密码所需的时间。您可以轻松地将攻击密码的时间从几小时增加到几年。

简单的迭代是不够的

仅仅将哈希输出链接到输入对于安全性来说是不够的。迭代应该在保存密码熵的算法的上下文中进行。幸运的是,有几个已发布的算法经过了足够的仔细研究,对它们的设计充满了信心。

一个好的密钥派生算法(如pbkdf2)将密码注入到每一轮散列中,减少了散列输出中的冲突问题。pbkdf2可以按原样用于密码验证。bcrypt通过加密步骤跟踪密钥派生;这样,如果发现了一种快速的密钥派生方法,攻击者仍然必须完成已知的明文攻击。

如何破解密码

存储的密码需要防止离线攻击。如果密码不加盐,可以通过预先计算好的字典攻击(例如,使用彩虹表)来破解密码。否则,攻击者必须花时间为每个密码计算一个哈希,并查看它是否与存储的哈希匹配。

所有密码的可能性并不相同。攻击者可能会彻底搜索所有短密码,但他们知道,每增加一个字符,暴力破解成功的几率就会急剧下降。相反,他们使用一个有序的密码列表。它们从"密码123"开始,并发展到使用频率较低的密码。

假设一个攻击者列表很长,有100亿个候选对象;假设一个桌面系统每秒可以计算100万个哈希。如果只使用一次迭代,攻击者可以测试她的整个列表少于三个小时。但是,如果只使用2000次迭代,那么时间将延长到几乎8个月。要打败一个更复杂的攻击者,例如,你需要更多的迭代,他能够下载一个能够利用GPU功能的程序。

多少钱足够?

要使用的迭代次数是安全性和用户体验之间的权衡。攻击者可以使用的专用硬件很便宜,但它仍然可以每秒执行数亿次迭代。攻击者系统的性能决定了在给定多次迭代的情况下破解密码需要多长时间。但是您的应用程序不太可能使用这个专门的硬件。在不加重用户负担的情况下,您可以执行多少次迭代取决于您的系统。

在身份验证期间,您可能会让用户多等一秒左右。分析您的目标平台,并使用尽可能多的迭代。我测试过的平台(移动设备上的一个用户,或服务器平台上的许多用户)可以轻松地支持6万到12万次迭代的pbkdf2,或成本系数为12或13的bcrypt。

更多背景

阅读pkcs 5获得关于salt和迭代在哈希中的作用的权威信息。尽管pbkdf2是用来从密码生成加密密钥的,但它作为密码认证的单向散列很好地工作。bcrypt的每次迭代都比sha-2哈希更昂贵,因此您可以使用较少的迭代,但其思想是相同的。Bcrypt还通过使用派生密钥加密众所周知的纯文本,超越了大多数基于PBKdf2的解决方案。生成的密码文本与一些元数据一起存储为"hash"。然而,没有什么能阻止你对pbkdf2做同样的事情。

以下是我在这个主题上写的其他答案:

  • 哈希密码
  • 哈希密码
  • 藏盐
  • PBKdf2与BCRYPT
  • 跨平台文件加密工具


对于那些说这是安全的人来说,他们大体上是正确的。"Double"散列(或其逻辑扩展,迭代散列函数)对于特定问题来说,如果操作正确,是绝对安全的。好的。

对于那些说这不安全的人来说,在这种情况下他们是正确的。在问题中发布的代码是不安全的。我们来谈谈原因:好的。

1
2
$hashed_password1 = md5( md5( plaintext_password ) );
$hashed_password2 = md5( plaintext_password );

哈希函数有两个基本属性,我们关注的是:好的。

  • 图像前阻力-考虑到hash $h,很难找到消息$m,因此$h === hash($m)好的。

  • 第二个图像前阻力-给定消息$m1,很难找到不同的消息$m2,这样hash($m1) === hash($m2)好的。

  • 抗碰撞-应该很难找到一对消息($m1, $m2),以便hash($m1) === hash($m2)(请注意,这类似于第二个图像前抵抗,但在这里不同的是,攻击者可以控制这两个消息)。好的。

  • 对于密码的存储,我们真正关心的是预映像电阻。另外两个是没有意义的,因为$m1是我们试图保护安全的用户密码。所以,如果攻击者已经拥有了它,哈希就没有什么可保护的了…好的。免责声明

    接下来的一切都是基于这样一个前提,即我们所关心的只是图像前的阻力。散列函数的其他两个基本属性可能(通常不会)不能以相同的方式容纳。因此,本文的结论仅适用于使用哈希函数存储密码的情况。它们一般不适用于……好的。我们开始吧

    为了讨论这个问题,让我们发明我们自己的哈希函数:好的。

    1
    2
    3
    4
    5
    6
    7
    function ourHash($input) {
        $result = 0;
        for ($i = 0; $i < strlen($input); $i++) {
            $result += ord($input[$i]);
        }
        return (string) ($result % 256);
    }

    现在应该很明显这个散列函数做了什么。它将输入的每个字符的ASCII值相加,然后将结果的模取为256。好的。

    让我们来测试一下:好的。

    1
    2
    3
    4
    5
    6
    var_dump(
        ourHash('abc'), // string(2)"38"
        ourHash('def'), // string(2)"47"
        ourHash('hij'), // string(2)"59"
        ourHash('klm')  // string(2)"68"
    );

    现在,让我们看看在函数周围运行几次会发生什么:好的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    $tests = array(
       "abc",
       "def",
       "hij",
       "klm",
    );

    foreach ($tests as $test) {
        $hash = $test;
        for ($i = 0; $i < 100; $i++) {
            $hash = ourHash($hash);
        }
        echo"Hashing $test => $hash
    ";
    }

    输出:好的。

    1
    2
    3
    4
    Hashing abc => 152
    Hashing def => 152
    Hashing hij => 155
    Hashing klm => 155

    人力资源管理,哇。我们产生了碰撞!!!!我们来看看原因:好的。

    下面是散列的输出,每个可能的散列输出都有一个字符串:好的。

    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
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    Hashing 0 => 48
    Hashing 1 => 49
    Hashing 2 => 50
    Hashing 3 => 51
    Hashing 4 => 52
    Hashing 5 => 53
    Hashing 6 => 54
    Hashing 7 => 55
    Hashing 8 => 56
    Hashing 9 => 57
    Hashing 10 => 97
    Hashing 11 => 98
    Hashing 12 => 99
    Hashing 13 => 100
    Hashing 14 => 101
    Hashing 15 => 102
    Hashing 16 => 103
    Hashing 17 => 104
    Hashing 18 => 105
    Hashing 19 => 106
    Hashing 20 => 98
    Hashing 21 => 99
    Hashing 22 => 100
    Hashing 23 => 101
    Hashing 24 => 102
    Hashing 25 => 103
    Hashing 26 => 104
    Hashing 27 => 105
    Hashing 28 => 106
    Hashing 29 => 107
    Hashing 30 => 99
    Hashing 31 => 100
    Hashing 32 => 101
    Hashing 33 => 102
    Hashing 34 => 103
    Hashing 35 => 104
    Hashing 36 => 105
    Hashing 37 => 106
    Hashing 38 => 107
    Hashing 39 => 108
    Hashing 40 => 100
    Hashing 41 => 101
    Hashing 42 => 102
    Hashing 43 => 103
    Hashing 44 => 104
    Hashing 45 => 105
    Hashing 46 => 106
    Hashing 47 => 107
    Hashing 48 => 108
    Hashing 49 => 109
    Hashing 50 => 101
    Hashing 51 => 102
    Hashing 52 => 103
    Hashing 53 => 104
    Hashing 54 => 105
    Hashing 55 => 106
    Hashing 56 => 107
    Hashing 57 => 108
    Hashing 58 => 109
    Hashing 59 => 110
    Hashing 60 => 102
    Hashing 61 => 103
    Hashing 62 => 104
    Hashing 63 => 105
    Hashing 64 => 106
    Hashing 65 => 107
    Hashing 66 => 108
    Hashing 67 => 109
    Hashing 68 => 110
    Hashing 69 => 111
    Hashing 70 => 103
    Hashing 71 => 104
    Hashing 72 => 105
    Hashing 73 => 106
    Hashing 74 => 107
    Hashing 75 => 108
    Hashing 76 => 109
    Hashing 77 => 110
    Hashing 78 => 111
    Hashing 79 => 112
    Hashing 80 => 104
    Hashing 81 => 105
    Hashing 82 => 106
    Hashing 83 => 107
    Hashing 84 => 108
    Hashing 85 => 109
    Hashing 86 => 110
    Hashing 87 => 111
    Hashing 88 => 112
    Hashing 89 => 113
    Hashing 90 => 105
    Hashing 91 => 106
    Hashing 92 => 107
    Hashing 93 => 108
    Hashing 94 => 109
    Hashing 95 => 110
    Hashing 96 => 111
    Hashing 97 => 112
    Hashing 98 => 113
    Hashing 99 => 114
    Hashing 100 => 145
    Hashing 101 => 146
    Hashing 102 => 147
    Hashing 103 => 148
    Hashing 104 => 149
    Hashing 105 => 150
    Hashing 106 => 151
    Hashing 107 => 152
    Hashing 108 => 153
    Hashing 109 => 154
    Hashing 110 => 146
    Hashing 111 => 147
    Hashing 112 => 148
    Hashing 113 => 149
    Hashing 114 => 150
    Hashing 115 => 151
    Hashing 116 => 152
    Hashing 117 => 153
    Hashing 118 => 154
    Hashing 119 => 155
    Hashing 120 => 147
    Hashing 121 => 148
    Hashing 122 => 149
    Hashing 123 => 150
    Hashing 124 => 151
    Hashing 125 => 152
    Hashing 126 => 153
    Hashing 127 => 154
    Hashing 128 => 155
    Hashing 129 => 156
    Hashing 130 => 148
    Hashing 131 => 149
    Hashing 132 => 150
    Hashing 133 => 151
    Hashing 134 => 152
    Hashing 135 => 153
    Hashing 136 => 154
    Hashing 137 => 155
    Hashing 138 => 156
    Hashing 139 => 157
    Hashing 140 => 149
    Hashing 141 => 150
    Hashing 142 => 151
    Hashing 143 => 152
    Hashing 144 => 153
    Hashing 145 => 154
    Hashing 146 => 155
    Hashing 147 => 156
    Hashing 148 => 157
    Hashing 149 => 158
    Hashing 150 => 150
    Hashing 151 => 151
    Hashing 152 => 152
    Hashing 153 => 153
    Hashing 154 => 154
    Hashing 155 => 155
    Hashing 156 => 156
    Hashing 157 => 157
    Hashing 158 => 158
    Hashing 159 => 159
    Hashing 160 => 151
    Hashing 161 => 152
    Hashing 162 => 153
    Hashing 163 => 154
    Hashing 164 => 155
    Hashing 165 => 156
    Hashing 166 => 157
    Hashing 167 => 158
    Hashing 168 => 159
    Hashing 169 => 160
    Hashing 170 => 152
    Hashing 171 => 153
    Hashing 172 => 154
    Hashing 173 => 155
    Hashing 174 => 156
    Hashing 175 => 157
    Hashing 176 => 158
    Hashing 177 => 159
    Hashing 178 => 160
    Hashing 179 => 161
    Hashing 180 => 153
    Hashing 181 => 154
    Hashing 182 => 155
    Hashing 183 => 156
    Hashing 184 => 157
    Hashing 185 => 158
    Hashing 186 => 159
    Hashing 187 => 160
    Hashing 188 => 161
    Hashing 189 => 162
    Hashing 190 => 154
    Hashing 191 => 155
    Hashing 192 => 156
    Hashing 193 => 157
    Hashing 194 => 158
    Hashing 195 => 159
    Hashing 196 => 160
    Hashing 197 => 161
    Hashing 198 => 162
    Hashing 199 => 163
    Hashing 200 => 146
    Hashing 201 => 147
    Hashing 202 => 148
    Hashing 203 => 149
    Hashing 204 => 150
    Hashing 205 => 151
    Hashing 206 => 152
    Hashing 207 => 153
    Hashing 208 => 154
    Hashing 209 => 155
    Hashing 210 => 147
    Hashing 211 => 148
    Hashing 212 => 149
    Hashing 213 => 150
    Hashing 214 => 151
    Hashing 215 => 152
    Hashing 216 => 153
    Hashing 217 => 154
    Hashing 218 => 155
    Hashing 219 => 156
    Hashing 220 => 148
    Hashing 221 => 149
    Hashing 222 => 150
    Hashing 223 => 151
    Hashing 224 => 152
    Hashing 225 => 153
    Hashing 226 => 154
    Hashing 227 => 155
    Hashing 228 => 156
    Hashing 229 => 157
    Hashing 230 => 149
    Hashing 231 => 150
    Hashing 232 => 151
    Hashing 233 => 152
    Hashing 234 => 153
    Hashing 235 => 154
    Hashing 236 => 155
    Hashing 237 => 156
    Hashing 238 => 157
    Hashing 239 => 158
    Hashing 240 => 150
    Hashing 241 => 151
    Hashing 242 => 152
    Hashing 243 => 153
    Hashing 244 => 154
    Hashing 245 => 155
    Hashing 246 => 156
    Hashing 247 => 157
    Hashing 248 => 158
    Hashing 249 => 159
    Hashing 250 => 151
    Hashing 251 => 152
    Hashing 252 => 153
    Hashing 253 => 154
    Hashing 254 => 155
    Hashing 255 => 156

    注意数字越大的趋势。原来那是我们的死胡同。运行hash 4次($hash=ourhash($hash)`,对于每个元素),最终得到:好的。

    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
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    Hashing 0 => 153
    Hashing 1 => 154
    Hashing 2 => 155
    Hashing 3 => 156
    Hashing 4 => 157
    Hashing 5 => 158
    Hashing 6 => 150
    Hashing 7 => 151
    Hashing 8 => 152
    Hashing 9 => 153
    Hashing 10 => 157
    Hashing 11 => 158
    Hashing 12 => 150
    Hashing 13 => 154
    Hashing 14 => 155
    Hashing 15 => 156
    Hashing 16 => 157
    Hashing 17 => 158
    Hashing 18 => 150
    Hashing 19 => 151
    Hashing 20 => 158
    Hashing 21 => 150
    Hashing 22 => 154
    Hashing 23 => 155
    Hashing 24 => 156
    Hashing 25 => 157
    Hashing 26 => 158
    Hashing 27 => 150
    Hashing 28 => 151
    Hashing 29 => 152
    Hashing 30 => 150
    Hashing 31 => 154
    Hashing 32 => 155
    Hashing 33 => 156
    Hashing 34 => 157
    Hashing 35 => 158
    Hashing 36 => 150
    Hashing 37 => 151
    Hashing 38 => 152
    Hashing 39 => 153
    Hashing 40 => 154
    Hashing 41 => 155
    Hashing 42 => 156
    Hashing 43 => 157
    Hashing 44 => 158
    Hashing 45 => 150
    Hashing 46 => 151
    Hashing 47 => 152
    Hashing 48 => 153
    Hashing 49 => 154
    Hashing 50 => 155
    Hashing 51 => 156
    Hashing 52 => 157
    Hashing 53 => 158
    Hashing 54 => 150
    Hashing 55 => 151
    Hashing 56 => 152
    Hashing 57 => 153
    Hashing 58 => 154
    Hashing 59 => 155
    Hashing 60 => 156
    Hashing 61 => 157
    Hashing 62 => 158
    Hashing 63 => 150
    Hashing 64 => 151
    Hashing 65 => 152
    Hashing 66 => 153
    Hashing 67 => 154
    Hashing 68 => 155
    Hashing 69 => 156
    Hashing 70 => 157
    Hashing 71 => 158
    Hashing 72 => 150
    Hashing 73 => 151
    Hashing 74 => 152
    Hashing 75 => 153
    Hashing 76 => 154
    Hashing 77 => 155
    Hashing 78 => 156
    Hashing 79 => 157
    Hashing 80 => 158
    Hashing 81 => 150
    Hashing 82 => 151
    Hashing 83 => 152
    Hashing 84 => 153
    Hashing 85 => 154
    Hashing 86 => 155
    Hashing 87 => 156
    Hashing 88 => 157
    Hashing 89 => 158
    Hashing 90 => 150
    Hashing 91 => 151
    Hashing 92 => 152
    Hashing 93 => 153
    Hashing 94 => 154
    Hashing 95 => 155
    Hashing 96 => 156
    Hashing 97 => 157
    Hashing 98 => 158
    Hashing 99 => 150
    Hashing 100 => 154
    Hashing 101 => 155
    Hashing 102 => 156
    Hashing 103 => 157
    Hashing 104 => 158
    Hashing 105 => 150
    Hashing 106 => 151
    Hashing 107 => 152
    Hashing 108 => 153
    Hashing 109 => 154
    Hashing 110 => 155
    Hashing 111 => 156
    Hashing 112 => 157
    Hashing 113 => 158
    Hashing 114 => 150
    Hashing 115 => 151
    Hashing 116 => 152
    Hashing 117 => 153
    Hashing 118 => 154
    Hashing 119 => 155
    Hashing 120 => 156
    Hashing 121 => 157
    Hashing 122 => 158
    Hashing 123 => 150
    Hashing 124 => 151
    Hashing 125 => 152
    Hashing 126 => 153
    Hashing 127 => 154
    Hashing 128 => 155
    Hashing 129 => 156
    Hashing 130 => 157
    Hashing 131 => 158
    Hashing 132 => 150
    Hashing 133 => 151
    Hashing 134 => 152
    Hashing 135 => 153
    Hashing 136 => 154
    Hashing 137 => 155
    Hashing 138 => 156
    Hashing 139 => 157
    Hashing 140 => 158
    Hashing 141 => 150
    Hashing 142 => 151
    Hashing 143 => 152
    Hashing 144 => 153
    Hashing 145 => 154
    Hashing 146 => 155
    Hashing 147 => 156
    Hashing 148 => 157
    Hashing 149 => 158
    Hashing 150 => 150
    Hashing 151 => 151
    Hashing 152 => 152
    Hashing 153 => 153
    Hashing 154 => 154
    Hashing 155 => 155
    Hashing 156 => 156
    Hashing 157 => 157
    Hashing 158 => 158
    Hashing 159 => 159
    Hashing 160 => 151
    Hashing 161 => 152
    Hashing 162 => 153
    Hashing 163 => 154
    Hashing 164 => 155
    Hashing 165 => 156
    Hashing 166 => 157
    Hashing 167 => 158
    Hashing 168 => 159
    Hashing 169 => 151
    Hashing 170 => 152
    Hashing 171 => 153
    Hashing 172 => 154
    Hashing 173 => 155
    Hashing 174 => 156
    Hashing 175 => 157
    Hashing 176 => 158
    Hashing 177 => 159
    Hashing 178 => 151
    Hashing 179 => 152
    Hashing 180 => 153
    Hashing 181 => 154
    Hashing 182 => 155
    Hashing 183 => 156
    Hashing 184 => 157
    Hashing 185 => 158
    Hashing 186 => 159
    Hashing 187 => 151
    Hashing 188 => 152
    Hashing 189 => 153
    Hashing 190 => 154
    Hashing 191 => 155
    Hashing 192 => 156
    Hashing 193 => 157
    Hashing 194 => 158
    Hashing 195 => 159
    Hashing 196 => 151
    Hashing 197 => 152
    Hashing 198 => 153
    Hashing 199 => 154
    Hashing 200 => 155
    Hashing 201 => 156
    Hashing 202 => 157
    Hashing 203 => 158
    Hashing 204 => 150
    Hashing 205 => 151
    Hashing 206 => 152
    Hashing 207 => 153
    Hashing 208 => 154
    Hashing 209 => 155
    Hashing 210 => 156
    Hashing 211 => 157
    Hashing 212 => 158
    Hashing 213 => 150
    Hashing 214 => 151
    Hashing 215 => 152
    Hashing 216 => 153
    Hashing 217 => 154
    Hashing 218 => 155
    Hashing 219 => 156
    Hashing 220 => 157
    Hashing 221 => 158
    Hashing 222 => 150
    Hashing 223 => 151
    Hashing 224 => 152
    Hashing 225 => 153
    Hashing 226 => 154
    Hashing 227 => 155
    Hashing 228 => 156
    Hashing 229 => 157
    Hashing 230 => 158
    Hashing 231 => 150
    Hashing 232 => 151
    Hashing 233 => 152
    Hashing 234 => 153
    Hashing 235 => 154
    Hashing 236 => 155
    Hashing 237 => 156
    Hashing 238 => 157
    Hashing 239 => 158
    Hashing 240 => 150
    Hashing 241 => 151
    Hashing 242 => 152
    Hashing 243 => 153
    Hashing 244 => 154
    Hashing 245 => 155
    Hashing 246 => 156
    Hashing 247 => 157
    Hashing 248 => 158
    Hashing 249 => 159
    Hashing 250 => 151
    Hashing 251 => 152
    Hashing 252 => 153
    Hashing 253 => 154
    Hashing 254 => 155
    Hashing 255 => 156

    我们把自己缩小到8个值…那太糟糕了…我们的原始函数将S(∞)映射到S(256)上。也就是说,我们创建了一个surjective函数,将$input映射到$output。好的。

    因为我们有一个Surjective函数,所以我们不能保证任何输入子集的映射都不会发生冲突(实际上,在实践中,它们会发生冲突)。好的。

    这就是这里发生的事!我们的功能不好,但这并不是为什么它起作用(这就是为什么它起作用如此迅速和彻底)。好的。

    同样的事情也发生在MD5上。它把S(∞)映射到S(2^128)上。因为无法保证运行MD5(S(output))是注入的,这意味着它不会发生碰撞。好的。TL/DR截面

    因此,由于将输出反馈回MD5可以直接生成冲突,因此每次迭代都会增加发生冲突的机会。然而,这是一个线性增长,这意味着虽然2^128的结果集减少了,但其减少速度不足以成为一个关键缺陷。好的。

    所以,好的。

    1
    2
    3
    4
    5
    $output = md5($input); // 2^128 possibilities
    $output = md5($output); // < 2^128 possibilities
    $output = md5($output); // < 2^128 possibilities
    $output = md5($output); // < 2^128 possibilities
    $output = md5($output); // < 2^128 possibilities

    迭代次数越多,缩减就越大。好的。修复

    幸运的是,有一种简单的方法可以解决这个问题:将一些东西反馈到进一步的迭代中:好的。

    1
    2
    3
    4
    5
    $output = md5($input); // 2^128 possibilities
    $output = md5($input . $output); // 2^128 possibilities
    $output = md5($input . $output); // 2^128 possibilities
    $output = md5($input . $output); // 2^128 possibilities
    $output = md5($input . $output); // 2^128 possibilities

    注意,对于$input的每个单独值,进一步的迭代不是2^128。也就是说,我们可能能够生成仍然与线发生冲突的$input值(因此将在远小于2^128可能输出的情况下稳定或共振)。但是,对于江户一号(6号)来说,一般情况下的情况仍然和单轮一样强烈。好的。

    等等,是吗?让我们用我们的ourHash()函数来测试这个问题。切换到$hash = ourHash($input . $hash);,进行100次迭代:好的。

    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
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    Hashing 0 => 201
    Hashing 1 => 212
    Hashing 2 => 199
    Hashing 3 => 201
    Hashing 4 => 203
    Hashing 5 => 205
    Hashing 6 => 207
    Hashing 7 => 209
    Hashing 8 => 211
    Hashing 9 => 204
    Hashing 10 => 251
    Hashing 11 => 147
    Hashing 12 => 251
    Hashing 13 => 148
    Hashing 14 => 253
    Hashing 15 => 0
    Hashing 16 => 1
    Hashing 17 => 2
    Hashing 18 => 161
    Hashing 19 => 163
    Hashing 20 => 147
    Hashing 21 => 251
    Hashing 22 => 148
    Hashing 23 => 253
    Hashing 24 => 0
    Hashing 25 => 1
    Hashing 26 => 2
    Hashing 27 => 161
    Hashing 28 => 163
    Hashing 29 => 8
    Hashing 30 => 251
    Hashing 31 => 148
    Hashing 32 => 253
    Hashing 33 => 0
    Hashing 34 => 1
    Hashing 35 => 2
    Hashing 36 => 161
    Hashing 37 => 163
    Hashing 38 => 8
    Hashing 39 => 4
    Hashing 40 => 148
    Hashing 41 => 253
    Hashing 42 => 0
    Hashing 43 => 1
    Hashing 44 => 2
    Hashing 45 => 161
    Hashing 46 => 163
    Hashing 47 => 8
    Hashing 48 => 4
    Hashing 49 => 9
    Hashing 50 => 253
    Hashing 51 => 0
    Hashing 52 => 1
    Hashing 53 => 2
    Hashing 54 => 161
    Hashing 55 => 163
    Hashing 56 => 8
    Hashing 57 => 4
    Hashing 58 => 9
    Hashing 59 => 11
    Hashing 60 => 0
    Hashing 61 => 1
    Hashing 62 => 2
    Hashing 63 => 161
    Hashing 64 => 163
    Hashing 65 => 8
    Hashing 66 => 4
    Hashing 67 => 9
    Hashing 68 => 11
    Hashing 69 => 4
    Hashing 70 => 1
    Hashing 71 => 2
    Hashing 72 => 161
    Hashing 73 => 163
    Hashing 74 => 8
    Hashing 75 => 4
    Hashing 76 => 9
    Hashing 77 => 11
    Hashing 78 => 4
    Hashing 79 => 3
    Hashing 80 => 2
    Hashing 81 => 161
    Hashing 82 => 163
    Hashing 83 => 8
    Hashing 84 => 4
    Hashing 85 => 9
    Hashing 86 => 11
    Hashing 87 => 4
    Hashing 88 => 3
    Hashing 89 => 17
    Hashing 90 => 161
    Hashing 91 => 163
    Hashing 92 => 8
    Hashing 93 => 4
    Hashing 94 => 9
    Hashing 95 => 11
    Hashing 96 => 4
    Hashing 97 => 3
    Hashing 98 => 17
    Hashing 99 => 13
    Hashing 100 => 246
    Hashing 101 => 248
    Hashing 102 => 49
    Hashing 103 => 44
    Hashing 104 => 255
    Hashing 105 => 198
    Hashing 106 => 43
    Hashing 107 => 51
    Hashing 108 => 202
    Hashing 109 => 2
    Hashing 110 => 248
    Hashing 111 => 49
    Hashing 112 => 44
    Hashing 113 => 255
    Hashing 114 => 198
    Hashing 115 => 43
    Hashing 116 => 51
    Hashing 117 => 202
    Hashing 118 => 2
    Hashing 119 => 51
    Hashing 120 => 49
    Hashing 121 => 44
    Hashing 122 => 255
    Hashing 123 => 198
    Hashing 124 => 43
    Hashing 125 => 51
    Hashing 126 => 202
    Hashing 127 => 2
    Hashing 128 => 51
    Hashing 129 => 53
    Hashing 130 => 44
    Hashing 131 => 255
    Hashing 132 => 198
    Hashing 133 => 43
    Hashing 134 => 51
    Hashing 135 => 202
    Hashing 136 => 2
    Hashing 137 => 51
    Hashing 138 => 53
    Hashing 139 => 55
    Hashing 140 => 255
    Hashing 141 => 198
    Hashing 142 => 43
    Hashing 143 => 51
    Hashing 144 => 202
    Hashing 145 => 2
    Hashing 146 => 51
    Hashing 147 => 53
    Hashing 148 => 55
    Hashing 149 => 58
    Hashing 150 => 198
    Hashing 151 => 43
    Hashing 152 => 51
    Hashing 153 => 202
    Hashing 154 => 2
    Hashing 155 => 51
    Hashing 156 => 53
    Hashing 157 => 55
    Hashing 158 => 58
    Hashing 159 => 0
    Hashing 160 => 43
    Hashing 161 => 51
    Hashing 162 => 202
    Hashing 163 => 2
    Hashing 164 => 51
    Hashing 165 => 53
    Hashing 166 => 55
    Hashing 167 => 58
    Hashing 168 => 0
    Hashing 169 => 209
    Hashing 170 => 51
    Hashing 171 => 202
    Hashing 172 => 2
    Hashing 173 => 51
    Hashing 174 => 53
    Hashing 175 => 55
    Hashing 176 => 58
    Hashing 177 => 0
    Hashing 178 => 209
    Hashing 179 => 216
    Hashing 180 => 202
    Hashing 181 => 2
    Hashing 182 => 51
    Hashing 183 => 53
    Hashing 184 => 55
    Hashing 185 => 58
    Hashing 186 => 0
    Hashing 187 => 209
    Hashing 188 => 216
    Hashing 189 => 219
    Hashing 190 => 2
    Hashing 191 => 51
    Hashing 192 => 53
    Hashing 193 => 55
    Hashing 194 => 58
    Hashing 195 => 0
    Hashing 196 => 209
    Hashing 197 => 216
    Hashing 198 => 219
    Hashing 199 => 220
    Hashing 200 => 248
    Hashing 201 => 49
    Hashing 202 => 44
    Hashing 203 => 255
    Hashing 204 => 198
    Hashing 205 => 43
    Hashing 206 => 51
    Hashing 207 => 202
    Hashing 208 => 2
    Hashing 209 => 51
    Hashing 210 => 49
    Hashing 211 => 44
    Hashing 212 => 255
    Hashing 213 => 198
    Hashing 214 => 43
    Hashing 215 => 51
    Hashing 216 => 202
    Hashing 217 => 2
    Hashing 218 => 51
    Hashing 219 => 53
    Hashing 220 => 44
    Hashing 221 => 255
    Hashing 222 => 198
    Hashing 223 => 43
    Hashing 224 => 51
    Hashing 225 => 202
    Hashing 226 => 2
    Hashing 227 => 51
    Hashing 228 => 53
    Hashing 229 => 55
    Hashing 230 => 255
    Hashing 231 => 198
    Hashing 232 => 43
    Hashing 233 => 51
    Hashing 234 => 202
    Hashing 235 => 2
    Hashing 236 => 51
    Hashing 237 => 53
    Hashing 238 => 55
    Hashing 239 => 58
    Hashing 240 => 198
    Hashing 241 => 43
    Hashing 242 => 51
    Hashing 243 => 202
    Hashing 244 => 2
    Hashing 245 => 51
    Hashing 246 => 53
    Hashing 247 => 55
    Hashing 248 => 58
    Hashing 249 => 0
    Hashing 250 => 43
    Hashing 251 => 51
    Hashing 252 => 202
    Hashing 253 => 2
    Hashing 254 => 51
    Hashing 255 => 53

    这里仍然有一个粗略的模式,但是请注意,它只是一个模式,而不是我们的底层函数(它已经很弱了)。好的。

    然而,注意到03成了碰撞,即使它们不是在单次运行中。这是我之前所说的应用程序(所有输入集的碰撞阻力保持不变,但由于底层算法的缺陷,特定的碰撞路径可能会打开)。好的。TL/DR截面

    通过将输入反馈到每个迭代中,我们可以有效地打破先前迭代中可能发生的任何冲突。好的。

    因此,md5($input . md5($input));应该(理论上至少)和md5($input)一样强。好的。这很重要吗?

    对。这是在RFC2898中PBKDF2取代PBKDF1的原因之一。考虑这两个循环的内部循环:好的。

    PBKDF1:好的。

    1
    2
    3
    4
    T_1 = Hash (P || S) ,
    T_2 = Hash (T_1) ,
    ...
    T_c = Hash (T_{c-1})

    其中c为迭代次数,P为密码,S为盐好的。

    PBKDF2:好的。

    1
    2
    3
    4
    U_1 = PRF (P, S || INT (i)) ,
    U_2 = PRF (P, U_1) ,
    ...
    U_c = PRF (P, U_{c-1})

    其中,prf实际上只是一个hmac。但就我们这里的目的而言,我们只需说PRF(P, S) = Hash(P || S)(也就是说,2个输入的prf与hash相同,大致上是两个输入连接在一起)。这不是很重要,但为了我们的目的。好的。

    因此,pbkdf2保持了底层Hash函数的抗碰撞性,而pbkdf1没有。好的。把所有的都绑在一起:

    我们知道迭代哈希的安全方法。事实上:好的。

    1
    2
    3
    4
    5
    $hash = $input;
    $i = 10000;
    do {
       $hash = hash($input . $hash);
    } while ($i-- > 0);

    通常是安全的。好的。

    现在,为了探究我们为什么要散列它,让我们分析一下熵的运动。好的。

    散列接受无限集:S(∞)并生成较小的、大小一致的集合S(n)。下一次迭代(假设输入返回)再次将S(∞)映射到S(n)上:好的。

    1
    2
    3
    4
    5
    6
    S(∞) -> S(n)
    S(∞) -> S(n)
    S(∞) -> S(n)
    S(∞) -> S(n)
    S(∞) -> S(n)
    S(∞) -> S(n)

    请注意,最终的输出与第一个输出具有完全相同的熵量。迭代不会"使其更加模糊"。熵是相同的。不可预测性没有神奇的来源(它是一个伪随机函数,而不是一个随机函数)。好的。

    然而,迭代是有好处的。它使哈希过程人为地变慢。这就是为什么迭代是个好主意。事实上,这是大多数现代密码散列算法的基本原理(反复做一些事情会使其变慢)。好的。

    Slow很好,因为它正在对抗主要的安全威胁:暴力强迫。我们的哈希算法越慢,攻击者就越难攻击从我们这里窃取的密码哈希。这是件好事!!!!好的。好啊。


    是的,重新散列会减少搜索空间,但是不,这并不重要-有效的减少是微不足道的。

    重新散列会增加暴力所需的时间,但这样做只有两次也是次优。

    您真正想要的是使用pbkdf2散列密码——一种通过salt和迭代使用安全散列的成熟方法。看看这个回复。

    编辑:我差点忘了-不要用MD5!!!!!使用现代加密哈希,如sha-2系列(sha-256、sha-384和sha-512)。


    是-它减少了与字符串匹配的可能字符串的数量。

    正如你已经提到过的,腌制的哈希更好。

    这里有一篇文章:http://websecurity.ro/blog/2007/11/02/md5 md5-vs-md5/,试图证明为什么它是等效的,但我不确定其逻辑。部分地,他们假设没有可用于分析MD5(MD5(文本))的软件,但显然,生成彩虹表是相当简单的。

    我仍然坚持我的答案,即MD5(MD5(TEXT))类型散列的数量比MD5(TEXT)散列的数量少,从而增加了冲突的可能性(即使仍然是不太可能发生的概率),并减少了搜索空间。


    大多数答案是由没有密码或安全背景的人提供的。他们错了。如果可能,使用每个记录唯一的盐。MD5/SHA/ETC速度太快,与您想要的相反。pbkdf2和bcrypt速度较慢(wich很好),但可以用asics/fpga/gpus(现在非常适合)打败它们。所以需要一个内存硬算法:输入scrypt。

    这里有一个关于盐和速度的外行解释(但不是关于记忆硬算法)。


    我只是从实际的角度来看。黑客在找什么?为什么,当通过哈希函数时,字符组合会生成所需的哈希。

    您只保存最后一个哈希,因此,黑客只需对一个哈希进行残暴处理。假设您在每一个BruteForce步骤中遇到所需哈希的几率大致相同,那么哈希的数量是不相关的。您可以进行一百万次哈希迭代,并且不会将安全性提高或降低一点,因为在行尾仍然只有一个哈希需要中断,中断它的几率与任何哈希相同。

    也许之前的海报认为输入是相关的,而不是。只要您放入哈希函数中的任何内容生成所需的哈希,它就会帮助您通过、更正输入或不正确的输入。

    现在,彩虹桌是另一回事了。由于彩虹表只携带原始密码,哈希两次可能是一个很好的安全措施,因为包含每个哈希的每个哈希的彩虹表都太大了。

    当然,我只是在考虑OP给出的示例,其中只是一个简单的文本密码被散列。如果您在散列中包含用户名或salt,则情况就不同了;完全不需要散列两次,因为彩虹表已经太大,不实用,并且包含正确的散列。

    不管怎样,这里不是安全专家,但这正是我从经验中发现的。


    根据我读到的内容,实际上可能会建议将密码重新散列成百上千次。

    其思想是,如果你能让密码编码花费更多的时间,攻击者就可以通过许多猜测破解密码。这似乎是重新散列的优势——不是它在密码学上更安全,而是生成字典攻击只需要更长的时间。

    当然,计算机一直在变快,所以这种优势随着时间的推移而减弱(或者需要你增加迭代次数)。


    假设您使用哈希算法:计算rot13,取前10个字符。如果你这样做两次(甚至是2000次),你就可以得到一个更快的函数,但得到相同的结果(即只取前10个字符)。

    同样,也可以生成一个更快的函数,该函数提供与重复散列函数相同的输出。因此,您对散列函数的选择非常重要:正如rot13示例所示,没有给出重复散列将提高安全性。如果没有研究表明该算法是为递归使用而设计的,那么假设它不会给您增加保护就更安全了。

    这就是说:除了最简单的散列函数外,所有的散列函数都很可能需要密码专家来计算更快的函数,因此,如果您要防范无法访问密码专家的攻击者,那么在实践中使用重复散列函数可能更安全。


    就个人而言,我不会费心处理多个散列,但我会确保同时散列用户名(或另一个用户ID字段)和密码,这样具有相同密码的两个用户就不会得到相同的散列。另外,为了更好的度量,我可能还会向输入字符串中抛出一些其他常量字符串。

    1
    $hashed_password = md5("xxx" +"|" + user_name +"|" + plaintext_password);


    只有当我在客户机上散列密码,然后在服务器上保存散列(使用不同的salt)时,双重散列才对我有意义。

    这样即使有人入侵服务器(从而忽略了SSL提供的安全性),他仍然无法获得清晰的密码。

    是的,他将拥有侵入系统所需的数据,但他无法使用这些数据来危害用户拥有的外部帐户。众所周知,人们几乎对任何事情都使用相同的密码。

    他唯一能得到清晰密码的方法就是在客户机上安装一个keygen——这不再是你的问题了。

    简而言之:

  • 客户机上的第一个散列在"服务器破坏"场景中保护您的用户。
  • 服务器上的第二个散列用于在有人持有数据库备份时保护您的系统,因此他无法使用这些密码连接到您的服务。

  • 一般来说,它不提供双重哈希或双重加密的额外安全性。如果你能把散列值打碎一次,你就可以把它再打碎一次。但这样做通常不会损害安全。

    在使用MD5的示例中,您可能知道存在一些冲突问题。"double hash"并不能真正帮助防止这种情况,因为相同的冲突仍然会导致相同的第一个哈希,然后您可以再次使用md5来获取第二个哈希。

    这可以防止字典攻击,比如那些"反向MD5数据库",但是Salting也可以。

    相切地说,双重加密并不能提供任何额外的安全性,因为它所做的只是生成一个不同的密钥,这是实际使用的两个密钥的组合。因此,找到"钥匙"的努力并没有翻倍,因为实际上不需要找到两个钥匙。对于散列来说这不是真的,因为散列的结果通常与原始输入的长度不同。


    正如本文中的一些响应所表明的,在某些情况下,它可能会提高安全性,而在其他情况下,它确实会伤害安全性。有一个更好的解决方案,将绝对提高安全性。不是将计算哈希的次数加倍,而是将盐的大小加倍,或者将哈希中使用的位数加倍,或者两者兼而有之!跳到sha-512而不是sha-245。


    减少搜索空间的问题在数学上是正确的,尽管搜索空间仍然足够大,可以满足所有实际用途(假设您使用盐),即2^128。但是,根据信封背面的计算,由于我们讨论的是密码,可能的16个字符串(字母数字、大写字母、几个符号)的数量大约是2^98。因此,在搜索空间中感知到的减少并不真正相关。

    除此之外,从密码学上讲,确实没有区别。

    尽管有一个称为"散列链"的加密原语,这是一种允许你做一些很酷的技巧的技术,比如在签名密钥被使用后,在不牺牲系统完整性的情况下,在最短时间内同步,这允许你彻底回避初始密钥分发的问题。基本上,您预先计算一组哈希-h(h(h…(h(k))…)),使用第n个值签名,在设置的间隔之后,发送密钥,并使用密钥(n-1)签名。接收者现在可以验证您是否发送了所有以前的消息,并且没有人可以伪造您的签名,因为它的有效期已经过去。

    像比尔建议的那样重新散列数十万次只是浪费你的CPU。如果您担心人们破坏128位,请使用较长的密钥。


    对。

    绝对不要使用传统散列函数的多次迭代,比如md5(md5(md5(password)))。充其量,您的安全性将得到边际的提高(像这样的方案几乎不提供任何针对GPU攻击的保护,只需通过管道传输即可)。充其量,您在每次添加迭代时都会减少散列空间(从而降低安全性)。在安全方面,最好假设最坏的情况。

    一定要使用一个由一个称职的密码学家设计的密码,它是一个有效的密码散列,能够抵抗暴力和时空攻击。其中包括bcrypt、scrypt,在某些情况下还包括pbkdf2。也可以接受基于glibc sha-256的哈希。


    我要冒险说在某些情况下它更安全…不过,不要轻视我!

    从数学/密码学的角度来看,这是不安全的,因为我相信其他人会给你一个比我更清楚的解释。

    然而,存在大量的MD5散列数据库,它们比MD5散列更可能包含"密码"文本。因此,通过双重散列,您就降低了这些数据库的有效性。

    当然,如果你使用盐,那么这个优势(劣势?)走开。


    双重散列很难看,因为攻击者很可能已经构建了一个表来处理大多数散列。最好是加盐,然后混合。也有新的模式来"签署"散列(基本上是盐渍),但以一种更安全的方式。