手游防破解防外挂技术方案(二)服务端篇

 
因为客户端理论上老是能被人破解,因此全部客户端都是不可信的,只有一个服务端是可信的。客户端的逻辑不可信,客户端发给服务端的数据也不可信。服务端做为惟一可信的中心,须要去验证客户端端发来的数据是否真实可信,而后根据业务需求作一些处理。此外,客户端和服务端的通讯信道可能被人截获,因此通讯协议上要作加密处理。本文分如下几小节:
- 通讯协议加密
- 帐号假装
- 重放攻击
- 异常数据断定
- 一个案例
 

通讯协议加密

在网络上传输重要的数据都不该使用明文,有不少工具能够很容易地截取协议包,抓取和更改其中的数据,好比WireShark。对于长链接,使用TCP或UDP协议,数据会以明文方式存在于协议包中。对于短链接,http现在已不多使用,苹果明确规定开发者须使用https,而非http,对于使用http协议的app会拒审。即便使用https,数据被网络协议层作了加密,但仍不安全。最典型的一种攻击是中间人攻击,作法是攻击者位于客户端和服务端的中间,截获任何一方发送的数据,处理后发给另外一方。对于客户端来讲,中间人假装成了服务端。对于服务端来讲,中间人假装成了客户端。中间人截获到任何一方的数据,都用公钥作一层解密,而后用本身的私钥加密数据发送给另外一方。这种状况下,咱们设计的全部通讯数据会被明文暴露给攻击者。因此,不论使用什么形式的链接以及哪一种网络协议,都须要本身作一层通讯数据加密。
 
典型的方式是用对称加密,客户端和服务端协商好一个密钥,能够经过一个公用的逻辑生成,也能够由服务端生成后传输给客户端。根据共用的密钥,一方对数据作加密后发送,另外一方获取到数据后作解密。通过这样处理后,攻击者抓包后没法简单地获取到解密数据。可是,因为客户端老是能被人破解,经过分析二进制代码或dll中间代码,动态调试等方法,就能逆向出加密解密的算法和密钥。因此,咱们能作的就是增长破解的难度,一般有如下方法:
 
1 用加固加壳反调试等各类方式增长逆向客户端代码的难度。
2 密钥不存明文,而是经过一个函数动态计算返回,函数名和实现都写得尽可能难懂一些。更进一步,能够必定程度牺牲代码的可维护性,不把通用的加密解密算法封装成函数,而是把逻辑分散到网络相关的逻辑中,加大逆向难度。
3 密钥常常更换,好比每一次链接用一个密钥,或者一次客户端启动用一个密钥,或者每个客户端版本用一个密钥。根据业务需求设计不一样强度的密钥逻辑。
4 原始数据最好不用文本格式,而用二进制,好比Protocol buffer。
 
通讯协议加密是防破解中重要的一环,一旦协议被人破解,攻击者就能获取原始数据制造进一步的危害。脱机挂就是其中一种,彻底舍弃了游戏逻辑,只要实现全部通讯协议接口就能假装成客户端和服务端通讯。
 

帐号假装

客户端是彻底不可信的,因此服务端应校验客户端的真实性。通常游戏,服务端会对每一个客户端分配一个惟一标识符ID,以方便管理。攻击者可能会改变本身的ID,从而把本身假装成其余玩家,而后修改或破坏其余玩家的数据。不少攻击者利用这种方式来帮助其余玩家修改数据,从而牟利。因此,咱们得从机制上防止帐号假装。一个解决方案是用token(或cookie)机制,大体流程为:
 
1 客户端登陆时,服务端回给客户端一个token。该token是服务端根据用户ID等重要信息加密后获得。注意加密算法和密钥仅保存于服务端,客户端不知道,因此破解者没法破解。
2 客户端保存该token,之后发送任何请求,都带上该token。
3 服务端响应客户端后续请求时,先根据token和密钥解密获得用户信息,与客户端请求中的其余信息好比用户ID作对比,若不匹配,则校验失败,断定客户端不可信。
 
