题 为PHP密码保护哈希和盐


目前据说MD5部分不安全。考虑到这一点,我想知道使用哪种机制来保护密码。

这个问题, “双重散列”密码是否比仅仅散列一次密码更安全?  表明多次散列可能是一个好主意,而 如何实现单个文件的密码保护? 建议使用盐。

我正在使用PHP。我想要一个安全快速的密码加密系统。散列密码一百万次可能更安全,但也更慢。如何在速度和安全性之间取得良好的平衡?另外,我更喜欢结果具有恒定数量的字符。

  1. 散列机制必须在PHP中可用
  2. 它必须是安全的
  3. 它可以使用盐(在这种情况下,所有的盐都同样好吗?有没有办法产生好的盐?)

另外,我应该在数据库中存储两个字段(例如,一个使用MD5,另一个使用SHA)?它会使它更安全或更不安全吗?

如果我不够清楚,我想知道使用哪种散列函数以及如何选择好的盐以便拥有安全快速的密码保护机制。

相关问题并不完全涵盖我的问题:

PHP中SHA和MD5的区别是什么
简单的密码加密
安全的方法存储密钥,asp.net的密码
您将如何在Tomcat 5.5中实现salted密码


1049
2017-12-30 22:02


起源


openwall.com/phpass 图书馆也很好 - Alfred
Md5现在完全不安全 - ExceptionSlayer
@NSAwesomeGuy这取决于你使用它的目的。毫无疑问,彩虹匹配或只是暴力无瑕的MD5密码是微不足道的,但是如果使用正确的腌制,建立一个快速破解密码组的彩虹表仍然是非常不切实际的,而蛮力是一种无懈可击的做法。 - Craig Ringer
PHP 5.5+内置了安全密码哈希 php.net/manual/en/function.password-hash.php - Terence Johnson
php.net/faq.password - hakre


答案:


免责声明:这个答案写于2008年。

从那以后,PHP给了我们 password_hash 和 password_verify 并且,自引入以来,它们是推荐的密码散列和检查方法。

答案的理论仍然是一个很好的阅读。

TL; DR

注意事项

  • 不要限制用户可以为密码输入的字符数。只有白痴这样做。
  • 不要限制密码的长度。如果您的用户想要一个包含supercalifragilisticexpialidocious的句子,请不要阻止他们使用它。
  • 切勿以纯文本格式存储用户密码。
  • 切勿向用户发送密码 除非他们丢了他们的,你发了一个临时的。
  • 永远不要以任何方式记录密码。
  • 切勿使用哈希密码 SHA1 或MD5甚至SHA256! 现代饼干 每秒可以超过60和1800亿个哈希值(分别)。
  • 不要混 bcrypt和 生的 hash()的输出,使用十六进制输出或base64_encode它。 (这适用于任何可能有流氓的输入 \0 在其中,这会严重削弱安全性。)

DOS

  • 尽可能使用scrypt; bcrypt,如果你不能。
  • 如果您不能使用带有SHA2哈希值的bcrypt或scrypt,请使用PBKDF2。
  • 在数据库受到威胁时重置每个人的密码。
  • 实现合理的8-10个字符的最小长度,另外需要至少1个大写字母,1个小写字母,数字和符号。这将改善密码的熵,从而使其更难破解。 (请参阅“什么是一个好的密码?”部分进行一些辩论。)

为什么哈希密码呢?

哈希密码背后的目标很简单:通过破坏数据库来防止恶意访问用户帐户。因此,密码散列的目标是通过花费太多时间或金钱来计算明文密码来阻止黑客或黑客。而时间/成本是你的武器库中最好的威慑力量。

您希望在用户帐户上使用良好,健壮的哈希的另一个原因是为您提供足够的时间来更改系统中的所有密码。如果您的数据库遭到入侵,您将需要足够的时间 最小 如果不更改数据库中的每个密码,请锁定系统。

Whitehat Security的首席技术官Jeremiah Grossman, 在他的博客上说 在最近的密码恢复后,需要暴力破解他的密码保护:

有趣的是,在实现这个噩梦的过程中,我学到了很多关于密码破解,存储和复杂性的知识。 我开始意识到为什么密码存储比密码复杂性更重要。如果您不知道密码的存储方式,那么您真正依赖的就是复杂性。 这可能是密码和加密专业人员的常识,但对于普通的InfoSec或Web安全专家,我非常怀疑。

