V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
NowTime
V2EX  ›  PHP

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

  •  
  •   NowTime · 2021-03-03 21:55:28 +08:00 · 1987 次点击
    这是一个创建于 1356 天前的主题,其中的信息可能已经有所发展或是发生改变。

    概述

    该网站并非前后端分离项目,通过 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 然后中间件之类的改一下验证


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

    先谢谢大家了 : )

    第 1 条附言  ·  2021-03-05 08:51:48 +08:00
    谢谢各位的建议,实在不行,可能得花点时间转换为前后端分离的项目
    11 条回复    2021-03-05 08:51:11 +08:00
    westoy
        1
    westoy  
       2021-03-03 22:02:16 +08:00
    php.ini 里有参数可以支持通过 GET 传递 session id

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

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

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

    能啊

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

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

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

    当然,referer 是不可靠的,但并没有比楼主的方法更不可靠。实在需要安全的话可以做成一次一密,即 token 使用一次就作废,下个页面的尾巴是新 token,这就无机可乘了。
    also24
        5
    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
        6
    falcon05  
       2021-03-04 00:21:39 +08:00 via iPhone
    不能存放在 Cookie,那就将 token 存 localstorage,每次请求附在请求头,有些 jwt 就是这样用的
    also24
        7
    also24  
       2021-03-04 00:22:41 +08:00
    @falcon05 #6
    连 Cookie 都不能用的场景,我觉得大概率 localStorage 也是一起被干掉了的。
    falcon05
        8
    falcon05  
       2021-03-04 00:23:30 +08:00 via iPhone
    不过不是单页应用,这样改的话需要点技巧
    just1
        9
    just1  
       2021-03-04 01:58:04 +08:00 via Android

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

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

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

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


    @imdong 这个方法可以考虑下
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1086 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 19:25 · PVG 03:25 · LAX 11:25 · JFK 14:25
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.