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

求大佬给点思路,web api 接口怎么防止被恶意重复访问?

  •  
  •   twg · 2020-11-24 14:10:29 +08:00 · 5168 次点击
    这是一个创建于 1220 天前的主题,其中的信息可能已经有所发展或是发生改变。

    背景:

    设计一个 http 接口,给客户端访问,但是这个接口会访问 redis 和 mysql,所以这个接口如果被别人知道,恶意攻击,可能会导致 redis 或 mysql 炸掉,所以有没有什么可行性的方案?
    

    我的解决方法:

    后端和前端约定一个 token,该接口是 post 方法请求,客户端每次请求都会在 form 中携带这个 token,后端通过比较这个 token,如果一致则执行业务代码,反之返回。因为 web 服务器前有一层 slb,ssl/tls 加在 slb 上,所以这样中间人应该获取不到这个 token 吧?
    
    这样安全吗?比如说,攻击人能从 app 程序二进制获取 token?
    

    或者还有没有别的方案?

    37 条回复    2020-11-25 10:18:45 +08:00
    VVVV7
        1
    VVVV7  
       2020-11-24 14:12:33 +08:00
    1. sign 签名 + time 时间戳
    2. IP 限流
    twg
        2
    twg  
    OP
       2020-11-24 14:18:57 +08:00
    @VVVV7 因为这个接口是登录之前,也就是还没到权限验证阶段,这样的话,sign 签名怎么实现?
    tabris17
        3
    tabris17  
       2020-11-24 14:21:33 +08:00
    @twg 私钥+nonce (时间戳),hash 算出来,不过需要客户端和服务器段时间同步
    twg
        4
    twg  
    OP
       2020-11-24 14:25:46 +08:00
    额..其实我想问的重点是,我想怎么区别这个客户端是我们 app 用户还是恶意用户?
    lsylsy2
        5
    lsylsy2  
       2020-11-24 14:27:26 +08:00
    @twg 那没啥特别好的方法,在前面包一层验证码之类的东西(本质是登录了)
    streamrx
        6
    streamrx  
       2020-11-24 14:27:31 +08:00 via iPhone
    @twg 请求的频率
    locoz
        7
    locoz  
       2020-11-24 14:28:31 +08:00 via Android
    如果你这个接口是公开的,别人在你的网站或者 app 上抓个包就能看到,并且接口返回的内容对用户来说有实际意义的话,那就老老实实加风控,你自己整的那些花里胡哨的没啥意义。
    locoz
        8
    locoz  
       2020-11-24 14:29:24 +08:00 via Android
    #7 加风控 -> 加风控厂商的风控产品
    twg
        9
    twg  
    OP
       2020-11-24 14:32:11 +08:00
    @locoz 这个是公开接口,但是 https 协议也能看到吗?
    zxCoder
        10
    zxCoder  
       2020-11-24 14:34:59 +08:00
    限制请求频率?
    imdong
        11
    imdong  
       2020-11-24 14:41:12 +08:00   ❤️ 2
    接口签名,客户端将密钥保护好,没有更好的办法。

    最近开项目,就遇到同样的问题我的做法是这样的(也是比较通用的做法):

    具体思路就是,客户端与服务端约定一个密钥(密码串),然后将请求的 GET POST 数据与客户端版本,当前时间戳,唯一随机数打包成一个字符串后用密钥签名( RSA Sign or hash ),放进 header 头传回服务器。

    服务器根据客户端版本选择密钥对数据进行验签核对时间,并检查 Redis 是否存在此唯一随机数,通过就将 唯一随机数存至 Redis,一分钟后过期。

    只要保证客户端这边没有被反编译,就基本安全(没有绝对的安全,涉及到客户端的,一定有可能被破解)
    xuanbg
        12
    xuanbg  
       2020-11-24 14:47:02 +08:00
    限流,可以根据来源 IP 进行访问限制,譬如每秒只允许同一 IP 请求 1 次,超过的就丢掉。问题是会误杀,因为很多局域网的用户对外都是同一个 IP 。
    xuanbg
        13
    xuanbg  
       2020-11-24 14:50:43 +08:00
    @imdong 客户端加密就是防君子不防小人,或者说防菜鸟不防老手。还不如服务端对 IP 限流,虽然有误杀率,但基本上也不太会影响正常的访问。
    twg
        14
    twg  
    OP
       2020-11-24 14:55:22 +08:00
    @imdong 感谢老哥,随便问一下,你说的`接口签名`是指啥?
    soulmt
        15
    soulmt  
       2020-11-24 14:58:36 +08:00
    参照微信小程序 login,设计一次性 token 用完过期, token 用对称加密即可,除非反编译源码,否则这个 token 可以解决这个问题。
    Jooooooooo
        16
    Jooooooooo  
       2020-11-24 14:59:04 +08:00
    1l 的方法基本就是通用的

    约定好加密方法然后每次请求带上时间戳和加密数据, 用事先交换好的密钥去加密 请求参数+时间戳, 得到的数据和服务器上计算对比, 不一致直接返回错误

    如果你想问 4l 这种风控的问题, 就没那么简单了

    限制访问可以用限流+拉黑这种方法
    qiayue
        17
    qiayue  
       2020-11-24 15:00:24 +08:00
    @twg 上面这些大哥说的签名是很常用的方式,可以参考微信的这个文档
    https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html
    locoz
        18
    locoz  
       2020-11-24 15:02:02 +08:00
    @twg #9 当然能看到,抓包、反编译、Hook 随便一个操作就能看到了。加签名、IP 限流之类的也没啥用的,一般做开发的人弄出来的防护都是跟纸糊的一样,随便就能捅破。所以如果你的这个接口想要确保绝大多数情况下的安全,那就老老实实用专业做这块的人弄的服务...如果你感觉没必要的话,那就说明这个接口没有重要到那种程度,随便加个限流就好了。
    opengps
        19
    opengps  
       2020-11-24 15:02:23 +08:00
    用 redis 做个访问频率限流,或者幂等性处理从缓存里直接返回同样的数据
    twg
        20
    twg  
    OP
       2020-11-24 15:03:15 +08:00
    @qiayue
    @Jooooooooo
    @soulmt
    @xuanbg
    感谢各位老哥解答.
    twg
        21
    twg  
    OP
       2020-11-24 15:10:15 +08:00
    @locoz 涨见识了
    zhiguang
        22
    zhiguang  
       2020-11-24 15:12:01 +08:00
    如果是私有接口弄个 ssl 双向认证
    zjsxwc
        23
    zjsxwc  
       2020-11-24 15:19:32 +08:00
    每隔一段时间给你客户一个你的证书与私钥, 参考农行的 K 宝
    meshell
        24
    meshell  
       2020-11-24 15:20:11 +08:00
    app 签名方式 防不住大佬的。就像 #13 说得一样,加一些风控吧,验证码这些 增加破解难道 .
    Macv1994
        25
    Macv1994  
       2020-11-24 15:31:23 +08:00
    谷歌翻译的 secret 字段大佬都能给你破译出来 哈哈哈 不过现在好像没有用了
    shellic
        26
    shellic  
       2020-11-24 15:37:13 +08:00
    Nginx 可以限制请求频率
    murmur
        27
    murmur  
       2020-11-24 15:40:35 +08:00
    首先要注册,实名制使用接口,然后在注册鉴权这部分拦截,微信有 token 但是 token 也是人获取的可以查到是谁
    gadsavesme
        28
    gadsavesme  
       2020-11-24 16:14:15 +08:00
    限流呗,如果是恶意攻击前端加密也不靠谱的。
    AkideLiu
        29
    AkideLiu  
       2020-11-24 16:50:04 +08:00 via iPhone
    如果简简单单就能解决,那些做 cyber security 的早去开滴滴了
    yscg
        30
    yscg  
       2020-11-24 16:54:32 +08:00
    看看重放攻击的解决方案
    polymerdg
        31
    polymerdg  
       2020-11-24 17:07:11 +08:00
    对称加密签名
    polymerdg
        32
    polymerdg  
       2020-11-24 17:07:31 +08:00
    约定大于配置
    tqrj
        33
    tqrj  
       2020-11-24 17:12:01 +08:00
    没有绝对的安全
    如果是没有登录的接口:可以根据 IP 去限制并发量这是最简单的
    然后就是前端 JS 生成 token 后端进行效验具体细节 自己研究 参考 国外 CloudFlare 俗称五秒 cdn 最开始几代很容易破解其实。目前第三代还是有一定难度 JS 有混淆 vm 加密之类的解密很耗精力
    登录之后的接口:其实可以直接 redis 限制并发为 1 这样?再配合 nginx 完成一些基础的限制
    上面都是我瞎想的没有实践经验
    Koral
        34
    Koral  
       2020-11-24 18:16:24 +08:00
    https://docs.konghq.com/hub/kong-inc/rate-limiting/
    看下这个呢?不知道满不满足需求
    LLaMA2
        35
    LLaMA2  
       2020-11-25 00:06:09 +08:00   ❤️ 1
    假定你的接口叫 api,GET 请求, 且传递的参数是 data=abc 。

    为了防止恶意重放攻击,可以实现如下:

    api?data=abc&time=时间戳&code=1000&hash=xxxx

    其中 hash 规则是 md5(abc + 时间戳 + 干扰码)

    时间戳和 time 的保持一致,为了后端做超时检测, 干扰码和 code=1000 存在对应关系。

    即你有一张表,事先生成了一堆序号和干扰码,干扰码对应的序号只有你和 APP 知晓,保证不能泄漏(实际上坏人需要花时间破解)

    你每次收到消息后按照同样的方法计算 hash 比较,发现 hash 比对不上,就说明数据被篡改,时间戳超时可能是重放。服务器就直接丢弃,返回错误给前端
    aawei
        36
    aawei  
       2020-11-25 00:15:11 +08:00 via iPhone
    验证码
    twg
        37
    twg  
    OP
       2020-11-25 10:18:45 +08:00
    @ye4tar 感谢解答,我准备采取类似方法.
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3940 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 00:57 · PVG 08:57 · LAX 17:57 · JFK 20:57
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.