V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
black11black
V2EX  ›  问与答

各位分享一下登录验证码的实现细节?

  •  
  •   black11black · 2020-12-20 08:33:38 +08:00 via Android · 2784 次点击
    这是一个创建于 1424 天前的主题,其中的信息可能已经有所发展或是发生改变。
    如题,关于登录验证,之前发过一个帖子,询问前端验证码是否有意义,当时问那个问题有两个考虑,其一是我不了解 js 模块经过混淆后在生产级别的安全性,其二是我觉得后端生成验证码的话理论上可以成为饱和攻击对象,基本靠部署引擎拦截,跟业务无关了。(因为我没有被这么攻击过,纯粹是猜想)

    当时回帖里诸位认为前端验证码搞不起,我也就放弃了。

    这个贴想问一下各位的验证码细节上都是怎么实现的,因为想要无状态部署,各位看看我现在的方案行不行。我现在用的方案是后端生成验证码的同时生成 hash 作为令牌,与验证码图片一同发送至前端。(比如一个简单的算法,将随机生成的验证码重复一次再经过 sha1),而前端进行验证码检验的时候,通过验算决定是否放行。

    感觉理论上只要 hash 算法保密应该这套系统就是安全的?
    26 条回复    2020-12-22 08:51:56 +08:00
    sampeng
        1
    sampeng  
       2020-12-20 09:29:01 +08:00 via iPhone
    验证在服务端进行,客户端只是体验
    eason1874
        2
    eason1874  
       2020-12-20 09:29:32 +08:00
    无状态,加盐加时间戳能防破解,但是在有效期内有重放问题,适合的场景不多。
    lpts007
        3
    lpts007  
       2020-12-20 09:29:37 +08:00 via Android
    “而前端进行验证码检验的时候,通过验算决定是否放行。”

    这意思还是前端判断是否正确?
    imdong
        4
    imdong  
       2020-12-20 09:36:19 +08:00 via iPhone
    方案一(常见)
    将验证码存于用户 Session 之中(具体方法有很多),验证后删除。

    方案二(和你的做法相似)
    生成的验证码进行加密或不可逆哈希(应该加盐防止彩虹表攻击),然后应该绑定一个时间与唯一 ID,如一分钟内有效,验证成功后将唯一 ID 存起来,一分钟内不允许使用,防止重放攻击。
    jzmws
        5
    jzmws  
       2020-12-20 09:58:45 +08:00
    @imdong 相对来说第二种更好一些, 0202 年基于 session 认证有很多坑, 前后端跨域在 chrome 80 以上同步不到 session

    配合配合 redis 就很方便了 ,不用去管理验证码失效的问题
    1. 获取验证 把图片显示给前端的同时,并且带上当前验证码存储的 key 值
    2.前端提交时候 用验证码的 key 值和输入内容
    3.通过 key 去取 redis 中内容和输入比较
    gam2046
        6
    gam2046  
       2020-12-20 11:52:42 +08:00
    前端是不可信的,任何在客户端运行的代码都不可信,服务端不能假定任何输入数据是没有被篡改过的。

    因此如果是前端通过某种离线算法验证,那么整套验证机制就形同虚设了。未经授权的访问都可以通过相同的路径访问,因为服务端无法区分。
    westoy
        7
    westoy  
       2020-12-20 12:07:28 +08:00
    哪有啥真正的无状态啊, 你就算用 secure cookie 做 session, 用户改个密码要多个设备同步登出不还得服务端保存一个 token 做检验嘛
    johnsona
        8
    johnsona  
       2020-12-20 15:36:25 +08:00 via iPhone
    @westoy 我之前总监就被网上博客忽悠瘸了,要什么无状态,自己也说不清楚,服务端不存状态的话,很多业务场景没办法给他做
    Lonely
        9
    Lonely  
       2020-12-20 17:36:31 +08:00 via iPhone
    @johnsona 状态存到其他地方罢了,服务本身不存状态
    wellsc
        10
    wellsc  
       2020-12-20 17:38:47 +08:00
    @johnsona 搞个分布式 session 之类的东西,业务容器本身还是无状态的,你们总监自己没理解罢了
    black11black
        11
    black11black  
    OP
       2020-12-20 21:34:12 +08:00 via Android
    @lpts007 表述错误,意思是前端发送这个请求时,(后端)完成检验
    black11black
        12
    black11black  
    OP
       2020-12-20 21:37:53 +08:00 via Android
    @johnsona 这有啥说不清楚的,当然要无状态,要不然服务可用性怎么拉上去?
    johnsona
        13
    johnsona  
       2020-12-20 21:42:13 +08:00
    @black11black 不是说你这个业务,我是说有的业务,比如有的人说 jwt 好,不用存后端,无状态,验证签名就好了,还可以存数据,不会被窜改,可以横向扩展,那退出登录怎么做,revoke jwt 还是要加一个黑名单,这就有的人乱搞的无状态
    johnsona
        14
    johnsona  
       2020-12-20 21:43:00 +08:00
    @wellsc 我的主张一直都是分布式 session
    black11black
        15
    black11black  
    OP
       2020-12-20 21:45:48 +08:00 via Android
    @johnsona jwt 退出登录确实不好解决,不过本身不会引起安全问题,我认为可以干脆不做这块。

    @imdong 所以看来为了防止重放,无论如何还是要保存一个节点间同步状态。因为理论上希望系统部署越简单越好,能只用 sql 就不多加服务,看来是不行了。
    black11black
        16
    black11black  
    OP
       2020-12-20 21:48:15 +08:00 via Android
    @johnsona 分布式 session 具体实现上怎么操作?维护一个进程间通信协议?或者 nginx 绑定 ip ?
    wellsc
        17
    wellsc  
       2020-12-20 22:06:26 +08:00
    @black11black 可以用 redis 实现,和缓存差不多道理的
    johnsona
        18
    johnsona  
       2020-12-20 22:35:54 +08:00 via iPhone
    @black11black 百度
    johnsona
        19
    johnsona  
       2020-12-20 22:36:43 +08:00 via iPhone
    @black11black 感觉你想的太复杂或者可能受 tomcat 影响吗
    johnsona
        20
    johnsona  
       2020-12-20 22:58:36 +08:00 via iPhone
    @black11black 你怎么跟产品解释说不做退出登陆,产品会觉得这么简单的功能
    Oceanhime
        21
    Oceanhime  
       2020-12-20 23:08:12 +08:00
    可以看看 vcaptcha 的离线验证方案, 和你的意思感觉差不多?
    https://www.vaptcha.com/document/faq.html#%E7%A6%BB%E7%BA%BF%E9%AA%8C%E8%AF%81%E6%A8%A1%E5%BC%8F%E5%8E%9F%E7%90%86
    非利益相关
    black11black
        22
    black11black  
    OP
       2020-12-21 05:11:18 +08:00 via Android
    @johnsona 不不,退出当然可以做,我的意思是即使后端没法验证退出,实际上倒不构成安全问题
    ysc3839
        23
    ysc3839  
       2020-12-21 15:07:28 +08:00 via Android
    我最近也有类似需求,最终选择的方案是 Encrypted JWT,有效期设为 2 分钟,使用后加到缓存中避免重放攻击。

    登录后也是返回 JWT,退出登录的话是禁止多处登录,然后数据库里面存一个 token valid since 时间戳,每次登录或者退出登录直接更新这个。
    johnsona
        24
    johnsona  
       2020-12-21 15:26:46 +08:00 via iPhone
    @black11black 我当时就这么搞的,我让前段退出直接删除 token 就行了,我不要面子的吗?他们不懂还以为我不行,而且前段删除 token,这个 token 还没 revoke 呢
    black11black
        25
    black11black  
    OP
       2020-12-22 01:55:46 +08:00
    @ysc3839 token valid since 是指维护一个进程间共享缓存,退出登录以后把这个 token 设为 invalid ?
    ysc3839
        26
    ysc3839  
       2020-12-22 08:51:56 +08:00 via Android
    @black11black 只是存时间戳,在此时间戳之前签发的 token 都无效。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5470 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 07:01 · PVG 15:01 · LAX 23:01 · JFK 02:01
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.