(强调我的。)

是什么让一个  密码呢?

。 (并不是说我完全赞同兰德尔的观点。)

简而言之,熵是密码内的变化程度。如果密码只是小写罗马字母,则只有26个字符。这没有太大的变化。字母数字密码更好,有36个字符。但允许使用符号的大写和小写大约是96个字符。这比仅仅是字母要好得多。一个问题是,为了使我们的密码令人难忘,我们插入模式 - 这减少了熵。哎呀!

密码熵是 近似 容易。使用全范围的ascii字符(大约96个可键入的字符)产生每个字符6.6的熵,对于未来的安全性,密码的8个字符仍然太低(52.679位的熵)。但好消息是:更长的密码和带有unicode字符的密码,确实会增加密码的熵并使其更难破解。

关于密码熵的讨论还有较长时间 加密StackExchange 现场。一个好的谷歌搜索也会带来很多结果。

我在与@popnoodles谈过的评论中指出了这一点 强制执行 X长度的密码策略,X多个字母,数字,符号等,实际上可以通过使密码方案更可预测来减少熵。我同意。 Randomess尽可能真正随机,始终是最安全但最难忘的解决方案。

据我所知,制作世界上最好的密码是Catch-22。它不是难忘的,太可预测的,太短的,太多的unicode字符(难以在Windows /移动设备上键入),太长时间等等。没有密码对我们的目的来说真的足够好,所以我们必须像他们一样保护他们在诺克斯堡。

最佳做法

Bcrypt和 scrypt 是目前的最佳做法。 Scrypt 会比bcrypt及时更好,但它还没有被Linux / Unix或网络服务器采用为标准,并且尚未对其发布的算法进行过深入的评论。但是,算法的未来确实看起来很有希望。如果你正在使用Ruby,那就有一个 scrypt gem 这将帮助你,Node.js现在有自己的 scrypt 包。您可以通过PHP在PHP中使用Scrypt Scrypt 扩展或 Libsodium 扩展(两者均在PECL中提供)。

我强烈建议阅读文档 隐窝功能 如果你想了解如何使用bcrypt,或找到自己   包装纸 或使用类似的东西 PHPASS 用于更传统的实施。我建议至少12轮bcrypt,如果不是15到18。

当我得知bcrypt只使用河豚的密钥时间表,并使用可变成本机制时,我改变了主意使用bcrypt。后者允许您通过增加blowfish已经很昂贵的密钥计划来增加强制密码的成本。

平均做法

我几乎无法想象这种情况了。 PHPASS 支持PHP 3.0.18到5.3,所以它几乎可以在所有可以想象的安装上使用 - 如果不这样的话,应该使用它 知道肯定 你的环境支持bcrypt。

但是假设您根本不能使用bcrypt或PHPASS。然后怎样呢?

尝试实现 PDKBF2 随着 最大轮数 您的环境/应用程序/用户感知可以容忍。我推荐的最低数字是2500发。另外,请务必使用 hash_hmac() 如果可以使操作更难以重现。

未来的实践

进入PHP 5.5是一个 完整的密码保护库 这消除了使用bcrypt工作的任何痛苦。虽然我们大多数人在大多数常见环境中都使用PHP 5.2和5.3,特别是共享主机,但@ircmaxell已经构建了一个 兼容层 对于即将向后兼容PHP 5.3.7的API。

密码学回顾与免责声明

实际需要的计算能力 裂纹 哈希密码不存在。计算机“破解”密码的唯一方法是重新创建密码并模拟用于保护密码的散列算法。哈希的速度与其强制的能力线性相关。更糟糕的是,大多数哈希算法可以轻松并行化,以便更快地执行。这就是像bcrypt和scrypt这样昂贵的计划如此重要的原因。

您无法预见所有威胁或攻击途径,因此您必须尽最大努力保护您的用户 在前面。如果你不这样做,那么你甚至可能会错过这样一个事实:你被攻击直到为时已晚...... 你有责任。为了避免这种情况,首先要采取偏执行为。攻击您自己的软件(内部)并尝试窃取用户凭据,或修改其他用户的帐户或访问其数据。如果你不测试系统的安全性,那么除了你自己,你不能责怪任何人。

