[英]PHP best practices for user authentication and password security
在不使用CMS或繁重框架的情况下对用户进行身份验证的最佳库/方法有哪些?
响应应该包括您认为应该被视为涉及用户身份验证的新PHP开发标准的任何建议。
安全地实施用户身份验证而不依赖于框架(或第三方库,如OpenID)来为您完成这项任务并非易事。
在10,000英尺的概述,你必须决定:
password_hash()
或scrypt是要走的路。 此答案中的信息与2015年5月9日相关且最新,可能会因密码哈希竞争的结束而被废弃
通常,用户名和电子邮件地址优于ID号。
应该没有安全要求来保持用户名的秘密,因为在实践中,当有人试图注册时,它们将被泄露。
您可以决定是否将电子邮件地址视为机密。 用户通常喜欢不接触垃圾邮件发送者,诈骗者和巨魔。
你应该使用password_hash()
和password_verify()
除非你有足够的经验来编写加密库以超越它。
有时开发人员喜欢创造性(例如添加“胡椒”,这通常意味着使用静态密钥进行预先散列或HMACing密码)并超越标准实现。 我们自己已经这样做了,但非常保守。
对于我们的内部项目(其安全性比大多数人的博客高得多),我们编写了一个名为PasswordLock
API封装器,首先使用sha256
散列密码,然后base64对原始散列输出进行编码,然后传递此base64编码hash to password_hash()
,最后使用正确实现的加密库加密bcrypt哈希。
重申一下,我们加密我们的密码哈希 , 而不是胡椒。 这使我们在发生泄漏时更具灵活性(我们可以解密,然后重新加密,因为我们知道密钥)。 此外,我们可以在同一数据中心的不同硬件上运行我们的Web服务器和数据库,以减轻SQL注入漏洞的影响。 (为了开始破解哈希,你需要AES密钥。即使你逃到文件系统,你也无法从数据库中获取它。)
// Storage:
$stored = \ParagonIE\PasswordLock\PasswordLock::hashAndEncrypt($password, $aesKey);
// Verification:
if (\ParagonIE\PasswordLock\PasswordLock::decryptAndVerify($password, $stored, $aesKey)) {
// Authenticated!
}
PasswordLock
: hash('sha256', $password, true);
base64_encode($step1);
password_hash($step2, PASSWORD_DEFAULT);
Crypto::encrypt($step3, $secretKey);
PasswordLock
: Crypto::decrypt($ciphertext, $secretKey);
hash('sha256', $password, true);
base64_encode($step2);
password_verify($step3, $step1);
我使用OpenID 。
但是像stackoverflow一样,我使用Google项目openid-selector来完成繁重的工作。
演示页面在这里 。
(OpenID)的明显优势是。
这里有很多很棒的答案,但我觉得值得这样说 - 在这种情况下不要试图重新发明轮子 ! 以各种方式搞砸用户身份验证非常容易。 除非您确实需要自定义解决方案,并且对安全方案和最佳实践有扎实的了解,否则您几乎肯定会遇到安全漏洞。
OpenID很棒,或者如果您打算自己动手,至少使用已建立的库并按照文档进行操作!
PHPass是一个使用bcrypt的轻量级,可变成本密码哈希库。
可变成本意味着您可以稍后调高散列密码的“成本”,以无缝地提高安全性,而无需使先前散列的用户密码无效。
用于散列存储的字段大小即使在增加“成本”时也是不变的,因为不增加散列的大小,而是增加生成它所需的迭代次数。
使用HTTP AUTH登录
经过身份验证后,对于PHP ,您只需使用$_SERVER['PHP_AUTH_USER']
来检索身份验证期间使用的用户名。
这可以是比在脚本级别处理解决方案更快,有时更灵活的解决方案,前提是需要有关用户的有限信息,因为所有可用的用户都是用于登录的用户名。
但是,除非您在脚本语言中实现完整的HTTP AUTH方案,否则不要将您的身份验证集成到HTML表单中(如下所述)。
在脚本语言中滚动自己的HTTP AUTH
实际上,你可以扩展 HTTP基本认证 通过脚本语言模仿它。 对此的唯一要求是您的脚本语言必须能够将HTTP标头发送到HTTP客户端。 有关如何使用PHP实现此目的的详细说明, 请参见此处:( 有关PHP和HTTP AUTH的更多信息,请参阅参考资料 )。
您可以使用典型的身份验证模式,文件存储,甚至PHP会话或cookie(如果信息不需要持久性)扩展上面的文章,在使用HTTP AUTH时提供更大的灵活性,同时仍然保持一些简单性。
缺少HTTP AUTH
HTTP身份验证的主要缺点是退出可能会带来的复杂性。 清除用户会话的主要方法是关闭浏览器,或者传递一个标题为403 Authentication Required。 不幸的是,这意味着HTTP AUTH弹出窗口会返回页面,然后要求用户重新登录或点击取消。 考虑到可用性时,这可能效果不佳,但可以使用一些有趣的结果(即使用cookie和HTTP AUTH组合来存储状态)。
HTTP AUTH弹出窗口,会话和HTTP标头处理由浏览器实现标准确定。 这意味着您将无法使用该实现(包括任何错误)而无法解决(与其他替代方案不同)。
基本身份验证还意味着auth_user和密码显示在服务器日志中,然后您必须使用https进行所有操作,否则用户名和密码也会以纯文本格式在每个查询上通过网络。
将应用程序的安全层与其余部分分开是很重要的。 如果您的应用程序逻辑与您的通信系统之间没有距离,您可以在一个地方安全地进行不安全的通信,并在其他地方安全地进行通信。 也许你会犯一个错误并在未加密的cookie中发送密码,或者你可能忘记一步验证用户的凭据。 没有“正确的方式”与用户沟通,你肯定会犯错。
例如,假设这是您现在验证用户的方式:
user_cookie = getSecureCookie()
if (user_cookie.password == session_user.password) {
do_secure_thing()
...
}
如果在getSecureCookie()中发现漏洞,并且您使用此代码验证整个应用程序中的用户,则可能找不到需要修复的所有getSecureCookie()实例。 但是,如果您将逻辑与安全性分开:
if (userVerified()) {
do_secure_thing()
...
}
...您将能够快速轻松地重新保护您的应用程序。 给自己一个安全的“正确方法”,你将不太可能犯下重大的安全错误。
最佳身份验证是利用多因素身份验证,理想情况下是所有安全敏感登录的无令牌版本。
密码保护,易于使用,具有高可靠性和安全性。 除EMC / RSA外,还有几种可用产品。 我更喜欢SwivelSecure的PINSafe。
伊戈尔S.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.