用于用户authentication和密码安全性的PHP最佳实践

什么是当前最好的库/方法来validation用户而不使用CMS或繁重的框架?

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

OpenID是一种基于在Yahoo,Google和Flickr等常用Web服务上的现有帐户对用户进行身份validation的方法。

login到您的网站是基于成功login到远程站点。

您不需要存储敏感用户信息或使用SSL来保护用户login。

该库的当前PHP版本可以在这里find。

我使用OpenID 。

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

(OpenID的)明显的优点是。

  • 你不需要成为安全专家。
  • 用户信任他们的信息的大网站。
  • 你可以请求(昵称等)的东西,但用户必须join。
  • 你不必担心:
    • 注册过程
    • 丢失/忘记密码

安全地执行用户身份validation而不依赖于框架(或第三方库,如OpenID)为您执行此操作并非轻而易举的事情。

在10,000英尺的概况下,您必须决定:

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

这个答案中的信息与2015年5月9日相关并且是最新的,并且可能因密码哈希竞争的结论而过时

主要select器

通常,用户名和电子邮件地址比ID号码好。

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

您可以决定是否将电子邮件地址视为秘密。 用户通常喜欢不被暴露给垃圾邮件发送者,骗子和巨魔。

密码散列

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

超越Bcrypt

有时开发人员喜欢创造性(例如添加一个“胡椒”,通常意味着使用静态密钥进行预哈希或HMACing密码),并超越标准实现。 我们自己做了这个,但非常保守。

对于我们的内部项目(其安全性比大多数人的博客高得多),我们编写了一个名为PasswordLock API封装,首先使用sha256对密码进行散列,然后对原始散列输出进行base64编码,然后传递base64编码散列到password_hash() ,最后使用正确实现的encryption库对bcrypt散列进行encryption 。

重申, 我们encryption密码哈希而不是胡言乱语。 这给了我们在泄漏情况下更灵活(我们可以解密然后重新encryption,因为我们知道密钥)。 另外,我们可以在同一个数据中心的独立硬件上运行我们的networking服务器和数据库,以减轻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);

密码validation与PasswordLock

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

进一步阅读

  • 安全问题:将Bcrypt与其他哈希函数结合在一起
  • password_hash
  • password_verify
  • password_compat (用于PHP <5.5.0)

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

OpenID很棒,或者如果你打算自己推出,至less应该使用一个已build立的库,然后按照文档!

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

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

即使由于不增加哈希的大小而增加“成本”,但用于哈希存储的字段大小也是恒定的,但是生成它所需的迭代次数是不变的。

使用HTTP AUTHlogin

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

一旦通过身份validation,对于PHP ,您只需使用$_SERVER['PHP_AUTH_USER']来检索在身份validation期间使用的用户名。

与在脚本级别处理解决scheme相比,这可以是更快,有时更灵活的解决scheme,前提是需要有关用户的有限信息,因为提供给用户的所有信息都是用于login的用户名。

但是,除非您使用脚本语言(如下所述)实施完整的HTTP AUTHscheme,否则忘记将validation集成到HTML表单中。

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

您实际上可以通过您的脚本语言中模拟HTTP Basic Auth来扩展它。 唯一的要求是你的脚本语言必须能够发送HTTP头到HTTP客户端。 有关如何使用PHP完成此操作的详细解释可以在这里find:( 更多关于PHP和HTTP AUTH )。

您可以使用典型的身份validation模式,文件存储,甚至是PHP会话或cookie(如果信息不需要持久化)来扩展上面的文章,给您使用HTTP AUTH更多的灵活性,但仍然保持一些简单性。

下降到HTTP AUTH

  1. HTTPauthentication的主要缺点是注销可能带来的复杂性。 清除用户会话的主要方法是closures浏览器,或者使用403 Authentication Required来传递标题。 不幸的是,这意味着HTTP AUTHpopup窗口返回到页面,然后要求用户重新login或点击取消。 考虑到可用性时,这可能无法正常工作,但可以使用一些有趣的结果(即,使用Cookie和HTTP AUTH的组合来存储状态)解决问题。

  2. HTTP AUTHpopup窗口,会话和HTTP头处理由标准的浏览器实现决定。 这意味着您将被困在该实现(包括任何错误),而没有解决方法的可能性(不像其他替代scheme)。

  3. 基本身份validation也意味着服务器日志中显示auth_user和密码,然后您必须使用https的所有内容,否则用户名和密码也会以纯文本的方式在每个查询上通过networking。

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

例如,假设这是您现在validation用户的方式:

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

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

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

…您将能够快速轻松地重新保护您的应用程序。 给自己一个“正确的方式”做安全,你将不大可能造成重大的安全失误。

最好的身份validation是利用多因素身份validation,理想情况下,所有安全性敏感的login是一个无令牌的版本。

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

伊戈尔S