基于浏览器的 xmlhttp/js/perl/php 游戏的作弊预防

Posted

技术标签:

【中文标题】基于浏览器的 xmlhttp/js/perl/php 游戏的作弊预防【英文标题】:cheat prevention for browser based xmlhttp/js/perl/php game 【发布时间】:2010-12-17 05:20:55 【问题描述】:

假设在基于浏览器的游戏中,完成一些操作(为简单起见,假设有人点击一个链接,他们的分数增加了 100)点击这个链接,该链接将有一个 URL,例如 increase_score.pl?amount=100 什么样的预防是否有人只是向网络服务器发送请求以执行此命令:

    一遍又一遍地没有真正完成点击链接和的任务 向服务器发送虚假请求,其中数量设置为类似 100000 的值。

我知道检查HTTP_REFERER 但我知道人们可以绕过它(不确定如何准确),除了检查第二个选项的一些界限之外,我有点难过。有人遇到过类似的问题吗?解决方案?

【问题讨论】:

您的应用程序应该知道该操作是否被允许。 某人可以将请求序列发送到服务器,使他们能够到达允许该操作的点 那么你的服务器实际上不应该给分。 关于为什么 HTTP_REFERRER 是一种容易被绕过的预防措施的“不确定如何准确”的评论 WRT 表明通常有很多关于 HTTP 协议和 CGI​​ 的内容您不知道,这将导致如果您正在考虑 Web 应用程序的安全性,则会出现许多问题。熟悉 HTTP(标头、不同版本)、代理、CGI、javascript、XSS、Web 服务器等将非常有益。 【参考方案1】:

如果您希望游戏仅在您的服务器上运行,您还可以在接收技巧中检测信号从哪里发送,并忽略任何不是来自您的域的内容。如果您必须从您的专用域运行以提交分数,那么篡改您的代码将是一件非常痛苦的事情。

这也阻止了 CheatEngine 的大部分技巧。

【讨论】:

游戏(至少是用户交互部分)仍然会在客户端运行,而不是在服务器端。我不明白你怎么能阻止这个。【参考方案2】:

听起来您的游戏的一个组件需要请求限制。基本上,您跟踪特定客户访问您网站的速度,并且当他们的速度超过您认为合理的速度时,您开始放慢对该客户的响应。有各种级别,从低级 IP 过滤器到您在 Web 服务器中处理的内容。例如,*** 在 Web 应用程序中有一点可以捕捉到它认为太多的编辑太靠近了。如果您想继续,它会将您重定向到您需要回复的验证码。

至于其他位,您不仅要验证所有输入的形式(例如,它是一个数字),还要验证值是否合理(例如,小于 100 或其他)。如果您发现客户在做一些有趣的事情,请记住这一点。如果您发现同一个客户经常做一些有趣的事情,您可以禁止该客户。

【讨论】:

【参考方案3】:

这里有几点需要注意。

首先,您的服务器对此类内容的请求应该是 POST,而不是 GET。只有GET请求应该是幂等的,不这样做其实是a violation of the HTTP specification。

其次,您在这里看到的是经典的客户信任问题。您必须相信客户端会向服务器发送分数或其他游戏间隔信息,但您希望客户端发送非法数据。防止不允许的操作很容易 - 但在 允许的 操作中防止犯规数据的问题要大得多。

Ben S 对您如何设计客户端和服务器之间的通信协议提出了很好的建议。允许将点值作为可信数据发送通常不是一个好主意。最好表明发生了一个动作,并让服务器计算应该分配多少点,如果有的话。但有时你无法解决这个问题。考虑一个赛车游戏的场景。客户端必须发送用户的时间,它不能被抽象为像“completedLevelFour”这样的其他调用。那你现在怎么办?

Ahmet 和 Dean 建议的令牌方法是合理的 - 但并不完美。首先,令牌 still 必须传输到客户端,这意味着它可以被潜在的攻击者发现并被恶意使用。另外,如果你的游戏 API 需要是无状态的怎么办?这意味着基于会话的令牌身份验证已过时。现在您进入了客户信任问题的深层、黑暗的内部。

您几乎无法做到 100% 万无一失。但是你可以让作弊非常不方便。考虑 Facebook 的安全模型(每个 API 请求都经过签名)。这非常好,并且需要攻击者实际挖掘您的客户端代码,然后才能弄清楚如何欺骗请求。

另一种方法是服务器重放。就像赛车游戏一样,不仅仅是将“时间”值发送到服务器,还具有记录时间并将其全部发送的检查点。为每个间隔建立现实的最小值,并在服务器上验证所有这些数据都在既定范围内。

祝你好运!

【讨论】:

【参考方案4】:

短版:你不能。您从客户端(浏览器)获得的每条数据都可能被知道自己在做什么的人手动欺骗。

