阻止人们破解基于 PHP 的 Flash 游戏高分表的最佳方法是啥
Posted
技术标签:
【中文标题】阻止人们破解基于 PHP 的 Flash 游戏高分表的最佳方法是啥【英文标题】:What is the best way to stop people hacking the PHP-based highscore table of a Flash game阻止人们破解基于 PHP 的 Flash 游戏高分表的最佳方法是什么 【发布时间】:2010-09-09 14:12:18 【问题描述】:我说的是动作游戏,没有分数上限,也无法通过重放动作等来验证服务器上的分数。
我真正需要的是 Flash/php 中最强大的加密,以及一种防止人们通过我的 Flash 文件调用 PHP 页面的方法。过去我尝试过一些简单的方法,例如多次调用单个分数并完成校验和/斐波那契序列等,还使用 Amayeta SWF Encrypt 混淆 SWF,但最终都被黑了。
感谢 *** 的回复,我现在从 Adobe 找到了更多信息 - http://www.adobe.com/devnet/flashplayer/articles/secure_swf_apps_12.html 和 https://github.com/mikechambers/as3corelib - 我认为我可以将其用于加密。不过,不确定这会让我了解 CheatEngine。
我需要知道 AS2 和 AS3 的最佳解决方案,如果它们不同的话。
主要问题似乎是 TamperData 和 LiveHTTP 标头之类的东西,但我知道还有更高级的黑客工具 - 例如 CheatEngine(感谢 Mark Webster)
【问题讨论】:
你应该设置分数限制,没有理由你不能这样做,每个级别,总共等等...... 第一个链接不再可用 【参考方案1】:这是网络游戏和竞赛的经典问题。您的 Flash 代码与用户一起决定游戏的分数。但用户不受信任,Flash 代码在用户的计算机上运行。你是索尔。您无法阻止攻击者伪造高分:
Flash 比您想象的更容易进行逆向工程,因为字节码有据可查并描述了一种高级语言 (Actionscript) --- 当您发布 Flash 游戏时,您就是在发布你的源代码,不管你是否知道。
攻击者控制 Flash 解释器的运行时内存,因此任何知道如何使用可编程调试器的人都可以随时更改任何变量(包括当前分数),或更改程序本身。
对您的系统最简单的攻击是通过代理运行游戏的 HTTP 流量,捕获高分保存,然后以更高的分数重播。
您可以尝试通过将每个高分保存绑定到单个游戏实例来阻止这种攻击,例如在游戏启动时向客户端发送加密令牌,可能如下所示:
hex-encoding( AES(secret-key-stored-only-on-server, timestamp, user-id, random-number))
(您也可以使用会话 cookie 来达到同样的效果)。
游戏代码将此令牌与高分保存一起回传到服务器。但攻击者仍然可以再次启动游戏,获得一个令牌,然后立即将该令牌粘贴到重放的高分存档中。
接下来,您不仅要提供令牌或会话 cookie,还要提供高分加密会话密钥。这将是一个 128 位 AES 密钥,它本身使用一个硬编码到 Flash 游戏中的密钥进行加密:
hex-encoding( AES(key-hardcoded-in-flash-game, random-128-bit-key))
现在,在游戏发布高分之前,它会解密高分加密会话密钥,因为您将高分加密会话密钥解密密钥硬编码到 Flash 二进制文件中,所以它可以做到这一点。你用这个解密的密钥加密高分,以及高分的 SHA1 散列:
hex-encoding( AES(random-128-bit-key-from-above, high-score, SHA1(high-score)))
服务器上的 PHP 代码检查令牌以确保请求来自有效的游戏实例,然后解密加密的高分,检查以确保高分与高分的 SHA1 匹配(如果您跳过这一步,解密只会产生随机的,可能非常高的高分)。
因此,现在攻击者反编译了您的 Flash 代码并迅速找到了 AES 代码,该代码像大拇指一样突出,尽管即使它没有,但它会在 15 分钟内通过内存搜索和跟踪器( “我知道我这个游戏的分数是 666,所以让我们在内存中找到 666,然后捕捉任何触及该值的操作 --- 哦,看,高分加密代码!”)。使用会话密钥,攻击者甚至不必运行 Flash 代码;她抓住了一个游戏启动令牌和一个会话密钥,可以发回任意高分。
您现在正处于大多数开发人员放弃的地步 --- 通过以下方式与攻击者相处几个月:
使用 XOR 操作加扰 AES 密钥
用计算密钥的函数替换密钥字节数组
在整个二进制文件中散布假密钥加密和高分帖子。
这主要是浪费时间。不用说,SSL 也帮不了你。当两个 SSL 端点之一是邪恶的时,SSL 无法保护您。
以下是一些实际上可以减少高分欺诈的事情:
需要登录才能玩游戏,让登录生成会话 cookie,并且不允许在同一会话上启动多个未完成的游戏,或同一用户的多个并发会话。
拒绝持续时间少于所玩过的最短真实游戏的游戏会话的高分(对于更复杂的方法,请尝试“隔离”持续时间低于平均游戏持续时间 2 个标准差的游戏会话的高分)。确保您在服务器端跟踪游戏时长。
拒绝或隔离只玩过一次或两次游戏的登录名的高分,这样攻击者就必须为他们创建的每个登录名生成看起来合理的游戏玩法的“书面记录”。
玩游戏期间的“心跳”得分,以便您的服务器在玩游戏的整个生命周期内看到得分增长。拒绝不遵循合理分数曲线的高分(例如,从 0 跳到 999999)。
游戏过程中的“快照”游戏状态(例如,弹药数量、关卡中的位置等),您可以稍后将其与记录的临时分数进行核对。您甚至不必从一开始就检测此数据中的异常情况;你只需要收集它,然后如果事情看起来有问题,你可以回去分析它。
禁用任何未通过您的一项安全检查的用户的帐户(例如,提交未通过验证的加密高分)。
请记住,您在这里只是在阻止高分欺诈行为。 没有什么可以阻止 if。如果你的游戏中有钱,那么有人会打败你想出的任何系统。目标不是阻止这种攻击;这是为了让攻击变得更加昂贵,而不是仅仅在游戏中表现出色并击败它。
【讨论】:
我创建了一个在线游戏社区,我们设计了整个奖励系统来奖励前 10 个百分位数的得分,而不是只奖励最高得分者,而且效果很好,所以试图回避这个问题会有所帮助也! 不错!简而言之,除非游戏在服务器上运行(或至少在服务器上运行健全性检查),否则您无法防止滥用。多人射击游戏也有同样的问题:如果客户端被修改以产生更好的瞄准,你不能在网络协议中阻止它。 我想还可以记录所有用户操作并在服务器上重放它们以验证/确定高分【参考方案2】:您可能问错了问题。您似乎专注于人们用来在高分榜上博弈的方法,但阻止特定方法仅此而已。我没有使用 TamperData 的经验,所以我不能说。
您应该问的问题是:“我如何验证提交的分数是否有效且真实?”具体方法取决于游戏。对于非常简单的益智游戏,您可能会发送分数以及特定的开始状态和导致结束状态的移动顺序,然后使用相同的移动在服务器端重新运行游戏。确认规定的分数与计算的分数相同,并且仅在它们匹配时才接受分数。
【讨论】:
这是我过去用于投票系统的一种技术。您无法阻止人们作弊,但是您可以做的是记录他们的行为,以便检查是否存在作弊行为。对于我们的投票系统,我们曾经存储时间戳和 IP 地址。 [续] 这样我们至少可以看到作弊行为的模式,并在必要时取消人们的资格。我们已经成功使用了很多次。【参考方案3】:一个简单的方法是提供你的高分值的加密哈希值以及它自己的分数。例如,通过 HTTP GET 发布结果时: http://example.com/highscores.php?score=500&checksum=0a16df3dc0301a36a34f9065c3ff8095
计算此校验和时,应使用共享密钥;这个秘密不应该通过网络传输,而应该在 PHP 后端和 flash 前端中进行硬编码。上面的校验和是通过将字符串“secret”添加到分数“500”并通过 md5sum 运行来创建的。
虽然此系统会阻止用户发布任意分数,但它不会阻止“重放攻击”,即用户重新发布先前计算的分数和哈希组合。在上面的示例中,500 分总是会产生相同的哈希字符串。通过在要散列的字符串中加入更多信息(例如用户名、时间戳或 IP 地址),可以减轻部分风险。虽然这不会阻止数据的重放,但可以确保一组数据一次只对单个用户有效。
为防止发生任何重放攻击,必须创建某种类型的挑战-响应系统,例如:
-
Flash 游戏(“客户端”)执行 http://example.com/highscores.php 的 HTTP GET,不带任何参数。此页面返回两个值:一个随机生成的 salt 值,以及该盐值与共享密钥组合的加密哈希。该盐值应存储在待处理查询的本地数据库中,并应具有与其关联的时间戳,以便它可能在一分钟后“过期”。
Flash 游戏将盐值与共享密钥结合起来,并计算一个哈希值来验证它是否与服务器提供的值匹配。这一步对于防止用户篡改盐值是必要的,因为它会验证盐值实际上是由服务器生成的。
Flash 游戏将盐值与共享密钥、高分值和任何其他相关信息(昵称、IP、时间戳)结合起来,并计算哈希值。然后,它通过 HTTP GET 或 POST 将此信息连同盐值、高分和其他信息一起发送回 PHP 后端。
服务器以与客户端相同的方式组合接收到的信息,并计算一个哈希值以验证它与客户端提供的信息是否匹配。然后它还会验证挂起查询列表中列出的盐值是否仍然有效。如果这两个条件都为真,它将高分写入高分表,并向客户端返回一个签名的“成功”消息。它还会从待处理的查询列表中删除盐值。
请记住,如果用户可以访问共享密钥,则上述任何技术的安全性都会受到损害
作为替代方案,可以通过强制客户端通过 HTTPS 与服务器通信,并确保客户端预配置为仅信任由您一个人签署的特定证书颁发机构签署的证书,来避免这种反复可以访问。
【讨论】:
【参考方案4】:我喜欢 tpqf 所说的,但与其在发现作弊时禁用帐户,不如实施一个蜜罐,这样每当他们登录时,他们就会看到他们被黑的分数,并且永远不会怀疑他们被标记为巨魔。谷歌搜索“phpBB MOD Troll”,你会看到一个巧妙的方法。
【讨论】:
这种方法的问题是这些作弊者在留言板等上互相吹嘘,所以它不会真正阻止他们。 我不同意。这听起来是一个非常聪明的方法。【参考方案5】:在接受的答案中,tqbf 提到您可以对分数变量进行内存搜索(“我的分数是 666,所以我在内存中查找数字 666”)。
有办法解决这个问题。我这里有课:http://divillysausages.com/blog/safenumber_and_safeint
基本上,您有一个对象来存储您的分数。在 setter 中,它将您传递的值与随机数(+ 和 -)相乘,在 getter 中,您将保存的值除以随机乘法器以获取原始值。这很简单,但有助于停止记忆搜索。
此外,请查看 PushButton 引擎背后的一些人的视频,他们谈论了一些可以对抗黑客攻击的不同方法:http://zaa.tv/2010/12/the-art-of-hacking-flash-games/。他们是课程背后的灵感来源。
【讨论】:
【参考方案6】:我做了一种解决方法...我给了分数增加的地方(你总是得到 +1 分数)。首先,我从随机数开始计数(比如说 14 ),当我显示分数时,只显示分数 var 减 14。如果饼干正在寻找例如 20,他们将找不到它(它将是 34 在内存中)。其次,因为我知道下一个点应该是什么...我使用 adobe 加密库来创建下一个点应该是的哈希值。当我必须增加分数时,我会检查增加的分数的哈希值是否等于应该的哈希值。如果破解者更改了内存中的点,则哈希值不相等。我执行了一些服务器端验证,当我从游戏和 PHP 中获得不同的分数时,我知道涉及作弊。这是我的代码(我正在使用 Adobe Crypto libraty MD5 类和随机加密盐。callPhp() 是我的服务器端验证)
private function addPoint(event:Event = null):void
trace("expectedHash: " + expectedHash + " || new hash: " + MD5.hash( Number(SCORES + POINT).toString() + expectedHashSalt) );
if(expectedHash == MD5.hash( Number(SCORES + POINT).toString() + expectedHashSalt))
SCORES +=POINT;
callPhp();
expectedHash = MD5.hash( Number(SCORES + POINT).toString() + expectedHashSalt);
else
//trace("cheat engine usage");
使用这种技术 + SWF 混淆,我能够阻止饼干。此外,当我将分数发送到服务器端时,我使用自己的小型加密/解密功能。像这样的东西(不包括服务器端代码,但你可以看到算法并用 PHP 编写):
package
import bassta.utils.Hash;
public class ScoresEncoder
private static var ranChars:Array;
private static var charsTable:Hash;
public function ScoresEncoder()
public static function init():void
ranChars = String("qwertyuiopasdfghjklzxcvbnm").split("")
charsTable = new Hash(
"0": "x",
"1": "f",
"2": "q",
"3": "z",
"4": "a",
"5": "o",
"6": "n",
"7": "p",
"8": "w",
"9": "y"
);
public static function encodeScore(_s:Number):String
var _fin:String = "";
var scores:String = addLeadingZeros(_s);
for(var i:uint = 0; i< scores.length; i++)
//trace( scores.charAt(i) + " - > " + charsTable[ scores.charAt(i) ] );
_fin += charsTable[ scores.charAt(i) ];
return _fin;
public static function decodeScore(_s:String):String
var _fin:String = "";
var decoded:String = _s;
for(var i:uint = 0; i< decoded.length; i++)
//trace( decoded.charAt(i) + " - > " + charsTable.getKey( decoded.charAt(i) ) );
_fin += charsTable.getKey( decoded.charAt(i) );
return _fin;
public static function encodeScoreRand(_s:Number):String
var _fin:String = "";
_fin += generateRandomChars(10) + encodeScore(_s) + generateRandomChars(3)
return _fin;
public static function decodeScoreRand(_s:String):Number
var decodedString:String = _s;
var decoded:Number;
decodedString = decodedString.substring(10,13);
decodedString = decodeScore(decodedString);
decoded = Number(decodedString);
return decoded;
public static function generateRandomChars(_length:Number):String
var newRandChars:String = "";
for(var i:uint = 0; i< _length; i++)
newRandChars+= ranChars[ Math.ceil( Math.random()*ranChars.length-1 )];
return newRandChars;
private static function addLeadingZeros(_s:Number):String
var _fin:String;
if(_s < 10 )
_fin = "00" + _s.toString();
if(_s >= 10 && _s < 99 )
_fin = "0" + _s.toString();
if(_s >= 100 )
_fin = _s.toString();
return _fin;
//end
然后我将变量与其他假变量一起发送,它只是在途中迷路了......对于小型 Flash 游戏来说这是很多工作,但在涉及奖品的情况下,有些人会变得贪婪。如果您需要任何帮助,请给我留言。
干杯,伊科
【讨论】:
【参考方案7】:使用已知(私有)可逆密钥进行加密是最简单的方法。我并不完全了解 AS,所以我不确定有哪些类型的加密提供商。
但您可以包括游戏时长(再次加密)和点击次数等变量。
像这样的所有事情都可以进行逆向工程,因此请考虑放入一堆垃圾数据来让人们失去嗅觉。
编辑:在一些 PHP 会话中也可能值得一试。当他们点击开始游戏并(正如这篇文章的评论所说)记录时间时开始会话。当他们提交分数时,您可以检查他们实际上有一个开放的游戏,并且他们提交的分数不会太快或太大。
可能值得计算一个标量,看看每秒/分钟游戏的最高得分是多少。
这些事情都不是不可回避的,但在人们可以看到的 Flash 中包含一些逻辑会有所帮助。
【讨论】:
遵循此方法的任何人还必须包含时间,并验证时间,否则您很容易受到重放攻击。【参考方案8】:根据我的经验,最好将其视为社会工程问题而不是编程问题。与其专注于让它不可能作弊,不如专注于通过消除作弊的动机来让它变得无聊。例如,如果主要诱因是公开可见的高分,则只需延迟显示高分的时间就可以通过消除作弊者的积极反馈循环来显着减少作弊。
【讨论】:
但这也消除了对实际玩家的即时高分的积极反馈,因此您正在降低游戏质量。【参考方案9】:您不能信任客户端返回的任何数据。验证需要在服务器端执行。我不是游戏开发者,但我做商业软件。在这两种情况下,都可能涉及金钱,人们会破坏客户端混淆技术。
可能会定期将数据发送回服务器并进行一些验证。不要专注于客户端代码,即使那是您的应用程序所在的位置。
【讨论】:
【参考方案10】:只要您的高分系统基于 Flash 应用程序通过网络发送未加密/未签名的高分数据这一事实,这些数据就可以被拦截和操纵/重放。答案由此而来:加密(体面!)或加密签名高分数据。这至少使人们更难破解您的高分系统,因为他们需要从您的 SWF 文件中提取密钥。许多人可能会在那里放弃。另一方面,只需要一个人来提取密钥并将其发布到某个地方。
真正的解决方案涉及 Flash 应用程序和高分数据库之间的更多通信,以便后者可以验证给定分数是否有点现实。这可能很复杂,具体取决于您拥有的游戏类型。
【讨论】:
【参考方案11】:没有办法让它完全无法破解,因为它很容易反编译 SWF,然后熟练的开发者黑客可以追踪您的代码并找出如何绕过您可能使用的任何加密系统。
如果您只是想通过使用 TamperData 等简单工具来阻止孩子作弊,那么您可以生成一个加密密钥,在启动时将其传递给 SWF。然后使用 http://code.google.com/p/as3crypto/ 之类的东西来加密高分,然后再将其传递回 PHP 代码。然后在服务器端解密后再存入数据库。
【讨论】:
【参考方案12】:您正在谈论所谓的“客户信任”问题。因为客户端(在这个现金中,一个在浏览器中运行的 SWF)正在做一些它被设计做的事情。保存一个高分。
问题是您要确保“保存分数”请求来自您的 Flash 电影,而不是一些任意的 HTTP 请求。一个可能的解决方案是在请求时将服务器生成的令牌编码到 SWF 中(使用flasm),该令牌必须伴随请求以保存高分。一旦服务器保存了该分数,令牌就会过期,不能再用于请求。
这样做的缺点是用户每次加载 Flash 电影时只能提交一个高分 - 您必须强制他们刷新/重新加载 SWF,然后他们才能再次播放以获得新分数。
【讨论】:
【参考方案13】:我通常在高分条目中包含游戏会话的“幽灵数据”。因此,如果我正在制作赛车游戏,我会包含重播数据。您通常已经拥有用于重播功能或幽灵赛车功能的重播数据(与您的上一场比赛比赛,或与排行榜上第 14 号的鬼魂比赛)。
检查这些是非常繁重的体力劳动,但如果目标是验证比赛中的前 10 名条目是否合法,这可能是对其他人已经指出的安全措施库的有用补充。
如果目标是保持高分列表在线直到时间结束而无需任何人查看,那么这不会给您带来太多好处。
【讨论】:
【参考方案14】:一个新的流行街机模组的做法是将数据从 flash 发送到 php,然后返回到 flash(或重新加载),然后再返回到 php。这使您可以做任何您想做的事情来比较数据以及绕过发布数据/解密黑客等。这样做的一种方法是将 2 个随机值从 php 分配到闪存中(即使运行实时闪存数据采集器,您也无法抓取或查看),使用数学公式将分数与随机值相加,然后使用检查它相同的公式来反转它,看看分数是否匹配它,当它最终到达 php 时。这些随机值永远不可见,并且它还会计算交易发生的时间,如果超过几秒钟,那么它也会将其标记为作弊,因为它假定您已停止发送以尝试找出随机值或运行这些数字通过某种类型的密码返回可能的随机值以与得分值进行比较。
如果你问我,这似乎是一个很好的解决方案,有人发现使用这种方法有什么问题吗?或者可能的解决方法?
【讨论】:
Wireshark。 Wireshark 永远是个漏洞。 是的,我试过这个确切的方法......嗯......我不知何故让合法用户被记录为作弊者(该功能一直在我的电脑上工作,但在其他一些电脑上不起作用)...所以现在我只允许作弊...我记录没有通过上述检查的人,我记录得分非常高的人,然后手动滥用他们...通过使他们的分数* -1 :P 他们通常好好开玩笑吧。 “一种方法是从 php 分配 2 个随机值到闪存中(即使运行实时闪存数据采集器,您也无法抓取或查看)” - 请赐教,有吗一种在不被 firebug 或任何其他工具监控的情况下将值从 php 传递到 flash 的方法?【参考方案15】:我认为最简单的方法是每次游戏注册要添加的分数时调用像 RegisterScore(score) 这样的函数,然后对其进行编码、打包并将其作为字符串发送到 php 脚本。 php 脚本会知道如何正确解码。这将停止对 php 脚本的任何直接调用,因为任何强制得分的尝试都会导致解压缩错误。
【讨论】:
【参考方案16】:只有将所有游戏逻辑保留在服务器端才能实现,服务器端也会在用户不知情的情况下在内部存储分数。出于经济和科学的原因,人类不能将此理论应用于除回合制以外的所有游戏类型。例如将物理保持在服务器端的计算成本很高,并且很难像手速一样做出响应。甚至有可能,在下棋时,任何人都可以将 AI 国际象棋游戏与对手相匹配。因此,更好的多人游戏还应该包含按需创意。
【讨论】:
【参考方案17】:实现你想要的东西是不可能的。 Flash 应用程序的内部始终是部分可访问的,尤其是当您知道如何使用 CheatEngine 之类的东西时,这意味着无论您的网站和浏览器服务器通信有多安全,克服它仍然相对简单.
【讨论】:
【参考方案18】:通过AMFPHP 与后端通信可能是个好主意。它至少应该阻止懒惰的人尝试通过浏览器控制台推送结果。
【讨论】:
以上是关于阻止人们破解基于 PHP 的 Flash 游戏高分表的最佳方法是啥的主要内容,如果未能解决你的问题,请参考以下文章
为拯救童年回忆,开发者决定采用古法编程:用Flash高清重制了一款游戏
高分求一个 flash as3.0的关于鼠标拖曳startDrag() 方法后 怎么获取拖曳后的坐标!!做凹透镜原理动画!