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

有没有什么前端验证码的成熟方案?

  •  
  •   LeeReamond · 2023-08-31 00:52:06 +08:00 · 3914 次点击
    这是一个创建于 445 天前的主题,其中的信息可能已经有所发展或是发生改变。

    首先,前端验证码和可靠二字完全不搭边我理解。但是后端验证码的话,后端首先需要进行一个 CPU 计算生成图片的过程,然后还需要维护一个对应状态,感觉成本有点高了,相比之下前端验证码对于后端来说就是无限轻量了。

    有没有一种可能性是走两套方案,先前端再后端?比如注册验证这种场景,现在国内一般都是要调 API 发手机验证码的,为了保护 API 几乎都需要前置经过某种验证才能调用 API ,那么有没有可能,在前几次验证码时是前端验证,后端 API 根据用户 IP 或者什么其他信息维护一个屏蔽表,调用次数达到一定程度后再使用稍微安全一些的后端验证码这样?

    这样前端的安全性要求其实也不高,能拦截 90%低端程序员就可以了。 有这样的项目吗?

    37 条回复    2023-09-01 09:20:01 +08:00
    yankebupt
        1
    yankebupt  
       2023-08-31 01:37:05 +08:00   ❤️ 2
    你自己就可以做一个
    首先图片是可以预生成的,你可以一次生成它 100W 张,扔服务器,扔CDN甚至让客户端预下载了都行
    然后你根据系统时间给出一个分段随机序号
    让客户端填完了把明文和序号发回来
    根据系统时间规则是因为对方如果 replay attack 会在 5-10 分钟内失效
    如果你想让客户端自己能判断对错,把明文的 Hash 也发过去让他自行验证。对面抓包看代码永远只知道 hash 不知道该填什么
    必须看图
    还不用维护状态
    yankebupt
        2
    yankebupt  
       2023-08-31 01:39:23 +08:00
    对了,扔 CDN 的话加个报复保护的 ip 限流……有很多人 cdn 被 D 的。
    dusu
        3
    dusu  
       2023-08-31 01:44:58 +08:00 via iPhone
    既然你觉得生成费劲成本高
    给你个笨但是又高效的办法
    为啥不提前生成一批验证码图片文件(总量为 36^长度)
    不暴露路径的情况下
    后端只需要生成 token
    然后前端随机来用呢?
    当然 还有很多可以优化的空间
    例如 o 和 0 可以去掉等等举一反三…
    yankebupt
        4
    yankebupt  
       2023-08-31 01:52:36 +08:00
    @dusu 这个方法和我刚才说的方法都有一个问题,就是 replay 攻击。
    都是可以填一次验证码,然后 5-10 分钟内利用一个序号无限申请,因为没状态……
    我那个还应该加上一条,不仅应该根据系统时间,还应该根据请求 ip 分段,最大程度防止 replay 。
    geelaw
        5
    geelaw  
       2023-08-31 04:26:28 +08:00 via iPhone
    @yankebupt #1 (经典计算机的)客户端不能自己验证,通常来说验证码的长度不足以阻挡离线枚举。

    如果是注册验证,一个简单的避免重放的思路是让验证码和注册信息绑定。当然我没有仔细想过这样做的问题,标准解决方案才是正道。
    0o0O0o0O0o
        6
    0o0O0o0O0o  
       2023-08-31 08:08:31 +08:00 via iPhone   ❤️ 1
    如果一定需要验证码,我建议且只建议 OP 购买并接入成熟服务,不要自研,你仅仅有图片验证码的概念就去自研的话约等于给攻击者送礼,包括 #1 - #4 。
    zachlhb
        7
    zachlhb  
       2023-08-31 08:13:16 +08:00 via Android
    可以用友验,极验这种服务的,前后端同时验证
    yyf1234
        8
    yyf1234  
       2023-08-31 08:26:43 +08:00 via iPhone
    极验不
    yyf1234
        9
    yyf1234  
       2023-08-31 08:27:04 +08:00 via iPhone
    就行了
    ShuWei
        10
    ShuWei  
       2023-08-31 08:38:48 +08:00   ❤️ 1
    考虑前端使用 wasm ,实时生成一个含语义理解的验证,比如实时生成并给出一个图片,让点击图片中特定内容的地方,然后验证坐标对不对。

    服务端生成和验证,其实真没有多大的压力,你可能想得有点多了

    或者,直接使用第三方的验证码服务,应该是最好的选择
    wu67
        11
    wu67  
       2023-08-31 09:16:30 +08:00
    我选择接入第三方的 sdk. 例如 阿里拉条公司 谷歌交通公司
    lanxiner
        12
    lanxiner  
       2023-08-31 10:04:57 +08:00
    近期正在研究验证码方案:
    建议用第三方
    阿里云、腾讯云都基本是按照使用量收费的, 非常便宜. , 但是不原生接入手机端,
    其他的网易云盾、极验这些做的比较成熟各个端都可以接, 但是价格相对比较高.
    用第三方的话基本上都有无痕验证, 他们有动态更新的风险识别算法,自动识别到有风险才会弹出验证码做进一步验证. (客户体验较高)
    mdn
        13
    mdn  
       2023-08-31 10:14:16 +08:00
    不行,后端并不知道接口是否经过前端认证之后发送的
    建议直接接入第三方验证,有无感验证,触发风控才需要弹窗验证
    manasheep
        14
    manasheep  
       2023-08-31 10:31:47 +08:00
    “感觉成本有点高了”,毛毛雨了。
    yankebupt
        15
    yankebupt  
       2023-08-31 11:03:00 +08:00
    @geelaw 我不太懂离线枚举,但是不是可以把 Hash 设置复杂点(比如多 Hash 嵌套几十层),客户端用户点提交后基本1秒之后才验证这种……
    反正服务端验证明文又不需要验证 Hash......

    但是离线反重放真的完全靠运气,对面上工具的话绝对没戏,所以只能防小白
    yankebupt
        16
    yankebupt  
       2023-08-31 11:11:28 +08:00
    @geelaw 要说非经典计算机,要有用的话肯定是把验证部分扔TEE里然后非对称加密握手拿到密钥,但又要买证书巨贵而且小程序之类还不能用……
    Maerd
        17
    Maerd  
       2023-08-31 11:15:54 +08:00
    直接接入第三方验证吧,前端验证基本拦不住爬虫
    yankebupt
        18
    yankebupt  
       2023-08-31 11:26:23 +08:00
    @geelaw 我的意思是,服务端只需算出他生成的那些张的 Hash ,而客户端需要枚举所有。而且等客户端枚举完,服务端可能以及换了一批 Hash 组合了
    或者如果不在意服务端亲自 Hash 一下的话,可以每次给客户端随机的Hash组合算法用于验证……
    比如
    md5(sha1(salt(sha1(salt(md5())))))
    salt(sha1(md5(sha1(salt(md5())))))

    还有真的很多人说成熟第三方,确实。为什么非得验证码。滑块不好么……第三方验证很贵么
    dzdh
        19
    dzdh  
       2023-08-31 11:35:37 +08:00
    wasm + cookie 带个随机数 类似 totp 那样 10 秒误差时间范围内算个 6 位数数出来
    hahaba
        20
    hahaba  
       2023-08-31 11:43:10 +08:00
    直接把接口加密了,前端的秘钥打散到各个文件再加密找都找不出来,连验证码都不用
    yankebupt
        21
    yankebupt  
       2023-08-31 11:54:17 +08:00
    比如那种定点滑块或者变异一点的二维滑块,客户端绘制,但是不是把验证结果发回去,而是把自己的绘制参数和用户的鼠标事件轨迹同时发回去服务器验证,用户就不知道验证逻辑是什么,而且为什么脚本自动滑有时候会失效。
    geelaw
        22
    geelaw  
       2023-08-31 11:55:27 +08:00
    @yankebupt #16 经典计算机的对立面是量子计算机,这样说是因为利用量子计算可以让(发送给客户端的)程序只能(被客户端自行)运行一次,但经典计算机没有这种可能。

    #18
    >把明文的 Hash 也发过去让他自行验证。
    我的解读是客户端会收到正确答案的 hash ,这样的话客户端可以自己尝试所有可能答案,计算它的 hash ,直到匹配为止,然后再把答案发给服务端。

    >服务端只需算出他生成的那些张的 Hash ,而客户端需要枚举所有。而且等客户端枚举完,服务端可能以及换了一批 Hash 组合了
    或者如果不在意服务端亲自 Hash 一下的话,可以每次给客户端随机的Hash组合算法用于验证……
    比如
    md5(sha1(salt(sha1(salt(md5())))))
    salt(sha1(md5(sha1(salt(md5())))))

    不太理解,客户端要想自己比对,当然需要知道如何计算 hash ,换用不同的算法没有意义。

    In any case, 这个方案不好。此外,从攻防、补丁的角度思考效率也不高,应该从形式化和证明的角度思考。
    libook
        23
    libook  
       2023-08-31 11:56:26 +08:00   ❤️ 1
    现在灰产,哪怕是低端程序员,Hack 接口是基操,前端验证码几乎没啥用,你只能防住完全不懂技术且也不会照着别人教程操作的人。从我们公司的经验来说,连小学生都知道怎么按照教程绕过限制薅羊毛。

    除非你的产品需求非常明确就是防君子不防小人。
    yankebupt
        24
    yankebupt  
       2023-08-31 11:57:40 +08:00
    还有最新的Edge和Chrome免验证,由浏览器随时验证用户是否是真人,然后数字签名过去一个消息证明用户是真人,只要验证是Chrome的签名就行了。开源的Headless因为开源所以没证书也没签名,具体实现原理我也不清楚,可以参考下。
    mdn
        25
    mdn  
       2023-08-31 12:01:02 +08:00
    @libook 而且现在都是有人做好脚本,直接运行就好(比如抢票),只能防没有动手能力的小白
    mdn
        26
    mdn  
       2023-08-31 12:04:35 +08:00
    @yankebupt #24 Puppeteer 可以控制本地 chrome
    yankebupt
        27
    yankebupt  
       2023-08-31 12:38:59 +08:00
    @geelaw 形式化验证虽然不万能,讲个笑话,验证码:1+1=2,黑客:等等,那只是个猜想,还没有证明!不能形式化验证!但其实该用一样用……
    但形式化验证也并不是完全没用,但凡客户端有台 Loseless qubit 量子电脑,最次也是租了点超算时间,那什么 hash 或者 salt 都没有用。有没有一定要客户端可以知道对错的实现呢?
    有!

    ……
    只是估计是有的。
    我们把判断对错的任务交给用户,不交给计算机了。
    考虑两个滑块,每个 5-6 张验证码,其中有两个是一样的,两个滑块图片风格不一样,都做成渐变视频,让用户把两个数字拉一样了,点提交……
    判断只需两个滑块的位置阈值……
    这样本地计算机就不知道验证码对错了,只有用户知道……
    是不是形式化验证要的是这样的答案?我觉得是,但很可能用处不大……
    yankebupt
        28
    yankebupt  
       2023-08-31 12:42:31 +08:00
    附:知道对错是指用户能明确知道自己是否误输入,自愿承担多次误输入造成的封禁惩罚,知道看不清点刷新
    如果明确的要拒掉错误输入的服务器请求,估计办不到的
    mxT52CRuqR6o5
        29
    mxT52CRuqR6o5  
       2023-08-31 12:43:44 +08:00   ❤️ 1
    我建议直接把验证码去了,既不能阻挡机器人,又降低用户体验的东西为啥要做呢
    yankebupt
        30
    yankebupt  
       2023-08-31 13:09:52 +08:00
    @ mdn 被脚本或插件控制的时候不会发出签名信息
    说的是因为浏览器验证用户是真人这段是闭源的。
    主要因为大家有 Chromium 和 Webkit 是开源的的印象,这里是段闭源验证,套壳浏览器没有

    当然可靠性没测过(没见人用过),所以不知道怎么样
    zjsxwc
        31
    zjsxwc  
       2023-08-31 13:11:22 +08:00
    同意,后端验证码真没多少 cpu 成本,
    比如 svg captcha ,
    后端每个验证码的字母都预先生成 svg 文本,
    要用的时候也不过改变一下这个字母扭曲的参数,
    后端验证码的成本和输出 html 没有区别。

    https://github.com/NikolaiT/SVG-Captcha
    ganbuliao
        32
    ganbuliao  
       2023-08-31 13:59:35 +08:00
    用第三方的行为验证码
    baobao1270
        33
    baobao1270  
       2023-08-31 15:45:03 +08:00
    后端做风控+限频阿
    LiuJiang
        34
    LiuJiang  
       2023-08-31 17:06:33 +08:00
    我也想问,有没有啥免费的验证服务,哈哈哈哈
    loolac
        35
    loolac  
       2023-08-31 18:02:25 +08:00
    手机扫码验证吧
    vueli
        36
    vueli  
       2023-08-31 19:27:48 +08:00
    后端可以返回验证码图片,几 KB
    liuidetmks
        37
    liuidetmks  
       2023-09-01 09:20:01 +08:00
    能不能换个思路,使用,类似于比特币
    你的请求的参数是 a ,找到随机 b 使得 sha256(a + b) 前面 20 个 bit 是 0 。(20 如果影响普通用户体验可以设置成 19 ,18)
    b 作为 参数的签名 一起发送给服务器,服务器简单验证就行了


    这样批量刷就变得很困难了
    如果想继续增加刷 api 成本,可以使用 scrypt 这类消耗内存形 HASH 替代 sha256
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5545 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 06:01 · PVG 14:01 · LAX 22:01 · JFK 01:01
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.