【问题标题】:Authenticate system without sessions - Only cookies - Is this reasonably secure?在没有会话的情况下验证系统 - 只有 cookie - 这是否相当安全?
【发布时间】:2011-10-01 16:32:41
【问题描述】:

我对您对此安全问题的建议/意见感兴趣。

我正在考虑做这样的事情:

  1. 从由 userId + expirationTime 构建的字符串中获取哈希 MAC (sha256),并作为由某个秘密字符串和 $_SERVER['HTTP_USER_AGENT'] 构建的密钥字符串。
  2. 从 userId + expireTime 中获取哈希 MAC (sha256),并作为之前生成的哈希(从第 1 步开始)的密钥。
  3. 根据 userId|expiration| 构建字符串和之前制作的哈希(从第 2 步开始)。
  4. 使用“rijndael-256”算法加密给定的字符串(从第 3 步开始)。 (mcrypt 系列函数)。
  5. 编码为 base64。
  6. 使用给定值设置 cookie。

你怎么看。这个可以吗? 我还可以通过 $_SERVER['HTTP_USER_AGENT'] 检查实现什么,以确保 cookie 不被盗(IP 地址除外)?

附:来自敏感数据的 cookie 将仅包含 userId。

编辑: 好的,清除一些东西。 我正在尝试制作不依赖会话的“安全”身份验证系统。有问题的应用程序或多或少地构建为纯 RESTful api。

第 2 步:

问题: “傅的协议没有对此提供答案 题。傅的原型中只有一把钥匙—— col,即服务器密钥。一个简单的解决方案 化是使用这个服务器密钥来加密数据字段 每个cookie;但是,此解决方案并不安全。”

解决方案: “我们对这个问题的解决方案简单而有效。 我们建议使用 HMAC(用户名|过期时间, sk) 作为加密密钥。该解决方案具有以下 降低三个良好的性能。一、加密密钥 由于用户的原因,对于每个不同的 cookie 都是唯一的 名称和到期时间。请注意,每当一个新的 cookie 被创建,新的过期时间被包含在 饼干。二、加密密钥不可伪造 因为服务器密钥是保密的。三、加密 每个 cookie 的 key 不需要任何存储 服务器端或在 cookie 中,相反,它是 com- 由服务器动态放置。 " 摘自 Alex X. Liu1、Jason M. Kovacs 的论文“A Secure Cookie Protocol”

第 4 步: 加密数据(看起来像这样:'marko@example.com|34234324234|324erfkh42fx34gc4fgcc423g4'),这样即使客户也无法确切知道里面是什么。

第 5 步: Base64 编码只是为了使最终值漂亮。

【问题讨论】:

  • 第2-4步需要什么?您不会通过在其中包含嵌套哈希来使哈希更安全,出于性能原因,最好只运行一次哈希。
  • 大多数会话管理设置使用 cookie 来存储会话 ID,并使用 GET ID 作为备份(如有必要并在会话设置中指明)。
  • @Marko Jovanovic:你不能 100% 确定 cookie 劫持。
  • @Marko - 那么你得到的保护只不过是默默无闻的安全,意思是,几乎没有。不管密钥的算法多么花哨,有人可以用http拦截和劫持。
  • Cookies 不是安全功能。

标签: php security authentication cookies


【解决方案1】:

我会咬人的。

为了保持任何类似的状态,您需要使用某种类型的键来识别用户。该密钥作为 cookie 或通过查询字符串参数发送到浏览器。

现在,可以在 Web 服务器本身(会话)内部或通过检查其他一些存储机制(通常是数据库记录)来验证该密钥。

应使用某种机制对密钥本身进行模糊处理。混淆的原因很简单,如果原始用户或其他人决定检查值,则更难猜测其他键可能具有的值。例如,如果键是您的用户 ID(不推荐)并且您使用递增整数,那么猜测其他用户键是微不足道的。 我想强调的是,对密钥进行混淆(甚至完全加密)绝对不能防止会话被劫持。它所做的只是让猜测其他人的会话密钥变得更加困难

也就是说,我认为密钥应该与您的用户 ID 完全无关,而是其他一些接近随机的值,例如生成的 GUID。坦率地说,base 64 编码的 GUID 与加密用户 id + 时间的安全级别完全相同。只是一个在您的服务器上的计算量比另一个更大。

