这样将“有状态验证”改成“无状态验证”有问题吗

2021-03-03 21:55:28 +08:00
 NowTime

概述

该网站并非前后端分离项目,通过 Sesssion 判断是否登录,并且比较多 HTML 代码是通过 PHP 控制显示的,也有一些数据是通过 Ajax 请求的。

现在公司要求,即使用户 禁用 Cookie 也需要让用户能正常登录、使用(具体为什么也不好说)

PS:因为页面比较多,暂时也不太现实改成前后端分离的模式

目前想到的解决方法

  1. 用户登录,跳转的 URL 后面再加上如 token 参数,token 由服务器生成长度 32 位,并储存在 Redis 里,TTL 设置为 86400 秒,大概结构就是

    key value
    user:info:服务器生成的 Token 序列化后的一些用户数据如用户 ID等数据
  2. 然后计划用 JS 将页面中 a 标签链接,如果包含了项目域名 www.baidu.com,如:https://www.baidu.com/test 的后面追加一个 token 参数(取当前页面地址栏 token 值),就变成了:https://www.baidu.com/test?token=xxxxxxxxxx

  3. 就像之前说的,页面中还有 Ajax 请求的,接口有 CSRF 验证,因为禁用了 Cookie 故请求失败( HTTP 状态码 419 ) 。暂时只想到的就是 Ajax 请求的时候也加上 Token 然后中间件之类的改一下验证


以上的做法不知道有大家有什么看法(比如有无安全方面的问题),或者有更好的建议

先谢谢大家了 : )

1896 次点击
所在节点    PHP
11 条回复
westoy
2021-03-03 22:02:16 +08:00
php.ini 里有参数可以支持通过 GET 传递 session id

不过这个可能会泄漏 session id, 导致安全问题

比如某人把带自己 session id 的 URL 发给其他人, 或者你们网站可以插入外部资源, 对方通过日志 referer(可以设置同源策略, 但部分老浏览器就糟了)
NowTime
2021-03-03 22:13:43 +08:00
@westoy 你这个建议可以,这样省了自己再改动代码 。

就是你说的安全问题,可能是个问题,不过我想了下,能否将用户一些特征如 IP 、UA 写入 Session,然后在判断是否登录那里,再判断下当前访问的 IP 、UA 是否与 Session 里的相同
westoy
2021-03-03 22:24:14 +08:00
@NowTime

能啊

但是捆绑 IP 会带来一个副作用, 有些小区宽带和二级运营商的用户 IP 是满地图飞的, 不是固定的

捆绑 UA 的话, 对方能通过跨站资源获取触发访问的老浏览器用户的 session id, 那也能获取 UA 啊
Rocketer
2021-03-04 00:09:51 +08:00
这个还是有状态验证,只是 session id 的传递方式变了。

我有个想法不知是否可行——既然所有的页面都是服务端渲染的,那你就在所有页面的 URL 后面加上个 token,然后服务端通过 referer 来读取。这样只需在出入口加两个中间件,出口负责加尾巴,入口负责读取尾巴并重建 session 就可以了,原有程序基本无需改动。

当然,referer 是不可靠的,但并没有比楼主的方法更不可靠。实在需要安全的话可以做成一次一密,即 token 使用一次就作废,下个页面的尾巴是新 token,这就无机可乘了。
also24
2021-03-04 00:16:28 +08:00
贴两个链接供参考:
https://www.php.net/manual/zh/session.idpassing.php

https://www.inbreak.net/archives/171


另 @Rocketer #4,实际上你这恰好说到了把 session id 写入 URL 的风险之一:
Referer 由于没有跨域限制,在页面引用、请求了其它站点的资源,或者跳转到了外链的时候,session id 会更容易泄漏。
falcon05
2021-03-04 00:21:39 +08:00
不能存放在 Cookie,那就将 token 存 localstorage,每次请求附在请求头,有些 jwt 就是这样用的
also24
2021-03-04 00:22:41 +08:00
@falcon05 #6
连 Cookie 都不能用的场景,我觉得大概率 localStorage 也是一起被干掉了的。
falcon05
2021-03-04 00:23:30 +08:00
不过不是单页应用,这样改的话需要点技巧
just1
2021-03-04 01:58:04 +08:00

想到一个奇技淫巧
原有页面通通用 iframe 来加载,sessionid 在 get 参数里。父页面用 history mode 来更新 URL,url 是 iframe 的地址去掉 session 。这样就能够不在浏览器地址栏显示了

不过 ajax 还得处理一下,那个得手动带上 sessionid
imdong
2021-03-04 07:52:23 +08:00
https://www.qs5.org/Post/653.html
曾经写过这样一篇文章,利用缓存机制实现。
NowTime
2021-03-05 08:51:11 +08:00
@westoy 这确实是个问题
@Rocketer 这个办法好,感觉就是有点复杂,还有就是有些页面打开后还会使用 Ajax 请求接口

@falcon05 SPA 的话使用这个方法很好,可惜项目并不是。
@also24 localStorage 倒是没有干掉

@just1 我们的应用就是通过别的网站用 iframe 加载的,但是还是怕用户复制项目中带有 Token 的链接给其他人


@imdong 这个方法可以考虑下

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/758186

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX