arcxingye / EatKano

H5 Games
https://xingye.me/game/eatkano
MIT License
1.77k stars 3.6k forks source link

关于反作弊 #15

Open kasuganosoras opened 2 years ago

kasuganosoras commented 2 years ago

这游戏挺有意思的,群里大伙玩了一晚上,不过有俩地方有待完善:

0x01 加密问题

虽然脚本被加密混淆了,但是可以很轻松通过

encrypt2 = encrypt;
encrypt = function(text){
    console.log(text);
    // 这里想干什么都行,比如把原本的分数替换为 233
    return encrypt2("233" + text.substr(3,));
}

实现打印加密前的明文内容,进行修改也可以。

0x02 变量问题

脚本内的变量全都是全局变量,可以直接被外部修改,例如

setInterval(function() {
    _date1 = new Date();
    _gameTimeNum = 20;
}, 100);

就可以实现暂停时间,加密混淆形同虚设。

实验:排行榜第一名那个嘉然 ID 就是我(狗头

0x03 修复方法

  1. 使用局部变量
  2. 避免直接公开加密方法 貌似没啥用

建议直接用 Swoole 一类的玩意起个 WebSocket 服务器,然后点击事件发送给服务器验证,通过判断点击时间间隔验证操作是否合法,以及是否有出现故意拖慢时间的操作,实现真 · 服务端反作弊(狗头

arcxingye commented 2 years ago

回家过年去了,也没个电脑,建议您来改((( 顺带一提,验证我也想过但是服务器实在吃不消,也不现实,就搁置了

kasuganosoras commented 2 years ago

有空我改改吧,WebSocket 验证其实不怎么消耗性能的,何况是这种单纯就是计算时间差和数字加减的东西,一台学生机大概就够了(

arcxingye commented 2 years ago

实时在线最高可达2k人,且人均一秒5到10次点击,这个数据量全验证想想还是蛮可怕的..

kasuganosoras commented 2 years ago

实际上 WS 依然无法解决作弊问题,可以很轻松通过伪造 WS 连接发送假数据实现绕过 所以……基于浏览器是基本上不可能实现安全的反作弊的…… 只能尽可能地阻止一般人作弊,稍微懂一点 Js 的其实都有办法绕过……

luanmenglei commented 2 years ago

对了,就算改了加密方式,仍然不建议直接把rsa密钥作为明文出现。 这用的免费js加密,随便跑个解码public key就出来了

luanmenglei commented 2 years ago

image 甚至可以通过这样来获取publickey hhhc

luanmenglei commented 2 years ago

在上传数据的地方做点文章吧,不过开源太好破解了(

luanmenglei commented 2 years ago

然后大概是可以没10分上传一次包,然后最后分数只要在预估出来的范围之内就好了。 然后之后再做cps检查之类的,娱乐小游戏真要讲太多反作弊也没意思

kasuganosoras commented 2 years ago

预估范围的最终结果就是开挂的人顶着预估的上限一直刷排行榜,就跟地平线 4 的各大测速排行榜一直被刷到 348.99MPH 一样

arcxingye commented 2 years ago

摆了,我也没什么办法,等大佬们来pr吧

luanmenglei commented 2 years ago

预估范围的最终结果就是开挂的人顶着预估的上限一直刷排行榜,就跟地平线 4 的各大测速排行榜一直被刷到 348.99MPH 一样

然而由此可见就算是单机游戏大厂都无法防止作弊,更别说网页游戏了,所以最多就只能把外挂的成绩尽量往下压

kasuganosoras commented 2 years ago

我的建议是:提交成绩的时候需要附上操作视频记录,可以是b站视频链接等等

idiotWu commented 2 years ago

然后点击事件发送给服务器验证,通过判断点击时间间隔验证操作是否合法

FYI: 点击事件完全是可以手动构造的。所以即使服务器端加了验证,也可以跑出极限分数:

let items = [];

function run() {
  if (items.length === 0) {
    items = [...document.querySelectorAll('.t1, .t2, .t3, .t4, .t5')];
  }

  const target = items.shift();
  const rect = target.getBoundingClientRect();
  const evt = new MouseEvent('mousedown', {
    bubbles: true,
    clientX: rect.left + rect.width / 2,
    clientY: rect.top + rect.height / 2,
   });

  target.dispatchEvent(evt);

  timer = setTimeout(run, 0);
}

// start
run();

// stop
clearTimeout(timer);

屏幕录像(鼠标指针也是画上去的):

https://user-images.githubusercontent.com/6022672/151297987-c5d77712-fb46-4f8b-a3aa-32801ada91ce.mp4

luanmenglei commented 2 years ago

然后点击事件发送给服务器验证,通过判断点击时间间隔验证操作是否合法

FYI: 点击事件完全是可以手动构造的。所以即使服务器端加了验证,也可以跑出极限分数:

let items = [];

function run() {
  if (items.length === 0) {
    items = [...document.querySelectorAll('.t1, .t2, .t3, .t4, .t5')];
  }

  const target = items.shift();
  const rect = target.getBoundingClientRect();
  const evt = new MouseEvent('mousedown', {
    bubbles: true,
    clientX: rect.left + rect.width / 2,
    clientY: rect.top + rect.height / 2,
   });

  target.dispatchEvent(evt);

  timer = setTimeout(run, 0);
}

// start
run();

// stop
clearTimeout(timer);

屏幕录像(鼠标指针也是画上去的):

recording.mp4

但实际上改用canvas就可以彻底解决这个问题

kasuganosoras commented 2 years ago

已经在写新版本了,使用服务端生成连续图片,点击事件全部交由服务端验证,可以实现真正的反作弊(除了图片识别防不住以外,一般的修改数据作弊都能防)

Catkamakura commented 2 years ago

拿python cv2 库简单撸了的“截图,图片识别,定位点击”的脚本最高跑到68分(

zjkwdy commented 2 years ago

拿python cv2 库简单撸了的“截图,图片识别,定位点击”的脚本最高跑到68分(

兄啊,你这效率还不如重写Math.random然后开连点器呢(恼

kasuganosoras commented 2 years ago

拿python cv2 库简单撸了的“截图,图片识别,定位点击”的脚本最高跑到68分(

直接取屏幕指定坐标下的 RGB 颜色,判断下是否有颜色(即不是纯白 255,255,255),有的话就模拟鼠标点击,这样都能轻松跑到 160~170 分,图片识别小题大做了属于是。。

TAOtxi commented 1 year ago

emm看不懂你们在说啥,不过python用selenium刷分还是很方便的,榜单前三都是我 ( 狗头