V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
leiuu
V2EX  ›  程序员

开放 api 接口,如何做签名验证?

  •  
  •   leiuu · 2019-10-16 10:39:50 +08:00 · 8146 次点击
    这是一个创建于 1895 天前的主题,其中的信息可能已经有所发展或是发生改变。

    RT。

    V 友好,想请教一个问题。

    场景是这样的,我需要暴露一个 api 给第三方,第三方有可能会把这个 api 放到公开网站中。

    如果没有做签名校验的话,可能爬虫 /任何人都能触发这个链接,这会导致系统会有很多非法的请求,进而带来系统数据异常等其他损失。

    针对这类问题,大家一般会用什么方法去解决?

    40 条回复    2019-10-19 10:50:58 +08:00
    Balthild
        1
    Balthild  
       2019-10-16 10:46:19 +08:00
    hmac 算法,对 URI + Body 签名
    yoshiyuki
        2
    yoshiyuki  
       2019-10-16 10:49:13 +08:00   ❤️ 1
    1,生成密钥 key
    2,要求客户端调用的时候,带上自己的密钥 id,并用参数转字符串后拼接密钥,md5 后得到签名
    3,服务端校验签名
    arrow8899
        3
    arrow8899  
       2019-10-16 10:49:26 +08:00   ❤️ 4
    签名在这里没用吧,对方也可能把签名算法公开出去。
    可以用 IP 白名单,限制第三方服务器特定的 IP 才能访问。
    laravel
        4
    laravel  
       2019-10-16 10:50:38 +08:00
    oauth 啊,给他一个 appid appsecret 他可以用这俩获取 access token (有过期时间的),微信公众平台 等不都是这样的吗
    CantSee
        5
    CantSee  
       2019-10-16 11:04:30 +08:00
    微信 银联 支付宝的不是有现成的例子啊!
    littleylv
        6
    littleylv  
       2019-10-16 11:06:28 +08:00
    一般的解决方案就是 OAuth 2.0
    xiaoyangsa
        7
    xiaoyangsa  
       2019-10-16 11:17:00 +08:00   ❤️ 2
    收费,按调用次数。。。
    leiuu
        8
    leiuu  
    OP
       2019-10-16 11:19:19 +08:00
    @yoshiyuki 👍 这个看起来合理。还有一个小问题,如何防止这个带签名的链接被暴露后重复调用?
    leiuu
        9
    leiuu  
    OP
       2019-10-16 11:20:08 +08:00
    @Balthild 感谢,我了解一下。
    0NF09LJPS51k57uH
        10
    0NF09LJPS51k57uH  
       2019-10-16 11:22:08 +08:00
    hmac 算法对 query params + timestamp + secret key 进行签名,服务器端用同样算法进行验签。
    leiuu
        11
    leiuu  
    OP
       2019-10-16 11:22:35 +08:00
    @littleylv
    @laravel
    @littleylv

    都推荐了 OAuth,我了解一下。🙏
    leiuu
        12
    leiuu  
    OP
       2019-10-16 11:22:50 +08:00
    @xiaoyangsa 不行 😂😂
    xiaoyangsa
        13
    xiaoyangsa  
       2019-10-16 11:25:28 +08:00
    @leiuu
    那就学微信的公众号登录授权吧。这个靠谱点。
    leiuu
        14
    leiuu  
    OP
       2019-10-16 11:25:53 +08:00
    @CantSee 求详解。

    @arrow8899 ip 白名单的话可能不太好弄,假设这个 api 要面对几百几千个第三方。用签名的方法的话, 如果被公开的话确实没什么好的办法。只能走商务路径了哈哈哈哈。
    shadow88sky
        15
    shadow88sky  
       2019-10-16 11:29:18 +08:00
    就是 Oauth 认证 不用想
    unco020511
        16
    unco020511  
       2019-10-16 11:31:16 +08:00
    请参考微信支付宝,蛮简单
    waterlaw
        17
    waterlaw  
       2019-10-16 11:32:14 +08:00 via Android
    之前公司用第三方的接口,Oauth + 签名
    anyforever
        18
    anyforever  
       2019-10-16 11:33:37 +08:00
    如果对方想公开密钥,你用什么签都没用啊,相当于人家把钥匙丢了,而你这锁又没换,捡到钥匙的当然可以随时开你的锁了。所以避免别人丢钥匙,你就得给他加个 IP 验证
    fancy111
        19
    fancy111  
       2019-10-16 11:34:25 +08:00
    既然都放到公开网站上了,加密签名授权什么的都是没用的。既然网页能调用,我利用链接一样可以。
    唯一就是加白名单了,具体情况你没说清楚。
    eason1874
        20
    eason1874  
       2019-10-16 11:41:29 +08:00
    最好的校验方法是加几个参数,timestamp、appid 和 sign(除 sign 以外所有参数按字母升序排序,密钥)。

    再加上 IP 白名单是最安全的,不过这个不是什么场景都有条件。
    ericgui
        21
    ericgui  
       2019-10-16 11:44:31 +08:00
    @Balthild github 就是用这个
    fengxianqi
        22
    fengxianqi  
       2019-10-16 11:47:01 +08:00
    阔以参考微信服务器的做法,我之前就是这么做的。
    timestamp,appid,appsecret,nonce 生成一个 signature,通过 timestamp 可以让 url 在某段时间失效,通过 nonce 可以防止重放攻击。微信公众号文档参考: https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html
    ochatokori
        23
    ochatokori  
       2019-10-16 11:50:13 +08:00 via Android
    不管你怎么认证对方都可以开放给其他人使用吧,最差就他做一个转发

    实际点就按次数收费或者限制调用次数,次数不够了让对方联系提供正当理由增加次数
    CRUD
        24
    CRUD  
       2019-10-16 11:52:29 +08:00
    1、生成一个签名 key,MD5 对 body+time+key 计算摘要作为签名。
    2、RSA,交换公钥,用自己的私钥签名,用对方公钥进行报文加密,相对比较麻烦。
    3、oauth。
    l4ever
        25
    l4ever  
       2019-10-16 12:00:53 +08:00
    第三方有可能会把这个 api 放到公开网站中。

    溜了溜了, 你自己玩微信公众号么?
    你把你的 appid appsecret 暴露出来看看..这机密都能随意泄露, 那你怎么加密都没啥用.
    markgor
        26
    markgor  
       2019-10-16 12:04:46 +08:00
    @l4ever appid appsecret 洩露出來,現在好像也沒什麼危害了吧...
    微信 JSSDK 或 Oauth 現在需要自行配置業務域名和 IP 白名單。
    yoshiyuki
        27
    yoshiyuki  
       2019-10-16 13:17:14 +08:00
    @leiuu 可以加上一个时间参数,近 5s 内的时间戳有效,时间戳参与签名计算,另外,密钥发放的时候,需要绑定 ip 白名单
    leiuu
        28
    leiuu  
    OP
       2019-10-16 14:10:21 +08:00
    @unco020511 蟹蟹
    @shadow88sky 蟹蟹

    @anyforever 这么讲我就明白了,哈哈哈

    @fancy111 场景的话其实是想用于广告监测,比如用户打开一个页面,成功加载一个广告,算一次广告展现,把这条信息发送给多个监测方,我们是其中一个。
    leiuu
        29
    leiuu  
    OP
       2019-10-16 14:13:33 +08:00
    @eason1874 这个方法靠谱!比较清楚了哈哈哈。


    @ericgui 蟹蟹


    @fengxianqi 我现在去看看


    @ochatokori 有道理!


    @CRUD 给力!!


    @l4ever @markgor 明白了 哈哈哈 你俩掰扯掰扯



    @yoshiyuki 靠谱!!
    murmur
        30
    murmur  
       2019-10-16 14:20:42 +08:00
    不暴露接口的直接随便 hash 一签都很安全
    放到 app 里不需要登录的只要数据够值钱怎么都不安全
    markgor
        31
    markgor  
       2019-10-16 14:26:33 +08:00   ❤️ 1
    ememe,沒什麼好扯的, @l4ever 所說沒大問題,安全事項肯定要注意。
    我想表達的是你參考微信,當初 oauth 就可為何後面加入百名單。
    按時間計算 5s 内的时间戳有效 這個方式有個平台在用,他們的技術給人罵到不敢吭聲。(你想象下網絡的延遲和時間的不同步問題因素),後來他們技術改為時間不一致後返回相差時間。(不用想了,又被人噴了一次,既然你都返回相差時間,你 TM 還不如直接跳過這個驗證?)

    如有可能 IP 白名單即可了。不用那麼多花花綠綠的。
    gongshishao
        32
    gongshishao  
       2019-10-16 14:31:38 +08:00
    阿里奇门规范了解一下,开放接口的常规加密手段
    leiuu
        33
    leiuu  
    OP
       2019-10-16 15:45:10 +08:00
    @markgor 同意!白名单方式具备条件的话是最好用。
    还有一个小问题,微信的验证方式,假设我将携带 signature 的链接暴露出来,同样会触发攻击吧?
    markgor
        34
    markgor  
       2019-10-16 16:01:13 +08:00   ❤️ 2
    @leiuu
    微信驗證方式:
    比如提交數據是:
    name="abc"
    age = 18

    假設 appid : 12345678
    假設 appsecret: abcdefg

    此時根據時間生成一個 timeStamp = 123456789
    隨機生成一串字符:nonseStr = a456sdf

    簽名方法:
    根據排序,文本合併:
    signature = md5('age=18&appid=12345678&name=abc&noseStr=a456sdf'.abcdefg)//大致這樣吧具體忘記了

    然後可以得出,
    如果篡改上面任意一個參數,最終的 signature 內容是不符的。
    上面條件,只有 age,name,timeStamp,nonseStr 是別人知道的,缺少了 appid 和 appsecret 兩個參數,
    因為 timeStamp 是一直變的,nonseStr 也是隨機生成的,如果通過截包方式猜測 appid 和 appsecret 明顯困難。(當然不排除有人直接固定 timestamp 和 nonseStr 的內容)
    所以就算 signature 或者 每次的請求被人攔截了,想篡改數據可能不大。

    為什麼後面微信會有個白名單驗證呢。
    那是因為有很多開發者把 appid 和 appsecret 都丟上 github 去了。
    所以後面開通的公眾號獲取 accessToken 都要設置 IP 白名單。
    markgor
        35
    markgor  
       2019-10-16 16:09:31 +08:00   ❤️ 1
    這麼說吧,
    如果你直接修改提交的內容,但是 signature 不改,微信那邊驗簽的時候直接就不通過了,因為你需要用被修改的數據重新跑一次加密的過程,才能得出正確的 signature (微信也是用得到的數據根據相同的公式進行簽名,再對比簽名是否一致)
    為什麼需要隨機字符和時間截加進去,就是為了進行數據混餚,增加解密難度(解出 appsecret 的難度)。


    後期為何綁定 IP,
    那是因為太多人的 appid 和 appsecret 洩露出去了。
    Leigg
        36
    Leigg  
       2019-10-16 17:02:15 +08:00 via Android
    你自己把方案都说出来了。
    Guidarin
        37
    Guidarin  
       2019-10-16 17:44:59 +08:00   ❤️ 1
    如果这个 API 只是给某个特定的合作方来使用,那就约定 secret key 用 Https + 签名 + IP 白名单,没必要用 oauth 协议,
    另外做好调用频率限制,看业务确定是否允许重载
    Ps: 有老牌的短信服务商,对外提供服务就喜欢使用 IP 白名单
    balabalaguguji
        38
    balabalaguguji  
       2019-10-16 20:41:58 +08:00
    这里有个签名算法,其实就是跟微信支付的一样的: https://easydoc.xyz/#/s/17790664/CZMqMhfW/72093984
    saltedFish666
        39
    saltedFish666  
       2019-10-17 17:17:32 +08:00
    最简单,IP 白名单啊
    abellee000
        40
    abellee000  
       2019-10-19 10:50:58 +08:00 via Android
    用 hmac 的 app 逆向过两个 唔 伪造起来还是挺简单的
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3439 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 11:18 · PVG 19:18 · LAX 03:18 · JFK 06:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.