繁体   English   中英

PHP用户身份验证和密码安全的最佳实践

[英]PHP best practices for user authentication and password security

在不使用CMS或繁重框架的情况下对用户进行身份验证的最佳库/方法有哪些?

响应应该包括您认为应该被视为涉及用户身份验证的新PHP开发标准的任何建议。

OpenID是一种基于雅虎,谷歌和Flickr等常见Web服务上的现有帐户对用户进行身份验证的方法。

登录到您的站点基于成功登录远程站点。

您无需存储敏感用户信息或使用SSL来保护用户登录。

可以在此处找到该库的当前PHP版本。

安全地实施用户身份验证而不依赖于框架(或第三方库,如OpenID)来为您完成这项任务并非易事。

在10,000英尺的概述,你必须决定:

  • 您是否将用户名,电子邮件地址或用户ID作为主要选择器?
  • 你应该如何存储密码? PROTIP: password_hash()scrypt是要走的路。
  • 你应该如何处理“记住我”复选框? 互联网上有很多不好的策略。 怀疑地对待每一个人,因为他们可能会在您的应用程序中引入漏洞。
  • 应用程序应如何处理忘记密码的用户?

此答案中的信息与2015年5月9日相关且最新,可能会因密码哈希竞争的结束而被废弃

主选择器

通常,用户名和电子邮件地址优于ID号。

应该没有安全要求来保持用户名的秘密,因为在实践中,当有人试图注册时,它们将被泄露。

您可以决定是否将电子邮件地址视为机密。 用户通常喜欢不接触垃圾邮件发送者,诈骗者和巨魔。

密码哈希

你应该使用password_hash()password_verify()除非你有足够的经验来编写加密库以超越它。

超越Bcrypt

有时开发人员喜欢创造性(例如添加“胡椒”,这通常意味着使用静态密钥进行预先散列或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

  1. hash('sha256', $password, true);
  2. base64_encode($step1);
  3. password_hash($step2, PASSWORD_DEFAULT);
  4. Crypto::encrypt($step3, $secretKey);

密码验证与PasswordLock

  1. Crypto::decrypt($ciphertext, $secretKey);
  2. hash('sha256', $password, true);
  3. base64_encode($step2);
  4. password_verify($step3, $step1);

进一步阅读

我使用OpenID

但是像stackoverflow一样,我使用Google项目openid-selector来完成繁重的工作。
演示页面在这里

(OpenID)的明显优势是。

  • 您不需要成为安全专家。
  • 用户信任大型网站的信息。
  • 您可以请求(昵称等),但用户必须选择加入。
  • 您无需担心:
    • 注册程序
    • 丢失/忘记密码

这里有很多很棒的答案,但我觉得值得这样说 - 在这种情况下不要试图重新发明轮子 以各种方式搞砸用户身份验证非常容易。 除非您确实需要自定义解决方案,并且对安全方案和最佳实践有扎实的了解,否则您几乎肯定会遇到安全漏洞。

OpenID很棒,或者如果您打算自己动手,至少使用已建立的库并按照文档进行操作!

PHPass是一个使用bcrypt的轻量级,可变成本密码哈希库。

可变成本意味着您可以稍后调高散列密码的“成本”,以无缝地提高安全性,而无需使先前散列的用户密码无效。

用于散列存储的字段大小即使在增加“成本”时也是不变的,因为不增加散列的大小,而是增加生成它所需的迭代次数。

使用HTTP AUTH登录

  1. 使用Apache: http//httpd.apache.org/docs/2.2/howto/auth.html
  2. IIS其他Web服务器也可以使用它。

经过身份验证后,对于PHP ,您只需使用$_SERVER['PHP_AUTH_USER']来检索身份验证期间使用的用户名。

这可以是比在脚本级别处理解决方案更快,有时更灵活的解决方案,前提是需要有关用户的有限信息,因为所有可用的用户都是用于登录的用户名。

但是,除非您在脚本语言中实现完整的HTTP AUTH方案,否则不要将您的身份验证集成到HTML表单中(如下所述)。

在脚本语言中滚动自己的HTTP AUTH

实际上,你可以扩展 HTTP基本认证 通过脚本语言模仿它。 对此的唯一要求是您的脚本语言必须能够将HTTP标头发送到HTTP客户端。 有关如何使用PHP实现此目的的详细说明, 请参见此处:( 有关PHP和HTTP AUTH的更多信息,请参阅参考资料 )。

您可以使用典型的身份验证模式,文件存储,甚至PHP会话或cookie(如果信息不需要持久性)扩展上面的文章,在使用HTTP AUTH时提供更大的灵活性,同时仍然保持一些简单性。

缺少HTTP AUTH

  1. HTTP身份验证的主要缺点是退出可能会带来的复杂性。 清除用户会话的主要方法是关闭浏览器,或者传递一个标题为403 Authentication Required。 不幸的是,这意味着HTTP AUTH弹出窗口会返回页面,然后要求用户重新登录或点击取消。 考虑到可用性时,这可能效果不佳,但可以使用一些有趣的结果(即使用cookie和HTTP AUTH组合来存储状态)。

  2. HTTP AUTH弹出窗口,会话和HTTP标头处理由浏览器实现标准确定。 这意味着您将无法使用该实现(包括任何错误)而无法解决(与其他替代方案不同)。

  3. 基本身份验证还意味着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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM