【问题标题】:Potholes in an automated multiplayer game where players can use their own algorithms自动多人游戏中的坑洼,玩家可以使用自己的算法
【发布时间】:2014-10-23 04:47:53
【问题描述】:

关于标签

我已将此标记为 Java C++ 问题。这意味着我不是在寻找特定语言的答案。我只标记了 C++ 和 Java,因为我精通它们,如果它们是用这些(或类似)语言编写的,很可能会理解您的代码示例。

我在寻找什么?

指针洞察关于我在开发软件时应该考虑的安全措施,主要是游戏,例如下面描述的。我所说的安全性是指检查并仔细检查用户没有以不希望的方式进行操作。这可能意味着诸如将他/她的现有最恶意病毒的更新集合发送到服务器/其他客户端等行为,或以其他方式损害其他玩家的用户体验,例如黑客攻击。


预期的问题和答案

您是在问如何阻止人们破解您的游戏?

无论如何,这不是我的问题,因为它方式对于这个线程来说太宽泛了。但是,如果您确实遇到了赢得每场比赛的简单方法(通过作弊),那么请告诉我。

这个问题更适合X

我已经在 CodeReview 和 Programmers 中问过这个问题;在这两个网络中,这个帖子都受到了不好的欢迎。公平地说,它在这里也很受欢迎(参考 ADTC 的评论),因此是赏金。放置赏金后,我重写了这篇文章以更好地满足 SO 的标准。但是,如果您仍然认为这篇文章不适合这里,请告诉我原因。我很难确定这是否真的更适合 SO 或程序员,所以不要认为这只是我在没有考虑一秒钟后发布在这里的转储。

要在两台机器之间建立连接,你应该使用套接字。谷歌一下。

我不是在寻求这种技术帮助。我知道如何实现该软件,这不是我第一次这样做。请看我问的实际问题。


我为什么要问这个?

有问题的软件

我正在开发一款类似蛇的多人游戏,玩家可以在其中使用自己的算法来确定蛇的下一步动作。玩家通过客户端-服务器连接相互连接,也就是说,一个玩家将充当主机。您可以假设服务器代码将等到所有玩家轮到他们,直到更新所有客户端之间的游戏状态。

关于游戏

我的游戏在文件夹中搜索任何兼容的 .jar 文件,其主类扩展了特定的抽象类。然后,玩家可以通过网络直接连接到其他玩家或通过从大厅搜索游戏来连接到其他玩家。

在玩游戏时,每个玩家都会使用自己的算法来确定蛇的下一步动作。每个游戏的持续时间可能会有很大差异,具体取决于为游戏指定的更新率,但大多数情况下它们很快并且很可能会在 30 秒内结束。

我还没有实现实际的网络多人游戏。


一个逻辑的模板源文件如下:

package template

import snake.*;

public class TemplateLogic extends SnakeLogic {

    @Override
    public void onLaunch() {
    }

    @Override
    public String getMove() {
        return "UP";
    }

}

所以我打算做的是,从托管玩家的角度来看,以字符串格式(“上”、“下”、“左”、“右”)通过网络获取玩家的下一步动作),因此在这方面不会有任何安全问题。每个客户用来确定下一步行动的实际程序只会在各自客户的计算机上运行。

我希望你一直在关注我。无论如何,我现在关心的是我可能忽略的任何其他坑洼。确定所有这些坑洼可能有点太繁琐了,所以我不会主要问这个。让我对此事有所了解是我所期待的。理想情况下,我可以从不同人的多个答案中获得更大的了解。

悬而未决的问题是,我能否阻止任何客户在他们的程序中使用会损害其他玩家的用户体验的方法?这样的方法可以是例如Thread.sleep():如果玩家让他的算法在每次移动之间等待 10 分钟,那将是非常烦人的。对于这个特殊的问题,我想我会为每个动作设置一个时间限制,之后落后/恶意的玩家将被踢出或分配一个默认动作,以便游戏可以正常继续。


旁注:

@Darinth 的回答让我想起了游戏的一个很重要的方面:允许用户输入,意思是蛇的下一步动作可以由人类玩家决定——也就是游戏可以用键盘正常弹奏。此外,没有什么会限制您在纯 AI 和纯键盘解决方案之间进行选择:您可以将它们混合在一起,例如,自己控制蛇,并在 AI 注意到您将自己逼入陷阱时接管。


总结一下

我是否忽略了一些重要的事情?我已计划将此作为一个小项目,供我和我的朋友消磨时间,但我有点狂热。

无论你的想法多么渺小,请毫不犹豫地回答。如果您想到更多兴趣点,您可以稍后编辑答案以使其更全面。我会定期检查任何答案以进行修改。

感谢您的宝贵时间。


我从答案中或自己获得的相关想法

  • 每次移动后将游戏状态的哈希值与所有客户端进行比较。 除了具有相同哈希值的玩家之外,所有玩家都将被踢出,最低要求主机将留在游戏(如果有 4 名玩家,其中 2 名玩家有一个哈希,另外 2 名玩家有另一个哈希,不包括主机的组将被踢,等等)。我想出了这个,但这要感谢@ToYono,所以归功于他。

  • 游戏开始前,比较每个玩家的校验和。 所有与主机校验和不同的玩家都将被踢出(甚至不让进入游戏)。归功于@ToYono。

  • 随机化任何排名匹配。 防止有效使用来自同一台机器的多个连接来玩同一游戏。如果一个玩家在一场游戏中玩多条蛇,他可能有一个算法试图合法地玩游戏,而两个算法只是破坏另一个玩家。归功于@Surt。

  • 允许用户输入。这从一开始就被设计为游戏的一部分,但我忘了提及。感谢@Darinth 提出了这种可能性,从而让我想起了这一重要方面。

【问题讨论】:

  • 最好将您的工作代码提交给code review并在那里询问。
  • 您的 API / 模板接口必须是防弹的。告诉我们更多关于它的信息。如果任何用户想要作弊,他将不得不在其中找到一个漏洞。
  • 如果作弊者是宿主,就说明他运行的是服务器代码?所以我猜作弊者可能会影响整个游戏
  • 某种校验和是的,用于检查游戏的完整性。除非玩家也破解了这个:)
  • 我认为这是一个很好的方法。一个被黑的游戏会取消所有玩家。

标签: java c++ security networking multiplayer


【解决方案1】:

如果一个玩家可以作弊,那么一些玩家就会作弊。那么最容易作弊的方法有哪些呢?

1) 改变游戏状态,有效撤销之前的动作。

  • 所有其他玩家和/或服务器都应该验证更新,因为它是谨慎的值,你处理它应该不是问题。客户端检查可能就足够了,但敏锐的黑客可以通过将检查更改为类似的东西来破解检查

    bool allowedMove() { 返回真; ...此处剩余的原始校验码 }

然后必须通过代码的校验和 SHA3 来应对?因为 MD5 即将结束其安全时代。

示例:WoW Teleport hack,x,y,z 在客户端计算并发送到主机。

  • 作弊者入侵客户端以获得所需的结果。
  • Bliz 在客户端上生成校验和。
  • 骗子刚刚插入了一个带有 x,y,z 的新网络包,以便传送到他们希望的位置。
  • Bliz 检查执行此操作的外部程序。
  • 作弊者随机化他们的外部程序。
  • Bliz 通过服务器端距离检查进行了反击。
  • 作弊者反击将传送限制在允许的距离内,导致人们在空中行走而没有飞行。
  • Bliz 通过进一步的服务器端健全性检查反击,显然解决了大部分问题。

2) 反应速度不人道,有效消除人为延迟。 在你的游戏中不是问题,除非更快提供更多动作,但这是程序之间的问题,所以......它们可能总是比人类更快。

  • 如果反应时间通常比人类快,那么骗子就在另一端。回复和 ping 时间的差异不够大。

3) 自动瞄准确保不人道的高命中率。

  • 该玩家的命中率远高于已确认的第二好的人类玩家。

示例:射击游戏 XXX

  • 外部程序通过 Windows API 捕获玩家坐标并为游戏提供更正的定位。

4) 使用其他外部帮助程序

  • AI 比其他玩家好很多

示例:在线国际象棋游戏,作弊者使用国际象棋程序帮助下棋。

  • 您的玩家可以创建一个程序来保存游戏状态,并让外部程序处理数据并进行下一步,然后由作弊程序加载并作为下一步发送。
  • 检查程序中的任何负载,玩家可能希望通过保存来分析其程序的有效性。
  • 使用优化的多芯片多线程矢量化算法,作弊者可以探索大部分或所有游戏状态。
  • 几乎不可能检查外部程序的帮助,您可以检查外部 Windows 事件生成,但会有很多误报。您可以尝试阻止任何加载/保存作弊,但作弊者可以在 IP 级别进行攻击。
  • 最大的保护是努力实现它可能会超过任何好处。

5) 多方格斗,部分玩家可能有多台电脑合作取胜

  • 使用多台计算机或程序实例可以增加作弊者主实例获胜的机会,因为其他人破坏了其他玩家。

示例:可能发生在射击游戏中?

  • 作弊者发送诱饵或压制单位引火或阻碍敌人移动,而真正的玩家射击对方玩家或以其他方式得分。
  • 很难检查,因为 2 个人可以在同一个位置合法地玩。
  • 如果多个玩家的计算机 MAC 地址相同,则可能表示作弊,因为他们将在同一台 PC 上进行游戏。但即使这样也不是作弊者,因为他们可以在封闭的虚拟机上玩游戏。

6) 预先计算所有游戏状态,以便作弊者使用最优策略。

  • 不这样做的玩家将选择次优的开始动作。

示例:井字游戏

  • 可以计算所有游戏状态。 (您可以在头脑中为井字游戏执行此操作)。
  • 对玩家进行评分应该会有所帮助,但作弊者仍然可以轻松获胜。
  • 预编译开局序列通常用于国际象棋程序。
  • 解决这个问题的唯一方法是非常随机的地图和具有如此大状态的起始位置,以至于无法预先计算。

7) 创建新的身份以超越收视率。

  • 作弊者被胜利所欺骗,他们会在低评级时为自己创造新的“玩家”以再次“获胜”。
  • 即使玩家没有作弊也会发生这种情况,他们会创建新的身份,这样他们就可以击败容易的受害者。

8) 赢得交易

  • 2个作弊者互相交易胜利

示例:WoW 战场

  • 使用外部程序来增加获得正确对手的机会。
  • 如果未与 正确的对手配对,则断开连接以避免其注册。即使没有作弊也经常发生断开连接(如果您想减少这种情况,请不要玩无线或手机)。

  • 检测 2 个 Mac 地址是否以不同的身份多次播放,并且每台 Mac 上只有一个获胜。

9) 输了就断开连接。

X) 未知的未知(相对于已知的已知、未知的已知、已知的未知)

  • 总有人发明了一些我们没有想到的新作弊方法。

示例:逃税

  • 总是存在漏洞、收入报告缺失或虚假、欺诈性新扣除等。

  • 幸运的是,总有一种方法可以查明某人是否在作弊,您可以检查他们提交给程序的算法并查看其作弊。请注意,您将获得的程序可能是假的,但测试它是否能赢得这么多可能是微不足道的。

  • 更聪明的作弊者会稍微低调一点。

