用于用户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
:
-
hash('sha256', $password, true);
-
base64_encode($step1);
-
password_hash($step2, PASSWORD_DEFAULT);
-
Crypto::encrypt($step3, $secretKey);
密码validation与PasswordLock
:
-
Crypto::decrypt($ciphertext, $secretKey);
-
hash('sha256', $password, true);
-
base64_encode($step2);
-
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
- 使用Apache: http : //httpd.apache.org/docs/2.2/howto/auth.html
- 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
-
HTTPauthentication的主要缺点是注销可能带来的复杂性。 清除用户会话的主要方法是closures浏览器,或者使用403 Authentication Required来传递标题。 不幸的是,这意味着HTTP AUTHpopup窗口返回到页面,然后要求用户重新login或点击取消。 考虑到可用性时,这可能无法正常工作,但可以使用一些有趣的结果(即,使用Cookie和HTTP AUTH的组合来存储状态)解决问题。
-
HTTP AUTHpopup窗口,会话和HTTP头处理由标准的浏览器实现决定。 这意味着您将被困在该实现(包括任何错误),而没有解决方法的可能性(不像其他替代scheme)。
-
基本身份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