|
1 | 1 | <?xml version="1.0" encoding="utf-8"?> |
2 | 2 | <!-- $Revision$ --> |
3 | | -<!-- EN-Revision: b8e1b1357def73f310c9f7405035b3acc0cb1eaf Maintainer: yuanyuqiang Status: ready --> |
| 3 | +<!-- EN-Revision: f012b2761819e0ab25ff8cf4bac6655cfbc6fcff Maintainer: yuanyuqiang Status: ready --> |
4 | 4 | <!-- CREDITS: mowangjuanzi --> |
5 | 5 | <chapter xml:id="faq.passwords" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink"> |
6 | | - <title>密码散列安全</title> |
| 6 | + <title>安全可靠的密码散列</title> |
7 | 7 | <titleabbrev>密码散列</titleabbrev> |
8 | 8 |
|
9 | | - <para> |
| 9 | + <simpara> |
10 | 10 | 本部分解释使用散列函数对密码进行安全处理背后的原因,以及如何有效的进行密码散列处理。 |
11 | | - </para> |
| 11 | + </simpara> |
12 | 12 |
|
13 | 13 | <qandaset> |
14 | 14 | <qandaentry xml:id="faq.passwords.hashing"> |
15 | 15 | <question> |
16 | | - <para> |
17 | | - 为什么需要把应用程序中用户的密码进行散列化? |
18 | | - </para> |
| 16 | + <simpara> |
| 17 | + 为什么需要把用户的密码进行散列化? |
| 18 | + </simpara> |
19 | 19 | </question> |
20 | 20 | <answer> |
21 | | - <para> |
22 | | - 当设计一个需要接受用户密码的应用时, |
23 | | - 对密码进行散列是最基本的,也是必需的安全考虑。 |
24 | | - 如果不对密码进行散列处理,那么一旦应用的数据库受到攻击, |
25 | | - 那么用户的密码将被窃取。 |
26 | | - 同时,窃取者也可以使用用户账号和密码去尝试其他的应用, |
27 | | - 如果用户没有为每个应用单独设置密码,那么将面临风险。 |
28 | | - </para> |
29 | | - <para> |
30 | | - 通过对密码进行散列处理,然后再保存到数据库中, |
31 | | - 这样就使得攻击者无法直接获取原始密码, |
32 | | - 同时还可以保证你的应用可以对原始密码进行相同的散列处理, |
33 | | - 然后比对散列结果。 |
34 | | - </para> |
35 | | - <para> |
36 | | - 需要着重提醒的是,密码散列只能保护密码 |
37 | | - 不会被从数据库中直接窃取, |
38 | | - 但是无法保证注入到应用中的 |
39 | | - 恶意代码拦截到原始密码。 |
40 | | - </para> |
| 21 | + <simpara> |
| 22 | + 设计任何接受用户密码的应用或服务时,密码散列是必须考虑到的最基本的安全问题之一。如果没有散列处理,泄露了存储的数据,任何存储的密码都将会窃取。如果用户使用不唯一的密码,那么不仅会危害应用或服务,还会危害其他服务上的用户账户。 |
| 23 | + </simpara> |
| 24 | + <simpara> |
| 25 | + 对用户密码应用散列算法,然后再存储,这样任何攻击者几乎不可能确定原始密码,同时仍然能够在未来将生成的散列值与原始密码进行比较。 |
| 26 | + </simpara> |
| 27 | + <simpara> |
| 28 | + 但值得注意的是,密码散列只能保护其在数据存储中不被泄露,但并不一定能保护它们不被注入到应用程序或服务的恶意代码截获。 |
| 29 | + </simpara> |
41 | 30 | </answer> |
42 | 31 | </qandaentry> |
43 | 32 | <qandaentry xml:id="faq.passwords.fasthash"> |
44 | 33 | <question> |
45 | | - <para> |
| 34 | + <simpara> |
46 | 35 | 为何诸如 <function>md5</function> 和 |
47 | 36 | <function>sha1</function> 这样的常见散列函数不适合用在密码保护场景? |
48 | | - </para> |
| 37 | + </simpara> |
49 | 38 | </question> |
50 | 39 | <answer> |
51 | | - <para> |
52 | | - MD5,SHA1 以及 SHA256 这样的散列算法是面向快速、高效 |
53 | | - 进行散列处理而设计的。随着技术进步和计算机硬件的提升, |
54 | | - 破解者可以使用“暴力”方式来寻找散列码 |
55 | | - 所对应的原始数据。 |
56 | | - </para> |
57 | | - <para> |
58 | | - 因为现代化计算机可以快速的“反转”上述散列算法的散列值, |
59 | | - 所以很多安全专家都强烈建议 |
60 | | - 不要在密码散列中使用这些散列算法。 |
61 | | - </para> |
| 40 | + <simpara> |
| 41 | + MD5,SHA1 以及 SHA256 这样的散列算法是面向快速、高效进行散列处理而设计的。随着技术进步和计算机硬件的提升,破解者可以使用<quote>暴力</quote>方式来寻找散列码所对应的原始数据。 |
| 42 | + </simpara> |
| 43 | + <simpara> |
| 44 | + 因为现代化计算机可以快速的<quote>反转</quote>上述散列算法的散列值,所以很多安全专家都强烈建议不要在密码散列中使用这些散列算法。 |
| 45 | + </simpara> |
62 | 46 | </answer> |
63 | 47 | </qandaentry> |
64 | 48 | <qandaentry xml:id="faq.passwords.bestpractice"> |
65 | 49 | <question> |
66 | | - <para> |
67 | | - 如果不建议使用常用散列函数保护密码,那么我应该如何对密码进行散列处理? |
68 | | - </para> |
| 50 | + <simpara> |
| 51 | + 如果不建议使用常用散列函数保护密码,那么如何对密码进行散列处理? |
| 52 | + </simpara> |
69 | 53 | </question> |
70 | 54 | <answer> |
71 | | - <para> |
| 55 | + <simpara> |
72 | 56 | 当进行密码散列处理的时候,有两个必须考虑的因素:计算量以及“盐”。散列算法的计算量越大,暴力破解所需的时间就越长。 |
73 | | - </para> |
74 | | - <para> |
75 | | - PHP 提供了<link linkend="book.password">一个原生密码散列API</link>,它提供一种安全的方式来完成密码<link |
| 57 | + </simpara> |
| 58 | + <simpara> |
| 59 | + PHP 提供了<link linkend="book.password">原生密码散列 API</link>,它提供一种安全的方式来完成密码<link |
76 | 60 | linkend="function.password-hash">散列</link>和<link linkend="function.password-verify">验证</link>。 |
77 | | - </para> |
78 | | - <!-- TODO Drop mention of crypt? --> |
79 | | - <para> |
80 | | - 还可以使用 <function>crypt</function> 函数, |
81 | | - 它支持多种散列算法。 |
82 | | - 针对每种受支持的散列算法,PHP 都提供了对应的原生实现, |
83 | | - 所以在使用此函数的时候, |
84 | | - 你需要保证所选的散列算法是你的系统所能够支持的。 |
85 | | - </para> |
86 | | - <para> |
87 | | - 当对密码进行散列处理的时候,建议采用 Blowfish 算法, |
88 | | - 这是密码散列 API 的默认算法。 |
89 | | - 相比 MD5 或者 SHA1,这个算法提供了更高的计算量, |
90 | | - 同时还有具有良好的伸缩性。 |
91 | | - </para> |
92 | | - <para> |
93 | | - 如果使用 <function>crypt</function> 函数来进行密码验证, |
94 | | - 那么你需要选择一种耗时恒定的字符串比较算法来避免时序攻击。 |
95 | | - (译注:就是说,字符串比较所消耗的时间恒定, |
96 | | - 不随输入数据的多少变化而变化) |
97 | | - PHP 中的 <link linkend="language.operators.comparison">== 和 === 操作符</link> |
98 | | - 和 <function>strcmp</function> 函数都不是耗时恒定的字符串比较, |
99 | | - 但是 <function>password_verify</function> 可以帮你完成这项工作。 |
100 | | - 我们鼓励你尽可能的使用 |
101 | | - <link linkend="book.password">原生密码散列 API</link>。 |
102 | | - </para> |
| 61 | + </simpara> |
| 62 | + <simpara> |
| 63 | + 散列密码时,建议采用 Blowfish 算法,这是密码散列 API 的默认算法。相比 |
| 64 | + MD5 或者 SHA1,具有更高的计算成本,同时还有具有良好的可扩展性。 |
| 65 | + </simpara> |
| 66 | + <simpara> |
| 67 | + <function>crypt</function> 函数也可用于密码散列处理,但仅推荐用于与其他系统的彼此协作。相反,强烈建议尽可能使用<link |
| 68 | + linkend="book.password">原生密码散列处理 API</link>。 |
| 69 | + </simpara> |
103 | 70 | </answer> |
104 | 71 | </qandaentry> |
105 | 72 | <qandaentry xml:id="faq.passwords.salt"> |
106 | 73 | <question> |
107 | | - <para> |
| 74 | + <simpara> |
108 | 75 | “盐”是什么? |
109 | | - </para> |
| 76 | + </simpara> |
110 | 77 | </question> |
111 | 78 | <answer> |
112 | | - <para> |
113 | | - 加解密领域中的“盐”是指在进行散列处理的过程中 |
114 | | - 加入的一些数据,用来避免从已计算的散列值表 |
115 | | - (被称作“彩虹表”)中 |
116 | | - 对比输出数据从而获取明文密码的风险。 |
117 | | - </para> |
118 | | - <para> |
119 | | - 简单而言,“盐”就是为了提高散列值被破解的难度 |
120 | | - 而加入的少量数据。 |
121 | | - 现在有很多在线服务都能够提供 |
122 | | - 计算后的散列值以及其对应的原始输入的清单, |
123 | | - 并且数据量极其庞大。 |
124 | | - 通过加“盐”就可以避免直接从清单中查找到对应明文的风险。 |
125 | | - </para> |
126 | | - <para> |
127 | | - 如果不提供“盐”,<function>password_hash</function> 函数会随机生成“盐”。 |
128 | | - 非常简单,行之有效。 |
129 | | - </para> |
| 79 | + <simpara> |
| 80 | + 加解密领域中的“盐”是指在进行散列处理的过程中加入的一些数据,用来避免从已计算的散列值表(被称作“彩虹表”)中对比输出数据从而获取明文密码的风险。 |
| 81 | + </simpara> |
| 82 | + <simpara> |
| 83 | + 简单而言,“盐”就是为了提高散列值被破解的难度而加入的少量数据。现在有很多在线服务都能够提供计算后的散列值以及其对应的原始输入的清单,并且数据量极其庞大。通过加“盐”就可以避免直接从清单中查找到对应明文的风险。 |
| 84 | + </simpara> |
| 85 | + <simpara> |
| 86 | + 如果不提供“盐”,<function>password_hash</function> 函数会随机生成“盐”。非常简单,行之有效。 |
| 87 | + </simpara> |
130 | 88 | </answer> |
131 | 89 | </qandaentry> |
132 | 90 | <qandaentry xml:id="faq.password.storing-salts"> |
133 | 91 | <question> |
134 | | - <para> |
135 | | - 我应该如何保存“盐”? |
136 | | - </para> |
| 92 | + <simpara> |
| 93 | + 如何保存“盐”? |
| 94 | + </simpara> |
137 | 95 | </question> |
138 | 96 | <answer> |
139 | | - <para> |
140 | | - 当使用 <function>password_hash</function> 或者 <function>crypt</function> 函数时, |
141 | | - “盐”会被作为生成的散列值的一部分返回。 |
142 | | - 你可以直接把完整的返回值存储到数据库中, |
143 | | - 因为这个返回值中已经包含了足够的信息, |
144 | | - 可以直接用在 <function>password_verify</function> 或 <function>crypt</function> |
145 | | - 函数来进行密码验证。 |
146 | | - </para> |
147 | | - <para> |
| 97 | + <simpara> |
| 98 | + 当使用 <function>password_hash</function> 或者 <function>crypt</function> |
| 99 | + 函数时,“盐”会被作为生成的散列值的一部分返回。可以直接把完整的返回值存储到数据库中,因为这个返回值中已经包含了足够的信息,可以直接用在 |
| 100 | + <function>password_verify</function> 函数来进行密码验证。 |
| 101 | + </simpara> |
| 102 | + <warning> |
| 103 | + <simpara> |
| 104 | + 应始终使用 <function>password_verify</function>,而不是重新散列并将结果与存储的散列进行比较,以避免时序攻击。 |
| 105 | + </simpara> |
| 106 | + </warning> |
| 107 | + <simpara> |
148 | 108 | 下图展示了 <function>crypt</function> 或 <function>password_hash</function> |
149 | | - 函数返回值的结构。 |
150 | | - 如你所见,算法的信息以及“盐”都已经包含在返回值中, |
151 | | - 在后续的密码验证中将会用到这些信息。 |
152 | | - </para> |
| 109 | + 函数返回值的结构。可以看出,他们包含未来密码验证所需的算法和盐的所有信息 |
| 110 | + </simpara> |
153 | 111 | <para> |
154 | 112 | <mediaobject> |
155 | 113 | <alt> |
156 | | - password_hash 和 crypt 函数返回值的组成部分,依次为:所选择的算法, |
157 | | - 算法选项,所使用的“盐”, |
158 | | - 以及散列后的密码。 |
| 114 | + password_hash 和 crypt 函数返回值的组成部分,依次为:所选择的算法,算法选项,所使用的“盐”,以及散列后的密码。 |
159 | 115 | </alt> |
160 | 116 | <imageobject> |
161 | 117 | <imagedata fileref="zh/faq/figures/crypt-text-rendered.svg" width="690" depth="192" format="SVG" /> |
|
0 commit comments