【讨论】:

  • 感谢您的回答。你认为其中一些观点适用于我的情况吗?与每条蛇由人类控制的普通蛇不同,在我的例子中,重点是蛇是由人工智能控制的。所有的选择都是非人的准确和闪电般的速度,并且总是最大化获胜的可能性(当然,假设是一个好的人工智能)。您对一般情况进行了很好的概述 - some 软件可以做什么。不过,我认为第 2、3 和 4 点对我的游戏来说不是问题。通过随机化排名匹配,可以减少第 5 点的担忧。
  • Issue 1. 我认为,@ToYonos 的答案已经涵盖了,但你在答案中提到了一个类似的案例(有一个例子!),这很好。一些普遍的问题也是持续存在的问题,没有好的回归。例如第4点:我受此启发,去看看chess.com是否有任何应对措施。它没。我轻松赢得了 2 场与 ELO 不错的玩家的比赛。鉴于 chess.com 是一个相当大的在线国际象棋网站,我不得不得出结论,他们没有什么可回答的 - 根本不可能确定控件背后是否有人。
  • 再次感谢您的洞察力。如果您可以对我的软件提出更多问题,请编辑您的答案,我一定会投赞成票。
  • 第 4 点是一种可能性,因为优化的多芯片多线程矢量化算法可以计算 所有 游戏状态,而 java 程序可能无法计算。
  • 你能想出办法来防止#4和/或#6吗?
【解决方案2】:

此回复总结了上面在评论部分进行的聊天。

  • 作为一名玩家必须主持游戏,如果作弊者是主持人怎么办?

如果作弊者是主机,这意味着他运行服务器代码。这意味着他可以在操作核心引擎时影响整个游戏。

一个好的解决方案是让每个玩家计算一个校验和,并将其与参与一场游戏的所有其他玩家的校验和进行比较。如果一个校验和不匹配,则游戏被取消。这个校验和可以是一个唯一的基于字符串的一个程序版本。

  • 主机也能破解这个系统吗?

由于每个玩家都会进行自己的比较,因此所有玩家都必须以相同的方式破解游戏,这是极不可能的。正如@Olavi Mustanoja 指出的那样,校验和系统将与更新客户端有很好的协同作用。

编辑:

OP 最初的想法是在所有玩家之间比较每个回合的游戏状态。

游戏的状态存储在一个 int 数组中,其中 0 表示可用空间,-1 表示一条蛇,-2 表示蛇头,8 表示苹果(或 cookie)。在每一轮之后,游戏将比较所有状态数组,如果在某些时候某些状态与其他状态不同,则终止游戏。这可以通过发送数组的哈希码轻松完成。

这个想法与我的校验和想法并不矛盾,它可能是双重安全性。

【讨论】:

  • 我将删除上述 cmets 中的对话,您也应该这样做以保持井井有条 :) 另外,我最初的想法是运行模拟游戏。游戏状态存储在一个 int 数组中,其中 0 表示可用空间,-1 表示一条蛇,-2 表示蛇头,8 表示苹果(或 cookie)。在每一轮之后,游戏将比较所有状态数组,如果在某些时候某些状态与其他状态不同,则终止游戏。这可以通过发送数组的哈希码轻松完成。
  • 好的,知道了。我的想法更多的是上游验证。你的想法也很好,两者都可以实现。我会更新我的答案。
  • 我并不是要排除校验和的想法。通过稍后的测试,我将决定一个或另一个,或者两者一起工作是否更好:)
【解决方案3】:

这在很大程度上取决于您打算限制什么。算法可以询问用户输入吗?算法可以访问的信息是否应该有限制?使用 java/c++ 代码使算法几乎可以做任何事情。您可以设置一个窗口来选择蛇要遵循的路径,让它们以人类智能和机器精度进行操作。您可以选择在不同的算法之间进行交换,这些算法可能会激活“逃生”模式以摆脱困境,或者可以选择攻击模式来专门尝试诱捕您注意到处于不利位置的玩家。如果您想避免这种情况,我的建议是提供一种脚本语言(如 Lua 或 Javascript)。这些可以很容易地定制以限制他们的能力并防止用户访问您不希望他们访问的任何内容。做得好,您实际上可以安全地将这些脚本发送到所有客户端/服务器,它们都可以安全地运行模拟并比较步骤/结果。

如果您对这些事情没意见,那么我唯一可能担心的其他问题就是主机使用已经提到的被黑客户端。

【讨论】:

  • 人类可以完全或部分操作蛇。实际上,我让用户很容易做到; API 将用户按下的最后一个键保存在内存中,并将蛇移动到适当的方向。这是设计的一部分。我打算在制作游戏时,游戏的速度是预先确定的,但可以由主机调节。通过这种方式,主机可以告诉其他玩家游戏应该由人类(慢速)还是算法(高速)来玩。如果每 5 毫秒执行一次新动作,人类将处于显着劣势。
  • 一般情况下,任何决定蛇下一步动作的方法都是允许的。玩家如何确定他/她的蛇的下一步行动并不重要,最佳算法获胜。在这件事上,所有玩家都站在平等的立场上,因为关键是如果你对算法有一个好主意,你很可能会赢。如果您有一个不为人知的/开箱即用的想法,那么您将胜过好的算法。如果你有一个涵盖一切的优秀算法,你就会赢。
  • 然而,注意到用户输入是可能的,即使我没有提到这一点,你也会获得 +1。这是我忘记提及的游戏的一个重要方面。
  • 编辑到第一条评论:API将用户最后按下的键保存在内存中,用户可以根据它选择移动到一个方向。
  • 理论上,您应该能够使用该类的方法来创建一个完整的窗口来承载用于控制 AI 代理的 UI。那时,您可以设置 AI 模式、攻击性级别等……此外,您在编辑时拼写错误。 :)
【解决方案4】:

主要问题是服务器。它具有游戏状态,需要被信任。您可以修改您的客户,因为客户可以做任何事情来确定下一步。如果服务器在远程机器上执行,您无论如何都不能真正信任服务器。由于机器本身不受信任,它可能会操纵所有校验和和数字签名。

我可以想到 3 件事可以让您的服务器受到信任:

  • 在您控制的机器上执行服务器 -> 游戏客户端连接到服务器。恕我直言,问题的最佳解决方案
  • 在 UserA 上托管服务器。 UserB 和 UserC 正在使用此服务器进行游戏。 UserA 和 UserD 可以在@UserB 托管的服务器上播放。没有人对破解/修改客户端/服务器代码感兴趣。 => 难以实现,但您不需要任何服务器基础架构(只有游戏大厅...)
  • 所有客户端都有本地服务器。只有当两个战斗人员就游戏结果达成一致时,它才会被计算 => 您可以检测到有人在做坏事,但不能检测到具体是谁。你可以在服务器上创建一个计数器,如果一个用户经常操纵匹配,你可以排除他们和他们的结果

【讨论】:

  • 感谢您的回答。我曾考虑在我的机器上制作一个服务器,但我认为这将是最无聊的解决方案:) 我必须保持服务器运行。从我收到的其他答案来看,我认为我最终陷入了第 2 点和第 3 点的混合,所有玩家都会看到游戏状态是否与所有其他玩家的游戏状态相同。如果不是,则整个游戏将被取消,因为游戏“不同步”,并且完全有可能 a) 有人作弊,或 b) 有人拥有不同版本的游戏。我认为这对每个人都是公平的。
  • 这里要小心误报,有些人在wifi或手机上玩会有很多DC。
  • @Surt 断开连接应该不是问题,这里的服务需要跟踪状态(使用 tcp 很清楚客户端知道什么)。如果断开连接,则可以保留状态并在重新连接时继续。如果状态不同步,则很有可能检测到操纵
  • 这让我想起了一个9) Disconnect when your losing.
  • @Surt jep 这是个问题 -> 游戏将永远处于等待位置。但是你可以让游戏暂停 -> 如果其中一个玩家没有连接,比如说有一天他/她输掉了游戏
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-14
  • 2012-02-20
相关资源
最近更新 更多