最后:我不是密码学家。无论我说的是我的意见,但我碰巧认为这是基于良好的常识......以及大量的阅读。请记住,尽可能偏执,让事情尽可能难以入侵,然后,如果您仍然担心,请联系白帽黑客或密码学家,看看他们对您的代码/系统的看法。


892
2017-12-30 22:15



秘密没有帮助,因为你的密码数据库应该是秘密的 - 如果他们可以获得该数据库,他们也可以找到你正在使用的任何秘密。然而重要的是盐是随机的。 - frankodwyer
请注意,“解密的计算能力”尚不存在,这并不是真的。由于大多数密码是字典单词或字典派生的,因此基于字典的攻击通常非常有效(因此使用密码策略和迭代计数)。 - frankodwyer
@wicked跳蚤,我不跟你争论。只是指出我们工作的这个领域是多么复杂和复杂。我一直希望能够通过建立小型网站内容管理系统的最佳,最智能,最好的做法接受教育。我还在这里学习。 ......每当我读到有意义的东西时,我很快就会注意到其他5个与之相矛盾的帖子。这种圆形的快速变得令人目不暇接:) - m42
有趣的修订。用户ID(例如,自动增量BIGINT)是一个好的随机数吗?或者因为它不是随机的,它不好?此外,我将不得不为数据库中的每个用户存储nonce ...网站密钥+ nonce + HMAC是否比多次迭代的salted(带有用户ID)哈希提供了显着提高的安全性?同样,为了安全性,多次重复使用HMAC? - luiscubal
通过电子邮件发送临时密码,要求用户在第一次使用时更改密码并通过电子邮件发送“安全”链接以允许他们设置密码同样存在风险。在任何一种情况下,任何拦截电子邮件的人都可以访问该帐户,只要他们在预期收件人之前使用该链接或密码即可。 - Tim Gautier


一个更简短,更安全的答案 - 根本不要写自己的密码机制,使用久经考验的机制。

  • PHP 5.5或更高版本: password_hash() 质量很好,是PHP核心的一部分。
  • 较旧的PHP版本:OpenWall phpass 库比大多数自定义代码要好得多 - 在WordPress,Drupal等中使用。

大多数程序员都没有专业知识来安全地编写加密相关代码而不会引入漏洞。

快速自检: 什么是密码拉伸以及您应该使用多少次迭代?如果你不知道答案,你应该使用 password_hash()因为密码机制的一个关键特性是密码机制的关键特性,因为CPU速度更快,并且使用更快 GPU和FPGA 破解密码的速度 每秒数十亿的猜测 (使用GPU)。

例如,你可以 在6小时内破解所有8个字符的Windows密码 使用5台台式机中安装的25个GPU。这是强制性的,即枚举和检查 每个8个字符的Windows密码,包括特殊字符,并不是字典攻击。那是在2012年,从2018年开始,您可以使用更少的GPU,或者使用25个GPU更快地破解。

对于在普通CPU上运行且非常快的Windows密码,还有许多彩虹表攻击。这一切都是因为Windows 仍然  不会盐或拉伸 它的密码, 甚至在Windows 10中  - 不要像微软那样犯同样的错误!

也可以看看: 

  • 优秀的答案 更多关于为什么 password_hash() 要么 phpass 是最好的方式。
  • 好博客文章 给出主要算法的推荐'工作因素'(迭代次数),包括bcrypt,scrypt和PBKDF2。

120
2017-11-08 12:02



但这些系统更为人所知,可能已经受到了损害。但是当你不知道自己在做什么时,它就会打败自己。 - ExceptionSlayer
重新“这些系统更为人所知并且可能已经受到损害” - 没有理由认为设计良好的身份验证系统应该因为它更为人所知而“已经受到损害”。像phpass这样的图书馆是由专家编写的,并且被许多人详细审阅 - 他们众所周知的事实与不同的人进行详细审查并且更可能意味着他们是安全的。 - RichVel
@PP - 在我看来,具有NSA后门的同行评审密码哈希算法的可能性非常低。不是真正的加密专家的人写一个没有其他漏洞的新密码散列机制的机会要低得多。典型的webapp只使用MD5或SHA-1哈希,这很糟糕 - 甚至Chris Shiflett的其他伟大的基本PHP安全书推荐MD5 ...... - RichVel
当我读到这个时,我的心在流血 - YAMM
@RichVel - password_hash()函数。如前所述,它内置于PHP核心(aka / ext / standard)。 - CubicleSoft


我不会以两种不同的方式存储密码哈希值,因为那时系统至少与使用中最弱的哈希算法一样弱。


40
2017-12-30 22:18



不用于密码哈希。攻击者只需要打破一个哈希来检索密码。无论如何,MD5和SHA1在密码方案中都没有任何实际的中断,这一点无关紧要。 - frankodwyer
对不起,我误解了你的答案,建议使用两个哈希......你其实是正确的。在密码情况下使用两个哈希会削弱系统,因为它们只需要打破较弱的哈希值。 - frankodwyer


虽然这个问题已得到解答,但我只想重申,用于散列的盐应该是随机的,而不是像第一个答案中建议的电子邮件地址。

有关的更多解释─ http://www.pivotalsecurity.com/blog/password-hashing-salt-should-it-be-random/

最近我讨论了密码哈希是否随机腌制   位比使用可猜测或已知的盐更安全   盐。让我们看看:如果系统存储密码被泄露为   以及存储随机盐的系统,攻击者将会   有权访问哈希和盐,所以盐是随机的还是   不,没关系。攻击者可以生成预先计算的   彩虹表破解哈希。这是有趣的部分   生成预先计算的表并不是那么简单。让我们举个例子   WPA安全模型。您的WPA密码实际上从未发送过   无线接入点。相反,它是用您的SSID(   网络名称 - 如Linksys,Dlink等)。一个很好的解释如何   这项工作就在这里。为了从哈希中检索密码,你会   需要知道密码以及salt(网络名称)。教堂   Wifi已经预先计算了具有前1000个SSID和的散列表   大约100万个密码。所有表的大小约为40 GB。   正如您可以在他们的网站上阅读的那样,有人在3天内使用了15个FGPA阵列   生成这些表。假设受害者正在使用SSID   “a387csf3”和密码为“123456”,会被那些人破解   表?没有! .. 这不可以。即使密码很弱,表也是如此   没有SSID a387csf3的哈希值。这就是拥有的美   随机盐。它将阻止那些在预先计算中茁壮成长的破解者   表。能阻止坚定的黑客吗?可能不会。但是使用   随机盐确实提供了额外的防御层。我们在的时候   这个主题,让我们讨论存储随机的额外优势   在单独的系统上的盐。场景#1:存储密码哈希值   在系统X上,用于散列的盐值存储在系统Y上。   这些盐值是可猜测的或已知的(例如用户名)场景#2:   密码哈希存储在系统X和用于的盐值上   散列存储在系统Y上。这些盐值是随机的。以防万一   系统X已被破坏,你可以猜测,有一个巨大的   在单独的系统上使用随机盐的优势(场景#2)。   攻击者需要猜测附加值才能破解   哈希值。如果使用32位盐,则2 ^ 32 = 4,294,967,296(约4.2   猜测的每个密码都需要迭代。


30
2018-02-12 00:52



即使攻击者获得了盐,“sitesalt:usersalt:password”字符串仍然可以抵抗预先计算的表,因为攻击者需要为每个用户生成表(因此攻击变得慢得多),除非当然是特定用户正在成为目标...... - luiscubal
关于“即使攻击者获得了盐,”sitesalt:usersalt:password“字符串仍然可以抵抗预先计算的表格”,完全同意。我的观点是,如果随机和长期使用sitealt,将使系统更安全(sitealt)可预测。我见过有人推荐使用电子邮件ID等作为盐,我不鼓励这样做。 - Gaurav Kumar
你错过了我最初的写作。我说使用随机随机数,与记录一起存储,加上电子邮件地址。添加电子邮件地址可为黑客提供额外的熵。我已经改写了我的回答,支持bcrypt。 - Robert K


从PHP 5.5开始,PHP具有简单,安全的函数,用于散列和验证密码, password_hash() 和 password_verify()

$password = 'anna';
$hash = password_hash($password, PASSWORD_DEFAULT);
$expensiveHash = password_hash($password, PASSWORD_DEFAULT, array('cost' => 20));

password_verify('anna', $hash); //Returns true
password_verify('anna', $expensiveHash); //Also returns true
password_verify('elsa', $hash); //Returns false

