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
第二个图像前阻力-给定消息
抗碰撞-应该很难找到一对消息
对于密码的存储,我们真正关心的是预映像电阻。另外两个是没有意义的,因为
接下来的一切都是基于这样一个前提,即我们所关心的只是图像前的阻力。散列函数的其他两个基本属性可能(通常不会)不能以相同的方式容纳。因此,本文的结论仅适用于使用哈希函数存储密码的情况。它们一般不适用于……好的。我们开始吧
为了讨论这个问题,让我们发明我们自己的哈希函数:好的。
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个值…那太糟糕了…我们的原始函数将
因为我们有一个Surjective函数,所以我们不能保证任何输入子集的映射都不会发生冲突(实际上,在实践中,它们会发生冲突)。好的。
这就是这里发生的事!我们的功能不好,但这并不是为什么它起作用(这就是为什么它起作用如此迅速和彻底)。好的。
同样的事情也发生在
因此,由于将输出反馈回
所以,好的。
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 |
注意,对于
等等,是吗?让我们用我们的
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 |
这里仍然有一个粗略的模式,但是请注意,它只是一个模式,而不是我们的底层函数(它已经很弱了)。好的。
然而,注意到
通过将输入反馈到每个迭代中,我们可以有效地打破先前迭代中可能发生的任何冲突。好的。
因此,
对。这是在RFC2898中PBKDF2取代PBKDF1的原因之一。考虑这两个循环的内部循环:好的。
PBKDF1:好的。
1 2 3 4 | T_1 = Hash (P || S) , T_2 = Hash (T_1) , ... T_c = Hash (T_{c-1}) |
其中
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。但就我们这里的目的而言,我们只需说
因此,pbkdf2保持了底层
我们知道迭代哈希的安全方法。事实上:好的。
1 2 3 4 5 | $hash = $input; $i = 10000; do { $hash = hash($input . $hash); } while ($i-- > 0); |
通常是安全的。好的。
现在,为了探究我们为什么要散列它,让我们分析一下熵的运动。好的。
散列接受无限集:
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位,请使用较长的密钥。
对。
绝对不要使用传统散列函数的多次迭代,比如
一定要使用一个由一个称职的密码学家设计的密码,它是一个有效的密码散列,能够抵抗暴力和时空攻击。其中包括bcrypt、scrypt,在某些情况下还包括pbkdf2。也可以接受基于glibc sha-256的哈希。
我要冒险说在某些情况下它更安全…不过,不要轻视我!
从数学/密码学的角度来看,这是不安全的,因为我相信其他人会给你一个比我更清楚的解释。
然而,存在大量的MD5散列数据库,它们比MD5散列更可能包含"密码"文本。因此,通过双重散列,您就降低了这些数据库的有效性。
当然,如果你使用盐,那么这个优势(劣势?)走开。
双重散列很难看,因为攻击者很可能已经构建了一个表来处理大多数散列。最好是加盐,然后混合。也有新的模式来"签署"散列(基本上是盐渍),但以一种更安全的方式。