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

Dar*_*nke 48 php authentication

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

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

Dar*_*nke 30

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

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

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

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

  • openID 的真正缺点是它基本上使任何大型网站运营商(谷歌等)都可以持续跟踪他们的用户以及他们在您自己的网站中所做的事情。而且,您的用户数据取决于远程提供商 - 这不是一件好事。如果他们决定对他们正在运行的 openid 服务进行任何更改,您将成为他们的...... (2认同)

Sco*_*ski 13

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

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

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

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

主选择器

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

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

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

密码哈希

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

超越Bcrypt

有时开发人员喜欢创造性(例如添加"胡椒",这通常意味着使用静态密钥进行预先散列或HMACing密码)并超越标准实现.我们自己已经这样做了,但非常保守.

对于我们的内部项目(其安全性比大多数人的博客高得多),我们编写了一个围绕此API的包装器PasswordLock,首先使用密码哈希sha256,然后base64编码原始哈希输出,然后将此base64编码的哈希传递给password_hash(),最后使用正确实现的加密库加密bcrypt哈希.

重申一下,我们加密我们的密码哈希,而不是胡椒.这使我们在发生泄漏时更具灵活性(我们可以解密,然后重新加密,因为我们知道密钥).此外,我们可以在同一数据中心的不同硬件上运行我们的Web服务器和数据库,以减轻SQL注入漏洞的影响.(为了开始破解哈希,你需要AES密钥.即使你逃到文件系统,你也无法从数据库中获取它.)

// Storage:
$stored = \ParagonIE\PasswordLock\PasswordLock::hashAndEncrypt($password, $aesKey);

// Verification:
if (\ParagonIE\PasswordLock\PasswordLock::decryptAndVerify($password, $stored, $aesKey)) {
    // Authenticated!
}
Run Code Online (Sandbox Code Playgroud)

密码存储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);

进一步阅读


Mar*_*ork 11

我使用OpenID .

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

(OpenID)的明显优势是.

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


Dou*_*ugW 9

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

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


Dar*_*nke 8

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

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

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

  • 我希望它应该发音为PHP*pass*.:) (54认同)

Pat*_*ert 5

使用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进行所有操作,否则用户名和密码也会以纯文本格式在每个查询上通过网络.

  • 我想补充一点,虽然使用http-auth作为内部内容是完全可以的,但如果你的酷酷网站使用它,对最终用户来说感觉非常"俗气"/便宜.这种"感知"问题很难解决. (2认同)

Eva*_*ske 5

将应用程序的安全层与其其余部分分开非常重要。如果您的应用程序逻辑和通信系统之间没有距离,您就可以在一个地方进行不安全的通信,而在其他地方进行安全的通信。也许您会犯一个错误并在未加密的 cookie 中发送密码,或者您可能会忘记验证用户的凭据。如果没有与用户沟通的“正确方式”,您肯定会犯错误。

例如,假设您现在验证用户的方式如下:

user_cookie = getSecureCookie()
if (user_cookie.password == session_user.password) {
    do_secure_thing()
    ...
}
Run Code Online (Sandbox Code Playgroud)

如果在 getSecureCookie() 中发现漏洞,并且您使用此代码来验证整个应用程序中的用户,则您可能找不到需要修复的所有 getSecureCookie() 实例。但是,如果您将逻辑与安全性分开:

if (userVerified()) {
    do_secure_thing()
    ...
}
Run Code Online (Sandbox Code Playgroud)

...您将能够快速轻松地重新保护您的应用程序。给自己一个“正确的方法”来确保安全,那么您犯下重大安全错误的可能性就会大大降低。