什么时候 password_hash() 如果使用它,它会生成一个随机盐并将其包含在输出的哈希值中(以及使用的成本和算法)。 password_verify() 然后读取该哈希并确定使用的salt和加密方法,并根据提供的明文密码进行验证。

提供 PASSWORD_DEFAULT 指示PHP使用已安装的PHP版本的默认哈希算法。究竟哪种算法意味着在未来版本中随时间变化,因此它将始终是最强大的可用算法之一。

增加成本(默认为10)会使哈希难以暴力,但也意味着生成哈希并验证密码对您的服务器的CPU来说将更有用。

请注意,即使默认哈希算法可能会更改,旧哈希将继续验证,因为所使用的算法存储在哈希中 password_verify() 接受它。


30
2017-09-21 21:33





我只想指出PHP 5.5包含一个 密码哈希API 它提供了一个包装器 crypt()。此API显着简化了散列,验证和重新散列密码哈希的任务。作者也发布了一个 兼容包 (以简单的单个password.php文件的形式 require 使用),对于那些使用PHP 5.3.7及更高版本并希望立即使用它的人。

它现在只支持BCRYPT,但它的目的是很容易扩展到包含其他密码散列技术,并且因为技术和成本存储为散列的一部分,对你喜欢的散列技术/成本的更改不会使当前散列无效,框架将自动化,在验证时使用正确的技术/成本。如果您没有明确定义自己的盐,它还会处理生成“安全”盐。

API公开了四个功能:

  • password_get_info()  - 返回有关给定哈希的信息
  • password_hash()  - 创建密码哈希
  • password_needs_rehash()  - 检查给定的散列是否与给定的选项匹配。用于检查哈希是否符合您当前的技术/成本方案,允许您在必要时进行重新哈希
  • password_verify()  - 验证密码是否与哈希匹配

目前这些函数接受PASSWORD_BCRYPT和PASSWORD_DEFAULT密码常量,这些密码常量目前是同义词,不同之处在于,当支持更新,更强大的哈希算法时,PASSWORD_DEFAULT“可能会在较新的PHP版本中发生变化。”在登录时使用PASSWORD_DEFAULT和password_needs_rehash()(并在必要时进行重新散列)应确保您的哈希值对蛮力攻击具有相当的弹性,几乎没有工作。

编辑:我刚刚意识到罗伯特K的回答中提到了这一点。我会在这里留下这个答案,因为我认为它提供了更多关于它如何工作的信息以及它为那些不了解安全性的人提供的易用性。


25
2018-04-27 21:41





我在用着 Phpass 这是一个简单的单文件PHP类,几乎可以在每个PHP项目中轻松实现。也可以看看 H

默认情况下,它使用Phpass中实现的最强可用加密,即 bcrypt 并回退到MD5以下的其他加密,以向Wordpress等框架提供向后兼容性。

返回的哈希可以按原样存储在数据库中。生成哈希的示例用法是:

$t_hasher = new PasswordHash(8, FALSE);
$hash = $t_hasher->HashPassword($password);

要验证密码,可以使用:

$t_hasher = new PasswordHash(8, FALSE);
$check = $t_hasher->CheckPassword($password, $hash);

17
2018-06-26 08:05





要记住的事情

关于PHP的密码加密已经说了很多,其中大部分是非常好的建议,但在你开始使用PHP进行密码加密的过程之前,请确保你已经实现了以下内容或准备好实现。

服务器

PORTS

无论您的加密有多好,如果您没有正确保护运行PHP和DB的服务器,您的所有努力都毫无价值。大多数服务器的功能相同,它们分配了端口,允许您通过ftp或shell远程访问它们。确保更改了您处于活动状态的远程连接的默认端口。通过不执行此操作,您实际上已使攻击者在访问系统时减少了一步。

用户名

对于世界上所有好的,不要使用用户名admin,root或类似的东西。此外,如果您使用的是基于unix的系统,请不要使root帐户登录可访问,它应该始终只是sudo。

密码

您告诉您的用户制作好的密码以避免被黑客入侵,同样做。当后门敞开时,通过锁定前门的所有努力有什么意义。

数据库

服务器

理想情况下,您希望将DB和APPLICATION放在不同的服务器上。由于成本原因,这并不总是可行的,但它确实允许一定的安全性,因为攻击者必须通过两个步骤才能完全访问系统。

用户

始终让您的应用程序拥有自己的帐户来访问数据库,并且只为其提供所需的权限。

