加密,防刷,惩罚处理方案(初搞)

这个方案涉及到客户端加密,服务器解密,防外挂,减少一定量的刷机行为

分析:

以泰国玩家为案例,之前文丰做了比较详细的分析
http://192.168.16.108:3000/boards/4/topics/707
总结为:1,利用工具修改客户端数据;
2,找到某些漏洞进行刷服务器;
3, 不排除有玩家进行ddos攻击;
4,外挂出现。
目前DAU是75W水平,1 nginx,25 resin,10 memcached,12 mysqldb.

设想:

首先大家想到的是加密,客户端数据加密,即对客户端传送给服务器的数据加密;
数据加密了,之前在数组里的token的就直接可以用玩家uid,做会话功能。
取客户端时间戳作为刷机校验码:把时间戳携带在每个返回的数组里,服务器端的MC
里对应其上次带回的时间戳,以<key=uid,value=client_time>,时间精确到毫秒级别,
服务器拿着此次返回的时间戳与上次的时间戳进行验证,如果发现两个值的差值是0
到某个毫秒级别,则判这次请求非法,则返回,同时记录日志,如果同一个用户发生
这种操作达到某个量级,则触发惩罚机制。

考虑到性能和服务器压力,我们可以对不同的命令做不同的处理:

命令分类: 1,初始化命令init_cmd,如玩家初始化游戏时,会时间或极短时间内发送不同的命令;
2,普通命令common_cmd:相对一些简单操作,如读缓存等,不涉及到事务或操作重要数据的命令;
3,重量级命令weight_cmd:相对一些复杂操作,如耗CPU,内存,像决对性的对DB的查询,或大量对像的修改命令;
4,并发命令concurrent_cmd:涉及到事务的,数据重要的操作,如买卖道器物品,兑换,升级等。

命令分类是分散来自不同的命令我们给出不同机制的处理,相对减轻服务器压力,通过分析日志,记录玩家非常规操作
行为,按命令级别做出不同级别的处理,同时依据不同的命令级别我们选用不同的控制频率 Ft。


设计:

flash client:
//客户端数组
String[] params = [cmd,param1,param2....,client_time,uid];
cmd 命令,param* 参数,client_time 客户端时间戳(精确到毫秒),uid 用户ID
客户端对数组DES加密成一个字符串参数 传给服务器端;(开发中,分出debug模式与正式版模式,利于开发人员的调试)
params-------DES加密------>"xxxxxxxxxxxxxxxxxxxxx";
加密KEY,是固定不变,还是按时间如周,或月的频率改变,大家可讨论,如果是变化的注意时间边界值的处理.

java server:

解密客户端参数:"xxxxxxxxxxxxxxxxxxxxx"-----解密---->params = [cmd,param1,param2....,client_time,uid];

用户ID: uid
当前用户请求业务命令: cmd
此次请求客户端时间戳:client_tim
上次请求时间戳: tc
命令集: xxxxx_cmd
可刷的时间间隔: Ft
惩罚度: Pn
Memcached: mc

switch(cmd)

init_cmd:
//按DAU为150W分析,玩家每天登录游戏必须的操作的命令;
//按每位玩家平均每天20次操作,数据级很大,暂不作监控处理;
common_cmd:
//因为是只做缓存查询操作,只要检验出在极暂时间内发请求,则判它为刷机行为,并返回,不提供服务;
Ft=f1;
weight_cmd:
//同common_cmd处理,并进入惩罚机制,惩罚别级:轻;Pn=p1;
Ft=f2;
concurrent_cmd:
//同common_cmd处理,并进入惩罚机制,惩罚别级:重;Pn=p2;
Ft=f3;

校验机制:

long tc=mc.get(uid);//取出该用户的上一次请求的客户端时间戳;
if(tc == null){//如果因为第一次访问或过期失效为null;
mc.set(uid,client_time);//把此次从客户端返回的时间戳存入mc;
return 0;
}else if(client_time-tc==0){//如果上次存入mc的时间戳和此次返回的时间戳相等,则表示为非法请求,并返回;
return 2;
}else if(client_time-tc < Ft){
mc.replace(uid,client_time);
return 1;
}else{
mc.replace(uid,client_time);//把此次从客户端返回的时间戳存入mc;
return 0;
}
依次返回结果值为:0,1,2;

惩罚机制:

设校验机制返回的结果值为 f (0<=f<=2);
惩罚度: pn (p1>p2>2)

if(f>0){
long pn= mc.addOrIncr("PUNISH_"+uid,f);
if(cmd is weight_cmd && pn>=p1){
//实现具体的惩罚规则;
//限时登录
//归零
mc.addOrIncr("PUNISH_"+uid,0);
}else if(cmd is concurrent_cmd && pn>=p2){
//实现具体的惩罚规则;
//限时时间长或罚金币 E币 或封号处理
归零
mc.addOrIncr("PUNISH_"+uid,0);
}

}


问题:

因为每个玩家的校验码存放在mc里,又基于我们的系统是分布式架构,所以去mc里取 tc(cliemt_time) 时会存在脏读情况,
是否考虑每个resin里存放一个当天有效的ConcurrentHashMap<uid,client_time> resin_map.
校验机制如下:

long tc=resin_map.get(uid);//取出该用户的上一次请求的客户端时间戳;(从本地resin内存里取)
if(tc == null){//如果本地取出的值为null;
tc=mc.get(uid);//则再去mc里取;
if(tc == null){//如果mc里也为null;
mc.set(uid,client_time);//把此次从客户端返回的时间戳存入mc;
resin_map.set(uid,cliemt_time);//放入resin map;
return 0;
}else if(client_time-tc==0){//如果上次存入mc的时间戳和此次返回的时间戳相等,则表示为非法请求,并返回;
return 2;
}else if(client_time - tc < Ft){
mc.set(uid,client_time);
return 1;
}
}else if(tc-client_time==0){//如果上次存入mc的时间戳和此次返回的时间戳相等,则表示为非法请求,并返回;
return 2;
}else if(client_time-tc < Ft){
mc.set(uid,client_time);
resin_map.set(uid,cliemt_time);
return 1;
}else{
tc=mc.get(uid);//则再去mc里取;
if(tc == null){//如果mc里为null;
mc.set(uid,client_time);//把此次从客户端返回的时间戳存入mc;
resin_map.set(uid,cliemt_time);//再存主本地resin map;
return 0;
}else if(client_time-tc==0){//如果上次存入mc的时间戳和此次返回的时间戳相等,则表示为非法请求,并返回;
return 2;
}else if(client_time-tc < Ft){
mc.set(uid,client_time);
resin_map.set(uid,cliemt_time);
return 1;
}
}

以上想法是牺牲性能的情况下换取了进一步控制并发,请求在短时间内访问同一台服务器的情况下发挥的作用很大。
结尾:以上主要是对防刷问题提出的方案,由于客户端加密的引入,对以下问题都能有些防范,

1.玩家修改客户端cookie值;
2.玩家找到平台调用游戏的url,修改其中的sessionkey和uid来冒充其它玩家;
3.利用charles修改传递的参数;
4.外挂。

对于ddos的攻击,可在nginx对外来IP做处理,
下面是对人人网上的阳光牧场 卖蔬菜做的10000次并发 返回的一些结果中有部分nginx做了处理
[img]http://dl.iteye.com/upload/attachment/473318/c27e7110-46ff-3def-8a03-bd052c49ea2b.bmp[/img]
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值