您需要从根本上重新考虑应用程序的结构。您需要对应用程序的服务器端进行编码,使其将来自客户端的每条数据都视为一堆肮脏的谎言,直到它可以向自己证明数据实际上是合理的。您需要避免给服务器一种“如果客户端告诉我这样做,显然它是允许告诉我这样做的”的心态。

方法错误: 客户:玩家史蒂夫说要给玩家史蒂夫一亿积分。 服务器:好的!

正确的方式: 客户:玩家史蒂夫说要给玩家史蒂夫一亿积分。 服务员:好吧,让我先看看玩家史蒂夫在这个时间点是否允许给自己一个亿万积分……啊。他不是。请向玩家 Steve 显示这条“Go Fsck Yourself, Cheater”消息。

至于告诉谁已登录,这很简单,只需将一个 cookie 交给客户端,该 cookie 的值是你在服务器上跟踪的几乎不可能猜到的值——但我假设你知道如何处理会话管理。 :-)(如果你不这样做,Google awaits.)

【讨论】:

爸爸,这是你的大整数。【参考方案5】:

我建议为每个操作创建一个特定的 URL。大致如下:

/score/link_88_clicked/
/score/link_69_clicked/
/score/link_42_clicked/

每个链接都可以做两件事:

    在会话中标记该链接已被点击,这样它就不会再次跟踪该链接。 增加他们的分数。

【讨论】:

这不会很好地扩展并且不必要地混淆应用程序。 URL 混淆是我所追求的。只需让玩家更难修改 URL 并获得分数优势。但是,我很好奇为什么这不能很好地扩展?解析分数并分派到方法调用的 mod_perl 处理程序似乎可以很好地扩展。【参考方案6】:

扩展 Ahmet 的响应,每次加载页面时,都会生成一个随机密钥。将密钥存储在用户会话中。将随机密钥添加到每个链接,以便获得这 100 分的新链接是:

increase_score.pl?amount=100&token=AF32Z90

点击每个链接时,检查以确保令牌与会话中的令牌匹配,然后创建一个新密钥并将其存储在会话中。每次他们提出请求时都会有一个新的随机密钥。

如果他们给你错误的密钥,他们会尝试重新加载页面。

【讨论】:

只是不要禁止人们这样做 - 重新加载页面是有正当理由的,例如尝试查看是否有任何更改或重新启动浏览器。 你所做的只是让你的应用程序变得更复杂,并且在作弊程序中需要相应的复杂度。这不是你想参加的军备竞赛,因为作弊者实际上有无限的时间来研究你的 Javascript,而且你无法实时更改它来做出回应。 其实这可能会导致一个问题——如果用户到达带有这样一个链接的页面并刷新,随机值会发生变化,并且该链接在从未被点击时变得不合法。跨度> 这仍然不安全,因为您可以修改 amount= 并保留令牌。安全的方法是为每个 link 生成一个令牌,然后只使用令牌作为参数,并在提交令牌时查找实际操作。这样,用户只能调用页面上真正存在的操作。当然,一旦一个令牌返回,或者在超时之后,您就会使所有令牌失效......这可以防止重放攻击。 1.谁说关于 Javascript 的? 2.如果你刷新,你也应该刷新令牌。 3. 是的,您可能不希望将 amount=x 作为参数。【参考方案7】:

游戏(应用程序)的逻辑应该基于不信任来自用户的任何东西的规则。

HTTP_REFERER 可以被任何网络客户端欺骗。

【讨论】:

【参考方案8】:

您可以使链接动态化,并在其末尾更改散列。在给定的时间段内验证哈希是否正确。

这取决于您允许点击的频率,其复杂性会有所不同。

【讨论】:

【参考方案9】:

如果您按照您的建议实施游戏,没有什么能阻止他们这样做。

您需要在服务器上实现游戏逻辑并仅在服务器验证操作后分配积分。

例如:当有人投票支持您的问题时,这不会作为提高您声誉的命令发送。该网络应用程序只是对服务器用户 X 对问题 Y 投了赞成票。然后,服务器验证数据并在一切检查完毕后分配分数。 (不是说 SO 是游戏,但需要的逻辑是类似的。)

【讨论】:

@JB: 哈哈哈,是的……而且我的分数是超过9000! :D @JB:当然不是。这是一个简单的社区,有一个机制——嘿!我的分数几乎达到了700!来吧,为大整数再投一票,来找爸爸....【参考方案10】:

带有 cookie/会话的令牌。

【讨论】:

以上是关于基于浏览器的 xmlhttp/js/perl/php 游戏的作弊预防的主要内容,如果未能解决你的问题,请参考以下文章

浏览器窗口之间是不是可以进行基于事件的通信? [复制]

如何编写基于Web浏览器的多人游戏?

基于浏览器的HTML5地理定位

基于浏览器的 REST api 身份验证

带有缩略图查看器的基于浏览器的远程桌面

在基于 Java 的桌面应用程序中嵌入浏览器 [重复]