Token机制实现上的考虑:
1 token算好后是存入缓存,后续收到请求时直接从缓存取,仍是丢弃掉,每次请求时再算一遍。
2 token是否设置过时时间。
 

重放攻击

重放攻击是一种常见的攻击方式。攻击者截取网络包,简单地复制多份,重复发送给接收端,使得接收端误觉得事件发生了屡次。客户端和服务端均可能遭受这种攻击。攻击者能够用这种方式实现各类效果,好比有限时间内屡次攻击怪物,屡次下单购买商品,屡次获取同一商品。解决方案通常有几种:
 
1 自增ID。协议包包含一个自增ID字段,每发送一次自增一次。接收端收到包后,断定ID是否和以前重复,或者增加量得太大,若是是则有重放攻击的风险。这个方案实现简单,但一旦网络协议被破解,很容易绕过去。
2 随机数。协议包包含一个随机数字段,发送端和接收端都用随机数生成器生成一连串随机数,用一个buffer保存以前一段时间接收到过的随机数。接收端收到包后,断定随机数是否在buffer内。更进一步,能够断定收到的随机数是否在将来N个随机数范围内,以断定网络协议是否可能遭到了破解。
3 时间戳。协议包包含一个时间戳字段,接收端断定收到的时间是不是过去时间且和如今时间有较大差值。通常会结合时间戳和随机数,在秒级别的时间戳上拼接一个随机数,若是有重复则有被重放攻击的风险。
 

异常数据断定

所谓道高一尺,魔高一丈。咱们作的不少防破解工做都是在提升破解门槛,增长破解难度,根本上很难防住全部漏洞。可是,在服务端咱们有一种从根本上解决问题的方式。任何一个被破解的数据,在数据上都会体现出一些规律。因此咱们能够玩家的行为数据上寻找线索和模式,以断定该数据是否为做弊玩家。
 
好比,玩家的攻击力,攻击频率,游戏货币的生成和消耗,各类道具的生成和消耗,都会符合咱们游戏设计的一些规律,好比事件的产生不会超过必定频率,某些数值的变化量每次不会超过一个阈值,某些数值的总量不会超过一个阈值,一些数据之间可能存在某种约束关系。咱们能够记录下这些关键数据和事件的消耗,上传给服务端,由服务端的一个特定服务来批量处理这些数据,而后断定玩家是否存在做弊行为。
 
这些断定不必定很是准确。在断定的严格程度上,咱们宁肯漏掉一些做弊玩家,也不能把正常玩家误判为做弊玩家。能够根据数据处理结果,把玩家标记为几个档次:正常,嫌疑,做弊。肯定为做弊的玩家能够自动作警告,封号或清空数据等处理。对于嫌疑玩家,咱们不肯定他是否必定做弊了,就用人工再筛查一遍,并采起相对温和的处理方式。为了知足这些需求,咱们须要创建相对完善的后台工具。
 

一个案例

淘宝上有不少卖游戏破解的服务。好比有个比较流行的弱联网游戏《梦幻家园》的破解服务,能够获得上亿金币和奖杯。卖家提供的破解有两种方式:
 
1 伪造客户端
咱们只须要给破解者提供咱们设备的IDFA,破解者就能够伪造该玩家的客户端,上传一个无限金币的存档。若玩家在系统设置里设置了限制广告标识符,则IDFA获取为0,这个方式就行不通。
2 伪造服务端
按照以下步骤:
(1)从破解者指定网站下载证书,将其添加到系统信任。设置wifi代理,填写为破解者提供的网址。
(2)进入游戏,此时客户端的网络请求会发给破解者的后台程序。破解者解包获得玩家的存档信息,而后修改成无限金币,返回给客户端。
(3)客户端拿到了该存档后,就已是无限金币。删除证书和代理,再进游戏,连到官方服务器,金币仍为无限。
 
这两种破解都须要彻底破解通讯协议,而这又是经过逆向分析彻底能作到的。该游戏的开发商Playrix也作了必定防御,当金币改为无限后玩一段时间,就会弹出警告框,提示检测到您的数据出现异常,被限制参加各类联网活动。这正是咱们前面提到的异常数据断定方案。