然后为您提供一个单独的用户帐户,该帐户不存储在服务器上的任何位置,甚至不存储在应用程序中。

像往常一样,不要使这个根或类似的东西。

密码

遵循与所有良好密码相同的指导原则。也不要在同一系统上的任何SERVER或DB帐户上重复使用相同的密码。

PHP

密码

永远不要在你的数据库中存储密码,而是存储哈希和唯一的盐,我将在后面解释原因。

HASHING

一种方式哈希!!!!!!!,永远不要以可以反转的方式哈希密码,哈希应该是一种方式,这意味着你不要反转它们并将它们与密码进行比较,而是哈希输入的密码以同样的方式比较两个哈希。这意味着即使攻击者可以访问数据库,他也不知道实际的密码是什么,只是它产生的哈希值。这意味着在最糟糕的情况下为您的用户提供更高的安全性。

那里有很多很好的散列函数(password_hashhash等等...)但你需要选择一个好的算法让哈希有效。 (bcrypt和类似它的是不错的算法。)

当散列速度是关键时,对Brute Force攻击的抵抗力越强。

散列中最常见的错误之一是散列并非用户独有。这主要是因为盐不是唯一产生的。

在散列之前,密码应该总是被腌制。 Salting会在密码中添加一个随机字符串,因此类似的密码在数据库中看起来并不相同。但是,如果每个用户的盐并不是唯一的(即:你使用的是硬编码的盐),那么你的盐就会变得毫无价值。因为一旦攻击者找到一个密码盐,他就会为所有人提供盐。

创建salt时,请确保它对于密码是唯一的,然后将完成的散列和salt存储在数据库中。这样做是为了让攻击者在获得访问权限之前必须单独破解每个盐和哈希值。这意味着攻击者需要做更多的工作和时间。

用户创建密码

如果用户通过前端创建密码,则意味着必须将密码发送到服务器。这会打开一个安全问题,因为这意味着将未加密的密码发送到服务器,如果攻击者能够监听并访问,那么PHP中的所有安全性都毫无价值。总是安全地传输数据,这是通过SSL完成的,但是即使SSL也没有完美无缺(OpenSSL的Heartbleed漏洞就是这样的一个例子)。

同时让用户创建一个安全的密码,它很简单,应该永远完成,用户最终会感激它。

最后,无论您采取的安全措施是否100%安全,保护技术越先进,攻击就越先进。但是,遵循这些步骤将使您的网站更安全,而且不太可能让攻击者追求。

这是一个PHP类,可以轻松地为密码创建哈希和salt

http://git.io/mSJqpw


13
2018-04-09 15:01



你应该从你的体面哈希算法列表中敲击SHA512,因为它太快了。仅与PBKDF2组合使用。虽然BCrypt基于河豚,但河豚本身是一种加密算法,而不是哈希算法。 - martinstoeckli
如何在数据库中存储随机盐?我认为你不哈希它(不能用于验证)也不清楚存储(如果攻击者可以读取数据库则没有真正的好处)。那么,你是怎么做到的? - Iazel
wmfrancia写道:“Salting会在密码中添加一个随机字符串,因此类似的密码在数据库中看起来并不相同”。这对我来说没有意义。数据库中的哈希值已经显得不同,因为这是哈希函数的一个属性。 - H2ONaCl
wmfancia写道,关于恒定的盐:“一旦攻击者找到一个密码盐,他就为所有人提供盐”。同样可以说,如果黑客确定哪个DB字段是盐,他就拥有所有这些的盐。由于恒温盐可能不在DB中,因此对于恒定的盐来说这是一件好事。 - H2ONaCl
当然,这些评论并不是说每个用户的随机盐并不比每个应用的一个盐好。这个比较好。 - H2ONaCl


谷歌称PHP可以使用SHA256。

你绝对应该使用盐。我建议使用随机字节(而不是限制自己的字符和数字)。通常情况下,选择的时间越长,越安全,越慢。我想,64字节应该没问题。


12
2017-12-30 22:20



对于任何人来说,64位应该足够了吗? - Konerak
@Konerak,20年后我会回到这里。 :)但是,确实SHA256确实可用。如果你想知道SHA256的安全性,你可能想看看这个: security.stackexchange.com/questions/90064/... - Vincent Edward Gedaria Binua