标签:限时免费 需要 Oday 魔兽世界 比较 技术总结 incr 客户端 bsp
黑客常见的攻击手段有2种。
第一种简单粗暴叫做重放攻击。
第二种就是修改包文。
所谓重放攻击就是攻击者冒充客户端重复发送上一个有效的网络包。
例子1:之前我们一个三国游戏做了限时免费抽卡活动。就是30秒内可以免费抽卡,这在策划看来是一个很紧张刺激的设计环节,如果你手速更快,你可能抢到比别人更多的卡牌。例如你点了抽卡,就会弹出翻牌特效,这个弹出会阻挡玩家的所有操作,你必须看完这个长达大约3秒的特效才能再次点击到抽卡按钮,也就是说策划预想的30秒免费抽卡应该最多产生大约10张。这个设计有什么问题呢?马上就有黑客来告诉(殴打)我们。我们在一次数据库排查中发现一名玩家的牌有数万张,这个数量大约需要花费RMB几十万元吧,但是这个玩家没有充值记录,后来仔细一查才发现是限时30秒免费抽卡活动造成的。他在一次活动中能抽到数千张免费的卡牌,这是为什么?答案就是重放攻击。不要小瞧这种简单粗暴的攻击方式,他能突破客户端界面操作的限制,直接发送有效信息给服务器。
例子2:之前我们一个三国游戏做了征收金币的功能。他的限制是每天每个玩家有3次征收的权利。每天的reset time的时候才会重置3次征收的权利。那么理论上讲,每天每一位玩家就有3次征收的权利。注意服务器的处理方式是产生这次bug的罪魁祸首。
// 服务器处理征收的伪代码 function texas (userId) { // 非阻塞式的从数据库获取这个玩家当时的征收次数 var times = await db.select(‘db_users‘, ‘today_texas_times‘, userId); if (times <= 0) { console.log(‘征收次数耗尽,操作无效‘); return; } // 增加金币并且消耗一次征收次数 await db.increase(‘db_users‘, ‘today_texas_times‘, userId, -1); await db.increase(‘db_users‘, ‘coin‘, userId, 1000); }
如果服务器代码这么写,那么重放攻击就能奏效。这个涉及到多线程问题。重放攻击打了一个时间差。因为两个请求消息几乎同时到这个函数,我们db.select并不会阻塞住主线程,那么texas就可能在非常短暂的时间里面进来2次甚至多次,而db.select这种访问数据库的操作是需要时间的。那么极有可能这2次访问返回值都是1,那么校验就都是合法的,金币最后加了2次,征收次数可能就变成了-1。
如何防御重放攻击呢?常见的做法是在通信包里加入一个状态数字,例如客户端与服务器连接上以后就从1开始发。每一次客户端与服务器发送了一次消息以后这个数字就会增加1。第几次通信这个数字就是几。这样如果只是通过简单的重放攻击的话,服务器就会发现这个包里面的serialNum跟服务器当前的serialNum不匹配。于是就能发现这个重放攻击。那么你说“黑客那么傻吗,他不会注意到状态数字的简单规律吗?”。其实大部分的黑客也就这水平了,因为他们用的发网络包工具就是这么简单,能重放攻击一下,如果没效果他就再去试别点或别的游戏。当然如果你遇到稍微厉害点的黑客,他也会伪造这个状态数字,那么你只需要升级一下状态数字就可以了。我们用伪随机数来做状态数字。例如第一次服务器生成一个随机数种子发送给客户端。这个客户端(注意每一个客户端都是不同的)与服务器都通过从这个随机数种子利用线性同余算法(RandomSeed * BigPrimeA + BigPrimeB)的伪随机来步进随机数来作为这个状态数字。这样就使得黑客在预测下一个状态数字的难度大大增加。当然这种做法并非绝对安全,但是作为游戏来讲,这样级别的安全已经够了。当然如果你做银行系统的话这种安全级别的防御还是不够的。
例子1:篡改包很好理解,就是修改消息包原来的某些参数。一般来说游戏服务器端的设计思想之一就是客户端不可能信任,也就是客户端发送过来的任何包都可能是被篡改过的。我们所要做的就是把服务器的校验工作做好。但如果某些校验的计算量特别大,我们不得不信赖客户端发送过来的数据。例如魔兽世界中玩家的位置更新,由于这个位置校验必须要有完整的物理建模才能完成,要知道物理碰撞计算是相当消耗cpu的,这时候我们不得不信赖客户端给服务器同步的位置信息。当初有些为采矿设计的瞬间移动外挂,甚至简单粗暴的用“变速齿轮(一种修改游戏运行速度)”软件就能轻松使魔兽世界玩家的移动速度大大增加。
例子2:这个例子比较复杂。虽然客户端服务器可以不信任,但是有时候三方网站跟服务器的通信可能就不得不“信任”。例如游戏中的充值问题。首先,客户端向游戏服务器申请充值30元,游戏服务器生成单号以后向三方支付请求订单,三方支付也会生成他平台自己的单号并且告诉游戏服务器单号信息和客户端需要支付的操作(一般是一个url的跳转),游戏服务器再返回客户端支付链接,正常情况下,客户端按照url跳转后正常支付,然后三方支付服务器收到钱以后就会“回调给”游戏服务器,这个玩家确实支付了30元。然后游戏服务器给玩家的账号充值30元相应的金币。但是问题是,如果黑客知道了游戏服务器的回调地址并且窃听到了一个回调包。那么黑客下一次可以点击一个充值1000元,但是这一次他并不会真正支付1000元,而是通过把上一次消息包里面的30元篡改成1000元的这个回调消息发送给游戏服务器,那么游戏服务器就以为用户真的充值了1000元,就会给玩家增加1000元相应的金币。
如何防御篡改包呢?一般来说可以通过加密消息包的方式来防御。因为消息包是密文,黑客在无法理解包文内容的情况下无法修改包文。当然加密解密算法都在客户端里面,如果客户端代码被黑客逆向出来了,那么他仍然可以篡改消息包。只不过要更费劲一些。学过密码学的同学都知道想要绝对安全的加密解密几乎不可能,我们只需要让黑客破解的时候更费劲一些就行了。通过消息包加密基本就可以挡住大部分的黑客篡改包。有些同学觉得加密的消息包不直观,有没有别的方式防御呢。另一种方式也很简单,就是将消息包整体加上一个前后端约定的key通过md5算法形成一个sign。每个消息都要验证这个sign的有效性,就可以防御消息包被篡改的问题。
我们在前后端的通信包里面加入sign字段用于校验包的合法性,加入serial字段用于确保包不被重放攻击。
标签:限时免费 需要 Oday 魔兽世界 比较 技术总结 incr 客户端 bsp
原文地址:https://www.cnblogs.com/changxw/p/12090858.html