【问题标题】:secure web authentication using cookies使用 cookie 的安全 Web 身份验证
【发布时间】:2011-10-06 22:08:01
【问题描述】:

我正在开发一个 PHP Web 应用程序,该应用程序的主要重点是安全性。到目前为止,我已将身份验证数据存储到 2 个 cookie 中:

  • 一个用于唯一哈希字符串(30 个字符)的 cookie
  • 一个 cookie 用于唯一 id(保存 cookie 信息和用户 id 的 mysql 数据库表的主键)

Db 表如下所示:

  • 用户(user_id、用户名、密码)
  • Cookie(cookie_id、user_id、哈希、时间、ip)

当用户访问页面时,应用程序会检查客户端上的现有 cookie(cookie 检查)并将它们与数据库表 Cookies 进行比较。如果哈希字符串和 id 匹配,则扩展会话,如果不匹配,则销毁会话(如果存在)并提示用户登录。它还通过将当前时间戳与上次活动的时间戳进行比较来检查会话是否过期。

当用户登录时生成一个哈希字符串并存储在数据库中(当前时间戳和IP也被存储)。然后将新生成的行的主 ID 和哈希字符串存储到两个 cookie 中并用于身份验证。

我想通过限制登录和 cookie 检查尝试来实施额外的安全措施,以防止字典或暴力攻击。我想实现当用户 N 次登录失败或验证 cookie 时他被阻止 20 分钟。但是,如果我使用 IP 执行此操作,我可能会阻止使用该 IP 的每个用户。

当失败尝试超过 X 次时,我可以锁定特定用户帐户,但问题是当攻击者未提供有效用户名时(因此我必须将整个 IP 阻止 N 分钟)。

登录表单也有验证码检查,但这只会减缓攻击速度(与拒绝登录尝试 X 分钟相比没什么)。

  • 是否有任何其他方法可以拒绝登录尝试而不阻止使用该 IP 的整个网络?
  • 当有 N 次 cookie 检查失败时,我是否应该拒绝登录尝试?
  • 如果用户 cookie 被盗,我使用 Cookie 表中的 IP 来防止重复使用它,因此 cookie 只能从与用户相同的 IP 使用。这是安全的还是我应该以其他方式做到这一点?

提前致谢,

PS:数据库中的所有密码都经过哈希处理,cookie 值在用于 db 查询之前已编码(因此无法注入)。

【问题讨论】:

    标签: php security web-applications authentication login


    【解决方案1】:

    我正在开发一个 PHP Web 应用程序,该应用程序的主要重点是 安全

    如果你关心安全你不应该自己实现身份验证,而是像 stackoverflow.com 一样使用 OpenID => http://www.codinghorror.com/blog/2008/05/openid-does-the-world-really-need-yet-another-username-and-password.html

    LightOpenID 是一个非常好的/简单的 openID 库 => http://gitorious.org/lightopenid

    我想实施额外的安全措施以防止字典或 蛮力攻击,通过限制登录和会话检查 尝试。我想实现当用户登录失败 N 次时 或验证他被阻止 20 分钟的 cookie。但如果我 使用 IP 执行此操作我可能会阻止使用该 IP 的每个用户 知识产权。

    P.S:我会使用 OpenID,但下面我会告诉我如何做到这一点。

    正如您所说,IP 的阻塞很糟糕,因为很多用户通过 NAT 共享相同的 IP。但是当您怀疑暴力攻击(来自 IP)时,我只会让他们仅在正确输入验证码的情况下进行身份验证。这样,在黑客被拒之门外的情况下,NAT 后面的用户仍然可以登录。

    登录表单也有验证码检查,但这只会减慢 攻击(与拒绝登录尝试 X 分钟相比没什么)。

    当您使用验证码保护您的网站时,如果密码长度足够长,入侵您的网站几乎是不可能的(您应该强制执行此操作)。因为假设您可以在 5 秒内解决一个验证码,即每分钟 12 个验证码。您可以做的是在多次尝试时锁定帐户。您向用户帐户发送了一个很长的字符串,他可以使用该字符串设置新密码

    【讨论】:

    • 不幸的是,OpenID 不是一个选项。暴力破解可以通过猜测用户名和密码或猜测存储在 cookie 中的会话 ID 来完成。因此,当使用已知用户名猜测密码时,我可以锁定帐户,但问题是用户名未知时。所以我只能锁定 IP(锁定整个网络),这是我试图避免的。
    • 为什么 OpenID 不是一个选项。要破解密码,您需要多次尝试使用相同的用户名。否则你永远不能蛮力破解这个(概率为零)。验证码停止暴力破解。然后黑客转移到不使用验证码的登录系统......
    • 这是给客户的,并且已经实现了登录系统。我同意在登录时使用验证码可以减慢暴力破解甚至停止它。但是,在检查现有会话/cookie 时,是否可以通过暴力破解?我是否需要限制 IP 的最大会话检查失败?或者我可以使用不同的方法吗? openID 如何应对?
    • cookie(session也是cookie)可以清除。谷歌等大型网站不使用验证码,因为它们对用户友好,但因为它是阻止攻击的唯一方法。
    • 我完全理解,我不明白的是如何在不阻塞整个 IP 的情况下阻止暴力破解会话 ID。当用户登录时(必须输入他的用户 + 密码),当每个 IP 有超过 2 次失败尝试时,您只需显示验证码。但是在验证会话/cookie时(当用户已经登录时)你不能这样做。如果你阻止IP你会阻止已经登录的用户。在有 3 个用户竞标购买的竞标网站上,锁定帐户并不是很好,因为您可能会在最后一分钟锁定另一个用户 :)
    【解决方案2】:

    安全不是靠复杂的代码来实现的,而是靠简单。与其自己发明会话处理,不如使用 php 的 builtin one

    此外,没有理由将用户名存储在 cookie 中,这样做只会使您的应用程序容易出现由于用户和会话不匹配而导致的各种漏洞。而是将用户 ID 与每个会话条目一起存储。

    您应该限制身份验证尝试(即密码输入),可能使用验证码,或者更好的是,根本不存储密码和use OpenID。此外,仅仅散列密码是不够的;确保use a salt

    【讨论】:

    • 我只存储一个散列和一个 cookie 表 ID,不存储用户名,甚至不存储用户 ID。我不使用会话的原因是当浏览器关闭时它们会被破坏。
    • @Simos Mikelatos 您编写的代码越多,其中出现错误的可能性就越大。将会话存储在两个位置是其中之一,即使做得正确,提供的安全优势也可以忽略不计,但很容易出现编程错误。
    • @jernej 您可以使用session.cookie_lifetime 配置cookie 生命周期,因此这并不是编写您自己的会话处理代码的理由。而且你极有可能搞砸一些事情,例如大幅降低会话 ID 的熵。
    猜你喜欢
    • 2023-03-31
    • 2020-06-16
    • 2014-07-31
    • 2012-08-01
    • 1970-01-01
    • 2016-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多