V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
iOS 开发实用技术导航
NSHipster 中文版
http://nshipster.cn/
cocos2d 开源 2D 游戏引擎
http://www.cocos2d-iphone.org/
CocoaPods
http://cocoapods.org/
Google Analytics for Mobile 统计解决方案
http://code.google.com/mobile/analytics/
WWDC
https://developer.apple.com/wwdc/
Design Guides and Resources
https://developer.apple.com/design/
Transcripts of WWDC sessions
http://asciiwwdc.com
Cocoa with Love
http://cocoawithlove.com/
Cocoa Dev Central
http://cocoadevcentral.com/
NSHipster
http://nshipster.com/
Style Guides
Google Objective-C Style Guide
NYTimes Objective-C Style Guide
Useful Tools and Services
Charles Web Debugging Proxy
Smore
adow
V2EX  ›  iDev

APP上用的 http 接口被盗用了,请教有啥解决方案?

  •  
  •   adow ·
    adow · 2013-11-21 10:12:12 +08:00 · 26689 次点击
    这是一个创建于 3810 天前的主题,其中的信息可能已经有所发展或是发生改变。
    我们有iOS/android 的App,里面使用的一些基于Http的url接口访问数据。最近我们发现这个接口被其他人盗用了,我们现在已经做的防盗用方法是:

    * 对url的参数进行sha1签名,和oauth类似,对所有参数排序,大写,然后用一个密钥进行签名,然后请求时附带这个签名;
    * 在请求里增加了随机值,防止url被重复使用;
    * 用于签名的密钥是在代码里的;

    我们猜想他们应该是反编译了我们iOS或者android的代码,找到了密钥和签名方法,所以我们的签名方法已经没用了。

    我们想下面改进的方法是:

    * 使用https;
    * 对签名方法进行改造,在sha1后的字符串,再用自己的方法修改里面字符的排序;
    * 用c来写这个签名方法,包括密钥等,然后编译成静态库,iOS/android中来使用这个静态库;

    以上只是我们想出来的解决方法,我们在这方面没有啥经验啊,不知道这些做法是否真的有效,或者有没有大幅增加破解的难度呢,也想问问大家有没有其他解决方案啊?
    57 条回复    2017-02-28 15:30:36 +08:00
    min
        1
    min  
       2013-11-21 10:32:57 +08:00
    服务器端怎么知道那些请求是来自盗用者的呢?
    kstsca
        2
    kstsca  
       2013-11-21 10:42:07 +08:00
    矛与盾 基本无解
    nocoo
        3
    nocoo  
       2013-11-21 10:43:19 +08:00   ❤️ 1
    akira
        4
    akira  
       2013-11-21 10:51:50 +08:00   ❤️ 2
    访问接口的时候,带上用户信息,例如用户id,udid之类的。
    用户id不合法的禁止调用。
    然后给每个用户设定个阀值就行了。

    ps: 任何只依赖app本地代码的功能,都是可逆可破的。时间差别而已
    Livid
        5
    Livid  
    MOD
       2013-11-21 10:54:31 +08:00   ❤️ 1
    如果一开始就设计成 https 的,那么别人就更难看到 URL 了。
    sun391
        6
    sun391  
       2013-11-21 10:57:09 +08:00   ❤️ 1
    所有请求多加个验证信息 比如说是 userid+timestamp 对称加密
    密钥写在c里

    不过这也只是增加了破解难度而已,索性就在规则上限制,一个userid只能调用X次/天,user创建时+验证码、邮箱验证(总之不能让他全自动注册)
    wxstorm
        7
    wxstorm  
       2013-11-21 11:00:04 +08:00   ❤️ 1
    https只能保证网络上数据被截获了是破解不了的。
    但是如果客户端被破解,https有啥用。。。
    adow
        8
    adow  
    OP
       2013-11-21 11:05:26 +08:00
    @akira
    @min

    恩,现在我们在请求时没有用户身份信息的,App也不需要用户登录,签名时的密钥都是同一个,保存在代码里的,所以暂时也无法确定盗用者的身份。要加上身份这一层就需要多添加额外的流程了,比如注册什么的,或者简单点就是用推送的deviceToken来标识身份。
    binux
        9
    binux  
       2013-11-21 11:13:26 +08:00   ❤️ 1
    假如你的app是一个黑盒,黑盒的输入是用户操作,中间有个过程是将用户操作编码加密发送出去。
    我都拿到你的app了,再不济,难道不能把用户操作去掉,直接黑盒使用编码加密功能吗?
    adow
        10
    adow  
    OP
       2013-11-21 11:19:24 +08:00
    @binux 是啊,我也这么想,即使我用c封装成静态库,你反编译后看的也许麻烦点,不过我要是直接用这个库进行编码岂不是更容易了,越想越绕了,难不成真的无解么。

    对了,我看到别人说,反向obj-c的工程貌似要难点么,而反向Android的java代码却似乎比较容易读。我们的Android项目是外包给另一个公司做的,我们想让他混淆一下java的代码,他们说项目涉及的模块还有第三方包太多,没法做混淆了,所以我才想到用c写一个,然后给iOS/Android用。
    wxstorm
        11
    wxstorm  
       2013-11-21 11:20:16 +08:00
    我觉得比较现实点的做法是 限制每个http接口在同一个客户端上的访问次数,比如同IP一天只能访问多少次,超过了要么就禁掉,要么弹个图片验证码让输入。

    走加密之类的,只要你的密钥存在一个可以发现的地方,都是可破解的~~
    humiaozuzu
        12
    humiaozuzu  
       2013-11-21 11:21:06 +08:00   ❤️ 1
    @Livid 加一个证书中间人攻击一样拿API数据
    icyalala
        13
    icyalala  
       2013-11-21 11:21:29 +08:00   ❤️ 1
    假设。。Android版本你已经在编译出了C的链接库,然后用Java调用。。
    那黑客直也可以直接用.so文件来调用接口啊。。。

    就是说,这些实际上都是用户的行为,只要黑客有心,你是很难区分出来的。。
    你只能在服务端验证参数是否合法、用户行为是否正常、调用频率是否OK.做好监控足够了。
    binux
        14
    binux  
       2013-11-21 11:22:46 +08:00
    @humiaozuzu 比如ingress就是这么被破解的
    humiaozuzu
        15
    humiaozuzu  
       2013-11-21 11:29:49 +08:00
    @binux 最近一直在分析各种 API 玩,Protobuf/HTTPS 都是很容易分析的
    同步推的 API 加密没找到方法
    jimrok
        16
    jimrok  
       2013-11-21 11:37:50 +08:00   ❤️ 4
    给你的建议,设备要注册,将device的token上送到服务器去。服务器给每个token下发唯一标识的令牌。如果同一个设备同时在多个ip同时访问,果断封掉这个token。
    tabris17
        17
    tabris17  
       2013-11-21 11:44:00 +08:00
    每个设备或者客户端都需要唯一标识,每次请求都要发送这些标识,只要封掉那些异常请求的标识就行了。比如单位时间发送过多请求
    darasion
        18
    darasion  
       2013-11-21 11:44:26 +08:00   ❤️ 2
    我觉的可以这样:
    1. 升级 app,升级接口,旧接口保留
    2. 旧接口一直保留,但使用假冒的数据,做的像真的一些。

    如果没有人注意你升级了接口,那利用你接口的人就懒得更新它的东西了。
    Sfan
        19
    Sfan  
       2013-11-21 11:45:51 +08:00   ❤️ 1
    用c来写这个签名方法,包括密钥等,然后编译成静态库,iOS/android中来使用这个静态库;
    我觉得还是这个可靠...
    sunwenjun
        20
    sunwenjun  
       2013-11-21 11:47:33 +08:00   ❤️ 1
    @humiaozuzu , 没有服务器的证书 https也能破解?
    adow
        21
    adow  
    OP
       2013-11-21 11:48:17 +08:00
    @jimrok
    @tabris17 但是他也可以发送一个伪造的deviceToken到服务器上然后获取令牌啊,我是不是应该发封掉这个token的时候就封掉这个ip,这样他就不能反复获取了,如果他是从服务器上发起的话这样应该就很难继续用了吧?
    jimrok
        22
    jimrok  
       2013-11-21 12:02:00 +08:00
    @adow 这个是避免不了的,还是要验证这个device的合法性,例如为这个设备推送一个token.但总能找到办法获取这些信息。根本还是要限制api的请求次数。例如同一个api,客户端1分钟内不能超过100次请求。这样盗用就没有什么价值了,换个思路,如果有人盗用你的接口,是件很美好的事情,你应该开放你的接口,使用oauth注册,让调用者很爽,这样他就离不开你了。如果换了我还求之不得让人调用,害怕我的文档写的不够好,别人不会调用。
    favormm
        23
    favormm  
       2013-11-21 12:12:50 +08:00   ❤️ 1
    这个应没有办法,因为你的接口来本就是给你客户端用的。 无论如何在你的客户端都会还原为原始数据。hack最终是可以在app内存中拿到这些原始数据与你所有的数据流操作方法。然后反汇编为高级代码,并模拟一个客户端与你服务器通信。
    zhujinliang
        24
    zhujinliang  
       2013-11-21 12:18:17 +08:00   ❤️ 1
    改成websocket的
    txlty
        25
    txlty  
       2013-11-21 12:22:14 +08:00   ❤️ 1
    这个问题,无解。你花多长时间限制,盗用者花多长时间破解。
    限制设备的话,盗用者可以凭空虚拟出无数个设备。
    封IP的话。。移动的出口IP并不多。都是单个IP配大量设备。
    txlty
        26
    txlty  
       2013-11-21 12:34:58 +08:00
    很好奇,盗用者是怎么个请求频率?
    是用单台服务器发请求?还是做自己的客户端 在N台手机发请求?

    这个盗用请求频率,和正常用户盯着手机看的请求频率,有什么区别?
    如果大于正常用户请求,那盗用者图的啥?
    如果和正常用户请求频率差不多。那从你的角度看,盗用者就是个合法客户端。
    yangqi
        27
    yangqi  
       2013-11-21 12:43:36 +08:00   ❤️ 1
    把手机想象成普通的客户端就行了, 你服务器总要登录然后开session, 和普通网站验证类似
    adow
        28
    adow  
    OP
       2013-11-21 12:43:43 +08:00
    @txlty
    @jimrok 盗用我们接口对我们服务器压力到不是很大,但是这里面还牵涉一些法律问题,我们和另外两家公司是签署了使用协议的,我们的产品是把A,B两家公司提供的数据进行整合,然后封装成一个独立的接口,我们服务器速度足够快,但是由于我们还要再访问A,B的数据,在请求压力大的时候肯定会给他们带来负担,所以尽可能减少对第三方公司的压力也是我们需要考虑的事情。还有,A,B 公司是授权我们的产品使用他们的数据,现在有另一家公司的产品使用了这个数据,而这个数据明显是从我们的接口上获取的,也会带来潜在的法律问题。
    tabris17
        29
    tabris17  
       2013-11-21 13:03:22 +08:00   ❤️ 1
    @adow 其实这个还是看你业务来的,比如可以增加获取新标识的成本,短信验证等。还有限制两次请求间的时间间隔。
    arron
        30
    arron  
       2013-11-21 13:15:14 +08:00   ❤️ 1
    要想完全防止,的加一个难识别的验证码,这样用户就不愿意了。
    不然就真没辙的,android太好解了。只能限制下访问频率和IP,让人家采集得不那么舒服。

    如果你的数据量很大。限制下频率和ip,即使人家用2000个ip去采集,一秒种采集一次,一年都采集不完的话,人家自然木有兴趣了...
    arron
        31
    arron  
       2013-11-21 13:15:51 +08:00
    然后就是找到采集你的人或公司, 告他去...
    dorentus
        32
    dorentus  
       2013-11-21 13:46:04 +08:00   ❤️ 1
    法律问题就通过法律方式解决呗。
    当然你可以故意提供一些钓鱼数据来证明对方确实是在未经授权使用你们的接口。
    chundong
        33
    chundong  
       2013-11-21 13:51:16 +08:00   ❤️ 1
    @adow 如果是用device token 的请求次数来判断是否是盗用的话,建议不要封掉它,返回一些假数据回去,貌似美丽说就是这么做的,讲ANTI-SPA的那段,但是跟你的情况不太一样,他们是想封掉推广链接,http://www.infoq.com/cn/presentations/Beautiful-architecture-development-change
    wupher
        34
    wupher  
       2013-11-21 14:22:34 +08:00   ❤️ 1
    使用非对称加密如何?
    用户在注册时生成一对密钥,公钥提交,私钥存于本地钥匙链。
    每次关键请求以私钥签名,服务器公钥验证。
    发现该客户请求异常,予以锁定,要求用户改密或其它方式来更改密钥。
    比直接用sha1,AES,3DES这类,应该会好点。
    愿意的话,就再挂https也行。
    lvye
        35
    lvye  
       2013-11-21 14:38:48 +08:00   ❤️ 1
    破解与否在于成本,ios再难越狱,还是会有人会去破解。
    你只能多设点限制,防住一部分人,让他的成本不断加大。
    victor
        36
    victor  
       2013-11-21 15:13:38 +08:00   ❤️ 1
    @jimrok 感谢已发送。

    @adow 我觉得 @jimrok 说的:“服务器给每个token下发唯一标识的令牌。如果同一个设备同时在多个ip同时访问,果断封掉这个token。” 这个法子比较好。如果你实现了,能介绍一下怎么在服务器端判断一个令牌每分钟请求多少次吗?
    adow
        37
    adow  
    OP
       2013-11-21 15:15:00 +08:00   ❤️ 1
    我现在想只让他的破解成本高一点

    * 使用https的话,他通过伪造一个证书来解码数据有多麻烦;
    * 如果我为每个设备生成私钥,然后通过https传递,本机保存在iOS的keychains里,要想把他提取出来的话难度高不高,还有Android下面有没有类似的安全保存数据的方案啊;
    orzfly
        38
    orzfly  
       2013-11-21 15:29:24 +08:00   ❤️ 1
    @adow 拆 HTTPS 的其实很简单,例如 http://fiddler2.com/ 这种东西就行,几秒的事情。
    tabris17
        39
    tabris17  
       2013-11-21 15:32:16 +08:00   ❤️ 1
    增加破解成本最好的办法就是采用私有通信协议
    cxh116
        40
    cxh116  
       2013-11-21 16:03:25 +08:00   ❤️ 1
    @tabris17 提到的方法不错,不一定要私有协议,用http协议也可以,只是返回的数据加密. 密钥里应该包含设备token和时间等字段,生成密钥和解密最好都是用c写,这样难道应该会大很多.
    missdeer
        41
    missdeer  
       2013-11-21 16:03:49 +08:00   ❤️ 1
    https是挡不住api分析的,现在好些工具都自带一个证书装到设备上再把设备代理指向工具开的端口就行了,比如上面XD说的fiddler2,mitmproxy等等
    missdeer
        42
    missdeer  
       2013-11-21 16:06:27 +08:00   ❤️ 1
    另外,比较怀疑用C写代码能增加复杂度的说法,在Android上用NDK写的代码最后也是跑在dalvik上,反编译这个字节码相对机器码来讲还是容易的多吧
    tabris17
        43
    tabris17  
       2013-11-21 16:26:01 +08:00
    多线程+私有协议能大大增加破解复杂度
    jimrok
        44
    jimrok  
       2013-11-21 16:30:03 +08:00   ❤️ 1
    @victor 这个简单,你只需要一台redis就可以高速记录下来。每分钟产生一个hash表,存放每个token的调用次数。一旦某个计数超出了阈值你就执行你的策略就好了。
    qiongqi
        45
    qiongqi  
       2013-11-21 16:48:56 +08:00   ❤️ 1
    @victor 同上,Leaky Bucket
    adow
        46
    adow  
    OP
       2013-11-21 19:51:52 +08:00
    @jimrok
    @victor
    @qiongqi

    如果是防止接口被他滥用,的确是可以这样做,如果他是从一台服务器上来请求我们的接口的话,大规模的调用是应该能够被发现的。可是现在他还直接做了一个Android的App(还有一个微信的应用),里面就用了我们这个接口,所以这么多设备都去单独获取token的话,我们是无法发现有啥异常的吧?
    adow
        47
    adow  
    OP
       2013-11-21 20:10:08 +08:00
    看了大家的建议,我这样来做的话如何:

    * 修改一下签名的方法使得不那么大众(现在是和OAuth里的签名方法一样的);
    * 每次App启动时到服务器上去获取密钥,密钥不保证在文件里,每次都启动都不一样,鉴于即使用https访问来获取密钥也能被看出来,我们想要不要直接写一个基于tcp/ip的通信的程序,用来创建和传递密钥,而传输的数据是一种自定义格式的,也可以再次加密解密什么的。不过我们都没写过这样的程序,感觉好像挺复杂的样子啊,真的要做到这样的地步么,我还真纠结;
    wwqgtxx
        48
    wwqgtxx  
       2013-11-21 21:52:03 +08:00 via Android   ❤️ 1
    弄一个私有的协议,好好混淆一下,用c封装,apk校验不通过就不允许调用,在外侧调用jni就行了
    victor
        49
    victor  
       2013-11-21 22:02:21 +08:00   ❤️ 1
    @adow 如果你真的確定對方偷用你的數據,不如直接一個電話過去警告對方。不行就發律師函。
    VYSE
        50
    VYSE  
       2013-11-21 22:41:48 +08:00 via Android   ❤️ 1
    https协议,java客户端都是直接看通讯协议的节奏。
    再防也顶多像腾讯一样搞得cracker烦到家,还是能搞出东西来。

    直接封盗用ip和找律师吧
    gluttony
        51
    gluttony  
       2013-11-21 23:12:00 +08:00   ❤️ 1
    @adow 用现成的SSL就行,客户端验证证书的正确性以防止中间人嗅探,app里存的证书要混淆一下。 http://www.inmite.eu/en/blog/20120314-how-to-validate-ssl-certificates-iOS-client
    sprhawk
        52
    sprhawk  
       2013-11-22 13:51:20 +08:00   ❤️ 1
    没有绝对的安全,我们先分析楼主的需求,楼主这个不用登录就可以使用的信息真的很重要,不能让别人访问吗?根据安全的等级,来确定要使用的策略吧

    不管让app发什么,我们都很难确保app的身份,嵌在app内的信息及算法,无法100%保证不被别人获取到,所以只能提高对方拿到这个关键信息的门槛了。
    gamexg
        53
    gamexg  
       2013-11-29 21:07:09 +08:00   ❤️ 1
    和对抗外挂类似,看过类似的文章。

    不知道你的实际情况,比较好的办法是做一些小的标志来识别是否盗用的接口,发现是非法用户的话也不要立即报错,而是延时+随机的返回错误的数据。

    小的标记可以是:
    你的程序会按特定的顺序使用负载均衡的域名,如果顺序大量异常的就是非法客户端。
    看似随机数或时间的参数,但其实和用户id或者其他的参数有一定的关系。
    自己的程序每次请求之间的间隔必定在多少秒之间。
    故意让服务器接口返回错误,你的程序会收到错误时会不更改序列号直接重发上次的请求。如果请求序列号变了就证明是非法的客户端。

    可以找一些类似的东西来做标记,然后可以根据各个标记被触发的情况来锁定非法客户端。
    gamexg
        54
    gamexg  
       2013-11-29 21:20:31 +08:00
    还有其他的小标记,例如你的程序必定会去取广告,或者检查更新,但是如果一个客户端没有检查版本更新就直接使用您的api了就有很大的可能性证明对方是非法客户端。

    就是一个观点,从各种不引人注意的地方设套,找出非法客户端。

    多弄些类似的标记就会让对方烦死的,不过你做起来也会比较麻烦了。
    yinxingren
        55
    yinxingren  
       2013-12-06 19:00:32 +08:00   ❤️ 1
    所有的这些动作只是加大盗用/破解的难度,但貌似也只能这么做了。
    昨天crack一个android app时,发现有很多jnl调用,那个作者是写了一个库,编成了.so机器码
    逆向了下能看到里面存放着的公钥,就是不去,由于个人能力有线没能搞定这个。
    所以这种办法还是可以做的
    onlyshit
        56
    onlyshit  
       2016-01-12 16:24:32 +08:00
    @adow 可以的吧。。。
    woostundy
        57
    woostundy  
       2017-02-28 15:30:36 +08:00
    @humiaozuzu HTTPS 双向验证,中间人证书就没用了。然而 app 被破解怎么都是无解。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2689 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 45ms · UTC 04:20 · PVG 12:20 · LAX 21:20 · JFK 00:20
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.