V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
NowTime
V2EX  ›  PHP

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

  •  
  •   NowTime · Mar 3, 2021 · 2432 views
    This topic created in 1881 days ago, the information mentioned may be changed or developed.

    概述

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


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

    先谢谢大家了 : )

    Supplement 1  ·  Mar 5, 2021
    谢谢各位的建议,实在不行,可能得花点时间转换为前后端分离的项目
    11 replies    2021-03-05 08:51:11 +08:00
    westoy
        1
    westoy  
       Mar 3, 2021
    php.ini 里有参数可以支持通过 GET 传递 session id

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

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

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

    能啊

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

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

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

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

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


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

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

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

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

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


    @imdong 这个方法可以考虑下
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   5077 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 45ms · UTC 01:09 · PVG 09:09 · LAX 18:09 · JFK 21:09
    ♥ Do have faith in what you're doing.