验证没有会话的系统 - 只有cookie - 这是否相当安全?

Mar*_*vić 6 php security authentication cookies

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

我在考虑做这样的事情:

  1. 从userId + expirationTime构建的字符串中获取哈希MAC(sha256),并从一些秘密字符串和$ _SERVER ['HTTP_USER_AGENT']构建密钥字符串.
  2. 从userId + expirationTime获取散列MAC(sha256),并作为先前制作散列的密钥(来自步骤1).
  3. 从userId | expiration |构建字符串 和先前制作的哈希(来自第2步).
  4. 使用'rijndael-256'算法加密给定的字符串(来自步骤3).(mcrypt函数族).
  5. 编码到base64.
  6. 设置具有给定值的cookie.

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

PS从敏感数据cookie只包含userId.

编辑: 好的,清除一些事情.我正在尝试制作不依赖于会话的"安全"auth系统.有问题的应用程序或多或少构建为纯粹的restful api.

第2步:

问题: "Fu的协议没有提供这个问题的答案.Fu的协议中只有一个密钥,即服务器密钥.一个简单的解决方案是使用此服务器密钥加密每个cookie的数据字段;但是,这种解决方案并不安全."

解决方案: "我们对此问题的解决方案简单而有效.我们建议使用HMAC(用户名|到期时间,sk)作为加密密钥.此解决方案具有以下三个良好属性:首先,加密密钥是唯一的因为用户名和到期时间,每个不同的cookie.请注意,每当创建一个新的cookie时,cookie中都会包含一个新的过期时间.其次,加密密钥是不可伪造的,因为服务器密钥是保密的.第三,每个cookie的加密密钥不需要服务器端或cookie内的任何存储,而是由服务器动态计算."来自纸张"安全Cookie协议"由Alex X. Liu,Jason M科瓦奇

第4步: 加密数据(看起来像这样:'marko@example.com|34234324234|324erfkh42fx34gc4fgcc423g4'),这样即使客户也无法准确知道内部的内容.

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

Not*_*tMe 10

我会咬人的.

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

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

密钥本身应该使用某种机制进行混淆.混淆的原因仅仅是如果原始用户或其他人决定检查该值,则更难以猜测其他密钥可能具有的值.例如,如果密钥是您的用户ID(不推荐)并且您正在使用递增的int,则猜测其他用户密钥是微不足道的. 我想强调,对密钥进行模糊处理(甚至是彻底加密)绝对不能防止被劫持的会话.它所做的只是让其他人会话密钥更难猜测.

也就是说,我认为密钥应该与您的用户ID无关,而是与生成的GUID之类的其他近似随机值.坦率地说,基本64编码的GUID与加密用户ID +时间完全相同.只是一个在服务器上的计算密集程度高于另一个.

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

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

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

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


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

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

  • +1"你发布的方法是浪费时间." 我们已经有很多简单的方法以正确的方式进行身份验证,实际上没有任何理由不这样做.(除了懒惰.) (2认同)
  • @jathanism:我不确定这是懒惰,因为有些人在他们的解决方案上付出了很多努力.我认为这是更好的捕鼠器综合症.;) (2认同)
  • @Marko:关注这个领导者.关闭会话,为每个API用户提供他们传入的基本64位编码guid以进行身份​​验证.对于每个数据库调用,验证id是否可以访问它们正在调用的函数.此外,打开SSL.接下来,让用户可以在需要时生成新ID.大多数大个子都是这样玩的.在这种情况下,ID是在"登录"过程中不发送给它们的秘密,它可以放在配置文件中.噗,没有会话,它和其他任何东西一样安全. (2认同)