当然,这个密钥可以根据每个请求而改变。浏览器发布一些内容,您生成一个新密钥并将其发回。如果浏览器发布了一个过期的密钥,然后记录它并将它们踢回登录屏幕。这应该在一定程度上防止重放攻击。但是,它引入了其他挑战,例如在各种浏览器上使用“后退”按钮。所以,你可能不想走这条路。

也就是说,您不能依赖客户端 IP 地址,因为同一用户可能会使用不同的 IP 发送后续请求。您不能依赖浏览器指纹识别,因为任何体面的黑客工具都会捕获它并提交相同的值,无论他们使用什么。

现在,如果您真的想这样做,您应该打开 SSL。否则你就是在浪费时间。整个对话(从登录屏幕开始)需要加密。如果不是,那么有人可以简单地侦听该 cookie,立即重播并劫持会话。关键是他们不需要知道其中包含的值来使用它们。所以你所拥有的所有这些散列等只是绒毛,会增加你的服务器负载。

我说过要使用 SSL 吗? ;) 这将从对话开始加密流量,并且攻击者无法重放相同的数据包,因为他们必须与服务器协商自己的握手。这意味着您所要做的就是确保您使用的任何会话 ID 都是不可猜测的,这样一个登录用户就无法接管另一个用户的会话。


所以,总结一下:你发布的方法是浪费时间。

您最好获得 10 美元的 SSL 证书并使用 base 64 编码的 GUID 作为会话 ID。你如何在你的服务器上存储会话信息并不重要……除非在负载平衡的情况下。此时它需要处于进程外并由数据库服务器支持..但这是另一个问题。

【讨论】:

  • 谢谢 :) 这样做的全部目的是使应用程序尽可能无状态和可扩展(我认为其中很大一部分是丢弃会话(无论它们可能保存在哪里)仍然在服务器上)),并使用客户端保存“状态”。再次感谢您。
  • @Chris Lively - 只是想知道这里的一些事情。如果我正在使用会话(PHP 会话),可能不会通过任何直接或间接方式与特定用户的 ID 或任何其他类似的东西绑定,并且我正在使用 HTTPS,那么我是否应该探索自定义会话 ID 作为反对 PHP 生成的 PHP Session ID?
  • +1 表示“您发布的方法是浪费时间”。我们已经有很多简单的方法来正确地进行身份验证,实际上没有理由不这样做。 (除了懒惰。)
  • @jathanism:我不确定这是懒惰,因为有些人在他们的解决方案中付出了很多努力。我认为这是更好的捕鼠器综合症。 ;)
  • @Marko:跟随领导者。关闭会话,为您的每个 API 用户提供一个 base 64 编码的 guid,他们传入该 guid 以进行身份​​验证。对于每个单独的数据库调用,验证 id 是否有权访问它们正在调用的函数。另外,打开 SSL。接下来,让用户有一种方法可以在需要时生成新 ID。大多数大个子都是这样玩的。在这种情况下,ID 是在“登录”过程中不会发送给他们的秘密,他们可以将其放入配置文件中。噗,没有会话,它和其他任何东西一样安全。
【解决方案2】:

@Marko 一些关于这种“cookie 中的会话”方法的安全性的问题:

首先,正如其他人所说,您需要安全连接。没有可行的方法来解决这个要求。这是必须的。

除此之外,在实施安全加密/身份验证系统方面还有很多陷阱。例如,您需要使 MAC 验证“恒定时间”,您需要注意如何实现加密/身份验证(操作模式、IV 创建等)。以此类推。

如果您不确定此类问题,我建议您查看 TCrypto(我维护):

TCrypto

它是一个小型的 PHP 5.3+ 键值存储库(默认使用 cookie 作为存储后端)。专为(可扩展的)“cookie 中的会话”使用而设计。随意使用它:) 另外,如果您对低级实现感兴趣,请查看代码。代码库不是很大,我想它会做得很好,展示了 PHP 应用程序中与加密相关的代码用法。

【讨论】:

  • 仅供参考; timoh 是 TCrypto 的开发者。
  • @WilboBaggins 没错。我的不好我没有在原始答案中说清楚(现在答案中提到了)。
猜你喜欢
  • 1970-01-01
  • 2016-09-22
  • 1970-01-01
  • 2023-02-23
  • 2013-02-24
  • 1970-01-01
  • 1970-01-01
  • 2020-06-16
  • 1970-01-01
相关资源
最近更新 更多