开发安全的PHP登录和身份验证策略

时间:2009-12-16 20:19:44

标签: php security authentication session cookies

我正在为一个新的PHP站点开发一个登录和身份验证系统,并且已经阅读了各种攻击和漏洞。但是,它有点令人困惑,所以我想检查一下我的方法是否有意义。

我计划存储以下数据:

  • 在会话中:用户ID,哈希+盐渍HTTP_USER_AGENT

  • 在Cookie和数据库中:随机令牌,散列+盐渍标识符

在每一页上,我都计划执行以下操作:

  1. 如果会话存在,请使用该身份验证进行身份验证。检查HTTP_USER_AGENT是否与存储会话中的匹配。

  2. 如果不存在会话,请使用cookie进行身份验证。检查Cookie中的令牌和标识符是否与数据库中的令牌和标识符匹配。

  3. 如果Cookie无效或不存在,请让用户登录。

  4. 这有什么明显的缺陷吗?只要我在cookie中设置超时,我应该相当安全,对吧?有什么我想念的吗?

    非常感谢提前。

8 个答案:

答案 0 :(得分:12)

一些随意的想法:

  1. 如果我窃取了您的某个用户的cookie(通过在您的网站中注入一些JS代码使用XSS攻击)该怎么办?然后,我将落入案例2.因此能够登录。恕我直言,如果您想要真正安全的身份验证,请不要使用“记住我”类型的cookie来存储用户凭据。
  2. 如果您确实将凭据存储在cookie中,请不要将密码存储为明文。
  3. 检查HTTP_USER_AGENT是阻止会话劫持的良好开端,但也许你可以将它与IP地址结合起来?与你的目标相比,在同一台主机上要比使用相同的浏览器困难得多。
  4. 但无论如何,感谢您花时间考虑良好的身份验证方案。很多PHP开发人员都没有。

    编辑:为了记录,让我在这里澄清一点:在这个幻想中有两个饼干。一个由PHP自动设置以传播会话ID(有时,我们看到网站将其放入URL,例如www.example.com/page.php?sessionId = [...]),第二个由您创建为了存储用户凭据并在会话丢失时对其进行身份验证。 XSS攻击适用于两者,即攻击者可以窃取会话cookie并劫持会话(生命周期有限),或者窃取凭证cookie并稍后进行身份验证。

答案 1 :(得分:2)

不应该。 php会话存储在您的服务器上 而不是用户。 php简单地留下指向它的会话cookie。如果您不在共享主机上,则甚至不需要对会话进行哈希处理。

答案 2 :(得分:2)

将cookie存储在数据库中是一个HORRILBE的想法。这意味着如果攻击者有一个SQL注入漏洞,他可以立即获得访问权限,而无需破解哈希密码。

说到你需要使用sha256作为密码,如果你使用md5(),你在技术上容易受到攻击,你可能会被发给一个CVE号码。

永远不会生成自己的会话ID,使用session_start()和$ _SESSION超级全局。

这是一种重定向人的安全方式。如果你没有在header()之后死掉,其余的php代码仍然是STILL EXECUTED,即使它没有被普通的浏览器显示(黑客仍然看到它)。

header("location: index.php");
die();

说实话,如果安全性让您感到困惑,请不要编写安全系统。人们已经为PHP单独编写了1,000多个登录系统,而且大多数都是易受攻击的。该项目有一个安全的身份验证系统: http://code.google.com/p/michael-the-messenger/downloads/list

答案 3 :(得分:1)

取决于你想要的安全......

跨站点漏洞: 让我们说另一个站点指示浏览器向您的站点提交一个表单,如果该用户已经登录表单提交就可以发布垃圾邮件(或更糟糕)。您需要为每个表单检查referer和生成的隐藏formID,以防止这种情况发生。

第二:如果你有高到中等的流量,sessionID可以重复甚至猜测,我会检查存储在用户cookie中的二手生成的ID。

答案 4 :(得分:1)

该方案在某些方面似乎不必要地复杂,因为增加的复杂性不会在功能或安全性方面获得任何好处。

  1. 浏览器发送的任何数据(例如Cookie,用户代理)都是可欺骗的。检查用户代理只有在攻击者与欺骗用户位于同一NAT后面且攻击者使用其他浏览器但不想更改用户代理时才会有所帮助。
  2. 会话使用cookie或URL查询参数存储会话ID客户端。如果您想延长会话的生命周期,请使用session_set_cookie_params使会话cookie保持更长时间。
  3. 用户代理不是机密数据,因此无需进行散列。

    会话cookie +检查远程IP无法捕获的攻击是:

    1. 攻击者与用户在同一NAT后面
    2. 盲注入攻击,攻击者欺骗用户的IP。尽管是只写的,但这些仍然会造成一些损害。
    3. 使用用户自己的浏览器的攻击,例如cross-site request forgery(CSRF)。
    4. 如果你可以找到一种向用户的浏览器发送挑战的方法,可以防止

      2),在完成请求之前必须对其进行响应,但是当你没有编写客户端时这很棘手。使用AJAX可以完成。 3)(如MindStalker所述)可以通过检查Referer头来防止,因为CSRF攻击不能影响任意头,并且XMLHttpRequest不允许设置Referer头(根据{ {3}},虽然实现可能不符合要求)。使用iframe,可能会绕过Referer检查。此外,可能会在客户端阻止Referer标头。

答案 5 :(得分:1)

大多数网站只使用PHP会话;会话数据($ _SESSION)位于您的服务器上的a file。发送到浏览器的所有内容都是会话ID。请务必重新生成每个请求的会话(session_regenerate_id)。你不需要发送两个cookie或任何东西。

这不太容易受到会话劫持的影响,因为每个请求都是一个新ID,因此攻击者拦截的旧版本是无用的。

显然,最好的解决方案是在整个会话期间使用SSL。

答案 6 :(得分:0)

恕我直言,成功登录后更改会话信息也很重要。由于注入,不能保存数据库中的会话信息。

答案 7 :(得分:0)

- 使用sha1加盐 - 当然,您必须定义每个表单都不安全,因此每个表单都使用了令牌。您创建每个表单条目并使用preg_match清理它。一个叫做卫生的过程。