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

怎么防止用户自己调用网站 API 发送 POST 请求篡改数据

  •  1
     
  •   b00tyhunt3r · 2021-10-07 13:28:09 +08:00 · 9596 次点击
    这是一个创建于 1145 天前的主题,其中的信息可能已经有所发展或是发生改变。

    譬如我有一个 API 节点, 这个 API 接收包含 1 个参数 "address" 的 POST 请求

    正常来说这个 address 是客户端在发送 POST 请求的时候程序自动获取的, 用户无法自己更改 但是如果用户自己用开发者工具之类的 call 这个 API, 在请求中传入自己有效的 Token 绕过鉴权, 和一个篡改的 address 参数, 那岂不是可以随意滥用这个 API 私自修改 address 了吗?

    刚刚接触 web 开发不是很懂,请问该如何防止这个情况的发生?

    65 条回复    2021-10-09 07:22:28 +08:00
    DogeFlyKite
        1
    DogeFlyKite  
       2021-10-07 13:44:20 +08:00   ❤️ 1
    搞一下 HTTPS 双向认证?
    seakingii
        2
    seakingii  
       2021-10-07 13:45:33 +08:00
    首先这个话题是"矛与盾",永恒的碰撞,难说能"防止"

    其次可以加一些手段加大不合法调用的难度 ,方法也是老久的

    百度: api 接口签名
    zmxnv123
        3
    zmxnv123  
       2021-10-07 13:48:31 +08:00   ❤️ 1
    token 根据 address 生成,服务端校验 token 和 address 是否匹配。
    flyhaozi
        4
    flyhaozi  
       2021-10-07 13:52:45 +08:00
    收藏了,学习下怎么绕过接口验证😁
    xiaopc
        5
    xiaopc  
       2021-10-07 13:56:22 +08:00 via Android   ❤️ 3
    首先,理论上用户端发来的任何信息都应视为不可信的,总有方法可以伪造,所以终极方法是「 address 」不应由客户端发
    其次,如果做不到的话,就只能提高伪造难度,比如楼上说的对请求使用某种签名,然后混淆相关代码(攻击者获得签名方式;比如使用可信介质( U 盾等)客户端证书
    zjsxwc
        6
    zjsxwc  
       2021-10-07 13:57:03 +08:00   ❤️ 6
    用户主动行为你禁止不了。
    但你可以做到不让用户之外的人恶意篡改,比如使用 https 。
    mercury233
        7
    mercury233  
       2021-10-07 13:57:18 +08:00
    默认你收到的都是篡改过的值,然后该怎么办就怎么办
    xiaopc
        8
    xiaopc  
       2021-10-07 14:00:34 +08:00 via Android
    (点错回复了)
    比如楼上说的对请求使用某种签名,然后混淆相关代码(如果攻击者获得签名方式就没用了);比如使用可信介质( U 盾等)存储的客户端证书进行签名(但是怎么保证证书不会被攻击者拿到)
    lmaq
        9
    lmaq  
       2021-10-07 14:04:10 +08:00
    公钥加密+签名认证
    coolrc
        10
    coolrc  
       2021-10-07 14:08:28 +08:00 via Android
    如果是用户用私有 token 发的,那这个接口应该只能改这个用户的相关 address,如果被滥用了也是用户自己主动泄漏 token 的,只会影响这个用户。

    如果是公用的 token,那你的 API 应该只能 get,而不能 put 。不能给修改数据的 API 用公共 token,不然怎么样加密都会被解析出来。
    chanchan
        11
    chanchan  
       2021-10-07 14:08:31 +08:00
    你觉得他不能用,他的 token 就不能有权限
    Junzhou
        12
    Junzhou  
       2021-10-07 14:21:40 +08:00   ❤️ 6
    他拥有他的合法 token,向接口发起请求,这样就是合法请求,为什么不能修改地址呢?

    如果传递给你的地址是错误的(非法的),那你在后端对地址做校验就好了。 如果你用的是 https,把请求这个行为,和请求携带的参数是否合法,分成两个事儿来理解。 对请求内容加签只是为了保证内容在传输过程中防篡改。如果本身请求发起时携带的参数时错误的,加签并不能解决这个问题。
    MintZX
        13
    MintZX  
       2021-10-07 14:23:23 +08:00 via iPhone
    你是想要防止入侵还是什么? 如果是防止入侵 token 就行了。如果是防止有有效身份的用户自己改信息,那基本上是不太可能的。你整套前端的代码我都能改,你怎么防╮( ̄▽ ̄"")╭
    Junzhou
        14
    Junzhou  
       2021-10-07 14:26:33 +08:00
    @xiaopc 5# 说的我觉得不太对,其实应该拆开了看,客户端发起的请求是可以信任的(可以做到可信),但是客户端请求携带的参数(数据),必须要假设是不可信的。
    markgor
        15
    markgor  
       2021-10-07 14:59:46 +08:00
    第一、https 和这个没关系吧。装个 Fiddler,你就算是 https 还不一样能拦截篡改。
    第二、address 生成是由客户端生成,那就不存在不能篡改,你要防止篡改的话只能由服务端生成。因为客户端生成的话你无法区分 address 是被篡改后的还是没被篡改,当然你可以对参数请求进行签名,但这样无疑只是增加破解的成本而已,别人只要反编译下或者多次对比,找出你加密的规则,那最后还不是一样照篡改你的数据。
    最后:前端提交的一切内容都应该视为不可信内容。
    qfdk
        16
    qfdk  
       2021-10-07 15:02:02 +08:00
    这里需要后端校验用户的权限,如果用户没有更改权限,传来也没用。
    首先 这个 token 要不是 jwt 的话 肯定会连着一个 previllage 的表,这里记录了一些可用的权限。正常要是 spring 的话 用 authority 来判断,默认是 访问 userinfo endpoint 来获取用户信息。 你可以用简单的 RWD 这样的三种权限来验证,看看有没有 W 权限。
    当然了,还有个简单的法子,你 post 的时候, 后端通过 token,知道是谁来发送的,只要测试一下这个人是不是在白名单里面就好了 也就是

    ```js
    if(allowEditAddress(token)){
    doSomething();
    }else{
    // 没有权限
    }
    ```
    qfdk
        17
    qfdk  
       2021-10-07 15:03:59 +08:00
    正常来说这个 address 是客户端在发送 POST 请求的时候程序自动获取的
    > 这个获取流程,移到后端呗
    Jooooooooo
        18
    Jooooooooo  
       2021-10-07 15:05:16 +08:00
    搜 验签
    jinliming2
        19
    jinliming2  
       2021-10-07 15:15:42 +08:00
    没有 100% 的安全。你只能增加代码逻辑混淆,通过特定的方式生成校验参数,以此来提高破解门槛。如果破解者的破解成本大于破解后的收益,就表示你的混淆有价值。
    如果不考虑破解收益,用户就是想不计成本的破解你的 API 混淆参数,那么你没办法,所有前端的校验逻辑理论上都是可以被破解的。
    hronro
        20
    hronro  
       2021-10-07 15:30:18 +08:00
    你在设计 API 的时候就应该想好,不应该信任客户端传过来的任何数据
    seakingii
        21
    seakingii  
       2021-10-07 15:36:47 +08:00
    @qfdk 你们忽略了一个场景,就是正常情况下,这个地址是由移动端 GPS 得到的, 所以不存在"由后端获取 address"的说法
    seakingii
        22
    seakingii  
       2021-10-07 15:38:15 +08:00
    这个场景应该是"正常情况下,这个地址是由移动端 GPS 得到"

    楼主可能是为了防止用户随意更改 address,(有点像打卡 APP 防乱改地址)
    pupboss
        23
    pupboss  
       2021-10-07 15:49:15 +08:00   ❤️ 1
    可以做,但是意义很小就是了,因为 address 数据追根溯源是用户产生的,只要是用户产生的数据他无论如何都能篡改,就算你堵住了 address API,用户照样可以 root 越狱后改机器的 GPS

    这也就是为什么说“任何用户输入都是不可信的”,后端简单做下过滤,避免用户传的数据对业务造成影响,避免不可靠的字段造成程序 crash,基本上就已经谢天谢地了
    qfdk
        24
    qfdk  
       2021-10-07 16:02:26 +08:00
    @seakingii #22 主要是楼主说的是 web 开发。没有万能的解决方案,只有一个针对于某个问题的一个方案。既然移动端来传输了,那就要考虑到移动那边了(估计楼主没到这么远呢), 你想的场景合理。要是 GPS 的情况可能要来个偏移算法,看看比如飘了多远,如果手机没电了各种情况了。 逃~~~
    xiaopc
        25
    xiaopc  
       2021-10-07 16:23:01 +08:00 via Android
    @Junzhou MITM 拿到请求,甚至直接在客户端做手脚,客户端请求也可以做
    lscexpress
        26
    lscexpress  
       2021-10-07 16:39:13 +08:00
    @zmxnv123 没关系啊,篡改数据的机器和获取 token 的机器在同一个地方
    linhongye
        27
    linhongye  
       2021-10-07 16:46:28 +08:00
    是的, 没有错...
    用户有 token 就是可以去操作这个东西...
    今天担心用户用 api 去操作 address, 明天就得担心用户虚拟 GPS 去操作 address.
    想阻止这件事, 就得去结合多个不同传感器的信息去做验证.
    回头来, 核心还是要考虑业务场景. 用户改了这个东西获得了什么好处, 你们损失了哪些东西?
    如果损失不大, 甚至只是减少了一些利润, 其实可以不管...
    一方面, 这种用户量不大, 等这种用户多了再去管.
    另一方面, 如果刚接触 web, 那可能是个新项目, 这种项目有用户来用就是胜利, 还管他怎么用呢....
    stevenhawking
        28
    stevenhawking  
       2021-10-07 17:48:20 +08:00
    你参数都是放开给用户端 <input/> 控件的,你能给他 disabled 掉吗
    ch2
        29
    ch2  
       2021-10-07 18:06:20 +08:00   ❤️ 1
    一开始你就要考虑这种情况:
    api 被逆向过,请求是用脚本发过来的
    这种没办法防,但是你可以写一些规则惩罚乱搞太厉害的号
    kinge
        30
    kinge  
       2021-10-07 18:21:42 +08:00
    你不需要防止客户端请求。你只需要校验参数就行了
    cs419
        31
    cs419  
       2021-10-07 18:31:22 +08:00
    这个防不了
    就类似爬虫一样 你可以加高对方的作弊成本
    但无法做到绝对的阻止

    如果你做到了绝对的阻止 那正常用户应该也被你拒之门外了
    niubee1
        32
    niubee1  
       2021-10-07 19:04:00 +08:00
    这是个设计问题吧,首先,如果一个不需要修改的值,为啥还要客户端原封不动传回去?
    liuidetmks
        33
    liuidetmks  
       2021-10-07 19:35:09 +08:00 via iPhone
    目前可用的办法就是 混淆 js 。目前混淆器好像可以做到类似于汇编了,到处跳转,属性都给你混淆了。
    监控下 debugger
    把运行环境,时间戳也当做参数。

    但是这也只能增加对方难度,不能杜绝。
    clf
        34
    clf  
       2021-10-07 19:48:51 +08:00 via Android
    如果这个参数不应该由用户看到和生成,那么就完全把业务逻辑放在后端。
    icyalala
        35
    icyalala  
       2021-10-07 20:19:44 +08:00   ❤️ 1
    ssl pinning (也就是客户端内置证书) 来防止初级的抓包
    参数签名+客户端防逆向
    服务端风控,这是最主要的
    根据我待过的几个公司的经验,就算大厂也基本就是这些了
    整体来说就是增加成本降低风险,完全避免是不可能
    zyxk
        36
    zyxk  
       2021-10-07 20:49:42 +08:00   ❤️ 1
    客户自己调用 api ,在校验合法的范围内,他随便改都可以.
    我也有个疑问,怎么防止客户不使用我的前台 /客户端 . 只用 api 或 第三方客户端调用 api
    或者换个说法 比如 前后端分离的 V2EX 怎么防止第三方客户端呢 ?

    @xiaopc @zjsxwc @coolrc @Junzhou
    @MintZX @markgor @qfdk @ch2
    ch2
        37
    ch2  
       2021-10-07 21:00:19 +08:00
    @zyxk #36 答案是没法防,微信都做不到完全防止逆向
    甚至后台都不一定能检测出来请求到底是不是自己客户端发的
    无非是:
    1. 用一些难以伪造的签名机制对请求进行签名,不要求请求必须被签名,不签名一样能用 api(可以很有效地对付懒省事的逆向者),但是服务器可以知道这个请求是第三方发过来的
    2. 以封号为手段对使用非官方客户端的用户进行惩罚,或者强制踢掉这个第三方客户端的用户
    使这个第三方客户端声誉受损没人敢用
    leafre
        38
    leafre  
       2021-10-07 21:19:30 +08:00
    签名+防逆向保护签名 token,只能尽可能提高篡改门槛
    rekulas
        39
    rekulas  
       2021-10-07 22:13:19 +08:00
    问题可以转换下,相当于淘宝用户都可以设置自己地址,然后问如何防止用户用工具模拟提交地址
    答案当然是无法防止,只能通过各种手段提高逆向难度

    毕竟对服务端来说,客户端都是“无状态”的,只要参数正确,无法识别是真客户端还是伪客户端
    qfdk
        40
    qfdk  
       2021-10-07 22:37:42 +08:00
    @zyxk 只能说加大难度,简单的是加了个 reCAPTCHA,为了防止计算机系学生,随便抓取 api 来进行开发第三方客户端(为了防止假设私人代码到他们的 vps 不行的 ddos 服务器来查询成绩,课程表等等)我们的方案是通过 gateway 来处理。gateway 与前端通讯是通过 session,每次前端请求,session 会续命 4h 。gateway 那边可以通过 sessionId 获取到用户的 token,token 我们不会保存在客户端(浏览器端)。这样所有的请求都通过我们 gateway 。如果第三方 学生需要搞的话,需要做到 keep-session,也就是不停的刷新浏览器或者发请求,超级麻烦。公共 API 都是 AES 加密参数的,秘钥我们知道,学生并不知道,这样公共 api 做到一人一个 token 不会重复,他们也没法穷举。
    iPhone9
        41
    iPhone9  
       2021-10-07 23:13:30 +08:00
    为什么你叫这个是篡改数据?
    timpaik
        42
    timpaik  
       2021-10-07 23:15:36 +08:00 via Android
    api 设计原则之一:客户端永远不可信
    ganbuliao
        43
    ganbuliao  
       2021-10-08 00:17:53 +08:00
    这种情况就 带一个 addressID 呗 后端通过 addressID 查出用户真实的 address 不就行了
    js8510
        44
    js8510  
       2021-10-08 06:02:26 +08:00
    我遇到过类似的。最后使用 presigned url 稍微增加了 手动 call api 的难度。

    1. client request for address updates -> server
    2. server return a presigned url for posing address chagnes and the url timeout in 200ms(一般是你 request response round trip 正常的时间范围)
    3. client update address with presigned url.

    因为 2. 返回的 presigned url 有 200ms timeout 而且只授权指定 ip. 所以,至少用户没办法手动操作直接 call api. 怎么着也要再搞个脚本 自动化一下。其实就拦截了不少特定场景下的用户了。

    但是我觉得你的用户如果都是程序员,而且直接 call api 的动机很强,那基本上就没有用了。
    xuanbg
        45
    xuanbg  
       2021-10-08 08:38:21 +08:00
    合法的用户,拥有合法的权限,使用合法的方式调用接口,怎么就成了篡改数据???

    如果这行为不符合你的预期,那一定是你的接口数据校验没做到位。这就不是身份验证或令牌的问题,而是对数据的操作没有进行必要的限制的问题。譬如订单都发货了,你还允许修改发货地址之类。
    zxcslove
        46
    zxcslove  
       2021-10-08 08:56:43 +08:00
    @xuanbg 除了游戏以外,用户应该对客户端有完全的权力,只是现在好多客户端都是吃里扒外,成了监军和叛徒。
    xiaooloong
        47
    xiaooloong  
       2021-10-08 09:28:16 +08:00
    @markgor 「装个 Fiddler,你就算是 https 还不一样能拦截篡改。」问题就在于装 Fidder 的时候需要你信任 Fidder 的 根 CA,这个过程别说 tls 了,你电脑上应用程序的数字签名都没意义了。
    xylophone21
        48
    xylophone21  
       2021-10-08 09:37:47 +08:00
    可以看一看钉钉是怎么防虚拟定位打卡的
    传统的
    1. 客户端各种加密,防止非官方 App
    2.客户端各种检测,防止 root 、虚拟机等模拟 GPS
    以及比较狠的
    1. [传说] 发现问题不报错,但是在后台标记,等着管理员找你
    pusheax
        49
    pusheax  
       2021-10-08 09:42:21 +08:00
    无法防止。
    重要的校验和限制,应当在服务器端完成,应当默认将客户端的所有输入都是不可信的。
    即使是 https,也可以通过加自定义证书来实现中间人攻击。其它的什么验证码、token 也有办法绕过。
    信息安全里面的 web 渗透测试就是研究这个的。
    lz 可以去网上找几篇 burpsuite 和通过 burp 证书分析 ssl 流量的文章看一下。嗷,还有如何自动抓取 token 做爆破的。
    markgor
        50
    markgor  
       2021-10-08 10:02:43 +08:00
    @xiaooloong 我觉得有没意义是一回事,是否能拦截也是一回事;
    而且我说的是针对前端参数可信情况,而你说的是个人电脑安全情况,完全不是一回事吧,
    再者,我可以在虚拟机中装 Fiddler 进行拦截吧?(当然我没这样做过,我都是开发机直接装 Fiddler 来的)


    @zyxk 没办法防,参考微信 web 版本,他们最后手段也只是根据注册账号的时间和使用频率等方面,限制账号是否能通过 web 登录。
    而客户端的话可以采用 sdk 进行加密,甚至可以自定义协议。

    其实微信就是一个最好参考对象;
    markgor
        51
    markgor  
       2021-10-08 10:15:58 +08:00
    其实讨论这个问题我觉得有点离题了。
    问题本身精简而言就是 防篡改参数。

    基于 WEB 形式,基本无解,哪怕你对请求参数进行加密,然后再把 JS 代码各种加密,最终别人甚至不需要解密你的 JS,直接 devtools 上打点,看看哪里是对参数加密的,把加密函数复制出来就可以了。(我之前遇到过大多数的都是这样
    高深一点的,通过浏览器特性进行加密,类似携程防爬原理,某些特性某版本的浏览器是支持 /不支持的,通过这些差异来进行加密,后端通过请求的 ua 和规则验证下,就知道是否被篡改 /爬虫的请求了。

    基于 APP 形式的:
    这种玩法就多了,
    一、使用自定协议
    二、sdk 中写加密函数,分发 sdk 给第三方而不是给请求地址第三方
    ........

    但其实就如楼上有人提过,不是不能破解,而是当破解效益低于破解成本时,没人会去破解;
    现在很多第三方直接开通开放平台,接口我也直接给你调用,这种情况下谁还会去分析破解呢?
    包括 v2ex,直接开放了 API 。
    xiaooloong
        52
    xiaooloong  
       2021-10-08 10:55:51 +08:00
    @markgor 是我理解错你的意思了,无视我_(:зゝ∠)_
    wineast
        53
    wineast  
       2021-10-08 10:57:51 +08:00
    所以你的问题是防篡改,而不是防监听 /防抓包,所以和是否是 http/https 请求没关系
    1. 防监听方面:当然 https 协议稍微安全点,中间人可以通过伪造证书的办法来抓到包,市面上现在的 fiddler,Charles 之类的,都是用此方法进行抓包。阻止的办法也很简单,现在很多银行类的 app 都在用,就是证书双向验证,只允许他颁发 /授权的证书进行通信,这样,自己办法的合法证书就无法通信了。
    2. 防篡改方面,上面很多大佬都说了业界的标准方法了,方法加签+服务端验证,可以解决大部分的安全漏洞,至少大部分的 app,都是使用这个办法。
    2.1 方法加签:将方法内所有参数 md5 加密,生成一个 signature,服务端接收到所有参数后,用同样方法再次生成 signature,做校验,另:参数可以加入时间戳,后续用服务端时间校验,可以保证请求在短期内有效,而长期无效
    2.2 服务端校验:上面已经说过了,就是类似传 addressId,去数据库里校验这个 addressId 是否有值或者是否属于本 token,又比如对时间戳校验,是否在 5 分钟之内,等等等等业务级别的校验。
    当然,防篡改方面,如果你的客户端是 web 端,理论上,你的加密过程(算法,包括私钥)都是透明的,就算用了混淆,黑客直接调用就好了,这里就有一个成本的问题
    zoharSoul
        54
    zoharSoul  
       2021-10-08 10:58:16 +08:00
    验签
    Quarter
        55
    Quarter  
       2021-10-08 11:05:23 +08:00 via iPhone
    我觉得上面有写回答好像达不对题

    你这个问题的话,个人觉得没办法完全禁止,但是可以加大难度,用加密让用户无法查看到请求的数据结构,然后加上代码混淆,提高代码阅读复杂度,不让人轻易看懂代码执行逻辑,目前 web 端的话只想到这个
    2i2Re2PLMaDnghL
        56
    2i2Re2PLMaDnghL  
       2021-10-08 11:06:16 +08:00
    实质上有一些诡异的策略,叫做低门槛高风险。
    你随便修改,但被发现你随便修改侵害了服务提供方的利益,那么嘿嘿嘿

    另外还有一种比较诡异的,API 限流付费。
    钱能解决的问题,谁还去搞破解,傻之逼吗?

    @seakingii 那更简单了,直接篡改 GPS 数据。你就算保证了整个客户端设备都是可信的,你也不能保证周围的电磁环境是可信的,使用单发射源发射信号并施以恰当的延迟可以模拟三维空间中任意位置,甚至可以不在地球表面。

    @zxcslove 游戏也应该允许用户对客户端有完全的权力
    游戏界内最优秀的常青树,都是可以用 mod 高度自定义的:老滚 5 还能玩 10 年,甚至 MC 1.7.10 都还能玩 30 年。
    就算是网络游戏,甚至是 moba,也有 dota2 可以自行换皮(只有自己能看到),滚 OL 可以第三方汉化。
    更别说 nethack 这楞是活了这么久的……
    tabris17
        57
    tabris17  
       2021-10-08 11:08:38 +08:00
    请求加签名,如果只是浏览器请求那就算了吧,都可以破解
    zxcslove
        58
    zxcslove  
       2021-10-08 11:13:56 +08:00
    @2i2Re2PLMaDnghL 咱们意思差不多,我说游戏例外主要也是考虑公平性方面的。按道理讲,客户端应该完全为客户负责,可以是服务方提供,也可以是自制或从第三方获取。
    efaun
        59
    efaun  
       2021-10-08 11:17:35 +08:00
    防止不了,postman 可以直接模拟浏览器行为
    yc8332
        60
    yc8332  
       2021-10-08 11:24:30 +08:00
    这种基本无法防止的。。你要做的是校验数据
    2i2Re2PLMaDnghL
        61
    2i2Re2PLMaDnghL  
       2021-10-08 11:34:37 +08:00
    @zxcslove 所以我一直在想,如何从游戏机制上使得作弊不可能,或者作弊不能获得收益甚至使自己亏损。
    见过某游戏自动挂机的方式太容易而且不作任何限制(美其名曰模拟现实证券市场),结果导致写出来的脚本太简单,正常玩家可以随意操纵自动挂机机器的情况……
    zxcslove
        62
    zxcslove  
       2021-10-08 11:58:38 +08:00
    @2i2Re2PLMaDnghL 感觉太难了,串流吧
    seakingii
        63
    seakingii  
       2021-10-08 12:20:31 +08:00
    目前实际上从技术上来防止都是有极限的
    上面也有说明,有终极大招,就是解决破解的人....
    比如腾讯游戏不就起诉制造物理外挂的人....
    sliveryukilee
        64
    sliveryukilee  
       2021-10-08 17:01:52 +08:00
    加签咯,防不了所有,但能防住 99.99%
    janssenkm
        65
    janssenkm  
       2021-10-09 07:22:28 +08:00 via iPhone
    TLS 套上客户端证书就行,
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5655 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 93ms · UTC 06:03 · PVG 14:03 · LAX 22:03 · JFK 01:03
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.