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

除了防止重复提交,token 可以防止对接口的暴力请求吗?

  •  2
     
  •   pp3182429 ·
    albin3 · 2014-08-06 15:02:37 +08:00 · 15065 次点击
    这是一个创建于 3772 天前的主题,其中的信息可能已经有所发展或是发生改变。
    1. 在调用接口的时候会经常需要token,google后发现是为了防止重复请求;
    2. 在返回的网页中嵌入token,很容易被获取到;有没有更高级的设计,可以防止接口被暴力请求?
    3. 可以在token中加入表单校验之类的增值功能么?
    26 条回复    2014-08-09 00:11:38 +08:00
    mornlight
        1
    mornlight  
       2014-08-06 15:06:35 +08:00   ❤️ 1
    凡是发送到客户端的东西,都应该视为可以很容易被获取到。
    除非是验证码这种需要识别的,但是该场景不适用。
    gamexg
        2
    gamexg  
       2014-08-06 15:53:02 +08:00
    token 不是用来防止 CSRF 攻击的吗?
    暴力请求指的是 ?
    semicircle21
        3
    semicircle21  
       2014-08-06 15:54:25 +08:00   ❤️ 1
    让客户端干点有代价的事, 比如让客户端找到x 满足 md5(token + x) -> 前3位是0的.
    loading
        4
    loading  
       2014-08-06 15:54:52 +08:00 via Android
    是洪水 ddos?

    请 lz 学习下 csrf
    pp3182429
        5
    pp3182429  
    OP
       2014-08-06 17:55:16 +08:00
    @gamexg 我的理解是无脑请求一个借口呀。
    pp3182429
        6
    pp3182429  
    OP
       2014-08-06 17:55:50 +08:00
    @semicircle21 好的,研究下。。谢谢!
    pp3182429
        7
    pp3182429  
    OP
       2014-08-06 17:57:26 +08:00
    @loading 唔,好。。目前在做一个金融类项目,需要考虑安全的比较多,有哪里可以系统学习一下的么?谢谢啦
    Shieffan
        8
    Shieffan  
       2014-08-06 18:02:01 +08:00
    最简单效果也一般用的最普遍的就是ip限制。
    xoxo
        9
    xoxo  
       2014-08-06 21:19:14 +08:00   ❤️ 1
    楼上的同学们没看懂楼主的问题;
    楼主说的是什么问题呢?

    重复提交,表面上是重复提交,威力不大,但实际。。。我们来分析分析:


    假设一个用户,余额100,平台恰好有个提现的地方,理所当然用户最多只能提取100元。

    我们来分析下程序在生成提现数据的过程:

    开启事务;

    用户发起一次提现请求,到达应用后,程序判断用户余额是否够用,如果不够就跳出事务了;

    然后扣除100元,

    然后再提现数据表中插入一条数据,

    到这里还没结束,因为事务还没提交,当上面进行顺利时,到达这里就应该commit提交了,如果上面操作任何一步异常,就rollback回滚了。


    看起来挺完美的过程,其实!弱暴了!

    为啥?



    假如用户发起两个请求,而且同一时间(1/1000秒级)请求到服务器,
    再走一次上面的逻辑:

    请求一达到服务器 请求二达到服务器
    开启事务 开启事务
    余额检查->通过 余额检查->通过
    扣除余额->done 扣除余额->done
    插入提现记录->done 插入提现记录->done
    提交->commit(); 提交->commit();


    两边几乎同时进行一样的操作,为什么没被拦截掉只处理一个请求呢?因为余额检查时,别的请求的事务未提交,在此请求内select的数据还未生效,所以两个请求处理都通过了检查。



    那怎么防御呢?

    token?
    扯J8蛋!token用来防御这原子级别的攻击?别说session了,即使你重写php底层,让session动态调用php的内存也无济于事。原因自己脑补;

    队列是终极解决方案。

    然后有一个临时方案,提现的表中肯定会有time/datetime之类的字段,在建表时将这个表中的time/datetime + userId 设置为联合主键,然后事务在插入提现数据时,因为时间同一秒且同一用户所以数据冲突,只会成功一条,然后事务报错启动回滚,近乎完美。唯一的瑕疵就是假如前后误差1ms, 然后恰好前一个时间是xxxx1,后一个时间是xxxx2,这样就扯痛蛋了。。。千分之一的概率。
    bombless
        10
    bombless  
       2014-08-06 21:36:03 +08:00
    hcun
    bombless
        11
    bombless  
       2014-08-06 21:37:56 +08:00
    缓存最近N次提交的ip吧,如果ip已经记录过了就更新这个ip的序号并拒绝这次提交。
    aWangami
        12
    aWangami  
       2014-08-06 22:30:11 +08:00
    @xoxo 如果限制所有的操作必须要token才能完成,操作之前先请求token。对于原子操作,如果同一个账号请求过token,那么必须等账户当前token失效(操作完成),才能进行下一次请求,这样子是不是简单实现了锁机制呢?
    20150517
        13
    20150517  
       2014-08-06 22:38:52 +08:00
    @xoxo 你要复习下数据库了,余额事务操作当然是锁行,你前一个事务在做,你第二个事务根本进不了检查!这根本不是什么 php问题,是数据库问题
    xoxo
        14
    xoxo  
       2014-08-06 22:48:33 +08:00
    @20150517
    我所言均为线上生产代码实战总结,理论派可以去试试。
    ooxxcc
        15
    ooxxcc  
       2014-08-06 22:55:06 +08:00
    @20150517 曾经用 @xoxo 说的方法欺负过一个页游的飘过……
    wdlth
        16
    wdlth  
       2014-08-07 00:18:57 +08:00
    要考虑线程安全,即使请求同时到达,仍然通不过线程安全。还有用悲观锁,队列什么的实现。

    很多页游程序为了高并发都不是线程安全的,被利用也是很常见的事……
    millson
        17
    millson  
       2014-08-07 07:25:38 +08:00
    update `user` set `coin` = `coin` - 100 where `id` = 'xxxxxx' and `coin` > 100;

    这样呢
    pp3182429
        18
    pp3182429  
    OP
       2014-08-07 10:08:51 +08:00
    @xoxo 谢谢xoxo的经验之谈,以前考虑简单了。
    Actrace
        19
    Actrace  
       2014-08-07 17:54:10 +08:00
    原子提交,MYISAM可以锁表,InnoDB可以锁行.
    pp3182429
        20
    pp3182429  
    OP
       2014-08-07 17:56:21 +08:00
    @Actrace 好的,用的是mysql
    Actrace
        21
    Actrace  
       2014-08-07 18:05:41 +08:00
    @pp3182429
    主要看你用什么数据库引擎了.
    我个人感觉其实最大的一块可能还是来自前端请求的压力,用Token来切割有效请求效果还是不错的.
    至于数据原子性提交的问题,MYIASM和InnoDB都支持锁,所以不是个问题,如果是PHP的话,已经自带队列了,同一个的PHP文件的执行请求被客户端多次发起,会阻塞后面的请求,直到这个请求完成处理,当然如果是多个客户端的话,你可能还需要增加一个查询中间件队列这些请求来规避可能带来的问题,不过只要正确运用了锁,基本上都没啥问题.
    pp3182429
        22
    pp3182429  
    OP
       2014-08-07 18:19:41 +08:00
    @Actrace 用的是Nodejs,io应该也是队列,这也是天然队列么?
    ryd994
        23
    ryd994  
       2014-08-08 02:23:40 +08:00
    谢谢@xoxo ,学习了
    加锁可以解决吗?限制请求频率呢?
    Actrace
        24
    Actrace  
       2014-08-08 09:11:59 +08:00
    @pp3182429 Nodejs没研究过...
    pubby
        25
    pubby  
       2014-08-08 10:48:00 +08:00
    @xoxo 可以不用队列,简单上锁就可以保证顺序处理了

    最简单的跨服务器锁可以使用MySQL的
    GET_LOCK()
    RELEASE_LOCK()
    IS_FREE_LOCK()
    IS_USED_LOCK()
    系列函数

    (* 需要保证所有业务服务器在上锁时连接的是同一个MySQL服务器)
    xoxo
        26
    xoxo  
       2014-08-09 00:11:38 +08:00
    @pubby 再仔细看看我分析的过程你就明白没用的。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1017 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 20:37 · PVG 04:37 · LAX 12:37 · JFK 15:37
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.