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

时间:2009-10-26 13:39:11

标签: php authentication

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

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

8 个答案:

答案 0 :(得分:30)

OpenID是一种根据用户在Yahoo,Google和Flickr等常见网络服务上的现有帐户对用户进行身份验证的方法。

登录您的站点取决于成功登录远程站点。

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

可以找到该库的当前PHP版本here

答案 1 :(得分:13)

Implementing user authentication securely不依赖于框架(或第三方库,例如OpenID)为您完成这项工作并非易事。

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

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

此答案中的信息截至2015年5月9日是相关且最新的,可能会因password hashing competition

的结论而过时

主选择器

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

应该没有安全要求来保密用户名,因为实际上当有人试图注册时它们会被泄露。

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

密码哈希

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

超越Bcrypt

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

对于我们的内部项目(其安全性比大多数人的博客高得多),我们编写了一个名为PasswordLock的API封装器,首先使用sha256哈希密码,然后base64对原始哈希输出进行编码,然后将此base64编码的哈希传递给password_hash(),最后使用a properly-implemented encryption library加密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);
  5. 使用PasswordLock进行密码验证:

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

答案 2 :(得分:11)

我使用OpenID

但是像stackoverflow一样,我使用Google项目openid-selector进行繁重的工作 演示页面here

(OpenID)的明显优势是。

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

答案 3 :(得分:9)

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

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

答案 4 :(得分:8)

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

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

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

答案 5 :(得分:5)

使用HTTP AUTH登录

  1. 使用Apache:http://httpd.apache.org/docs/2.2/howto/auth.html
  2. 也可以使用IISother web servers
  3. 经过身份验证后,对于PHP,您只需使用$_SERVER['PHP_AUTH_USER']来检索身份验证期间使用的用户名。

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

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

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

    您实际上扩展 HTTP Basic Auth可以通过脚本语言来模拟。对此的唯一要求是您的脚本语言必须能够将HTTP标头发送到HTTP客户端。有关如何使用PHP完成此任务的详细说明,请参见:(see more on PHP and 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进行所有操作,否则用户名和密码也会以纯文本形式通过网络查询每个查询。

      < / LI>

答案 6 :(得分:4)

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

例如,假设您正在验证用户:

user_cookie = getSecureCookie()
if (user_cookie.password == session_user.password) {
    do_secure_thing()
    ...
}

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

if (userVerified()) {
    do_secure_thing()
    ...
}

...您将能够快速轻松地重新保护您的应用程序。给自己一个安全的“正确方法”,你将不太可能犯下重大的安全错误。

答案 7 :(得分:1)

最佳身份验证是利用多因素身份验证,理想情况下是所有安全敏感登录的无令牌版本。

密码保护且易于使用,具有高可靠性和安全性。除EMC / RSA外,还有几种可用产品。我更喜欢SwivelSecure的PINSafe。

Igor S