【问题标题】:Game's score is based on a client-side countdown. How to bulletproof it?游戏的分数基于客户端倒计时。怎么防弹呢?
【发布时间】:2011-05-02 22:26:57
【问题描述】:

我正在开发一款基于 JavaScript 倒计时得分的游戏:在倒计时归零之前完成关卡的速度越快,得分就越高。

当我最终从服务器端的客户端收到它时,我如何确保它不会以某种方式改变?

我最初的想法是做两个检查点:一个在关卡的开头,另一个在结尾。 Checkpoint 基本上是通过 AJAX 发送到服务器端 PHP 脚本的会话,然后加上时间戳。因此,在客户端完成游戏后,分数将与服务器端的分数进行验证。这种保护有用吗?

提前谢谢你!

编辑: 我也愿意接受任何其他方式来实现所需的功能。

【问题讨论】:

    标签: php javascript synchronization


    【解决方案1】:

    简单地说,您将值存储在数据库的日期时间字段中。然后,您使用该值播种您的 javascript。因此,客户端的任何更改都不会影响存储的时间。

    但是,如果您依赖客户端来获取值,则您无法做任何事情来确保它是正确的。用户仍然可以毫无问题地欺骗 ajax 请求。这有点困难,但肯定是可行的。

    一旦你的倒计时以某种方式与客户端相关,就没有转义了:)

    【讨论】:

      【解决方案2】:

      正如其他人指出的那样,您无法确定时代没有被篡改,但是有一些方法可以减轻后果:

      如果您有一个(服务器端)系统怀疑分数已被篡改,您可以将该 IP 地址或 cookie 列入黑名单,而不向其他用户显示这些分数。 向黑客显示分数。这有几个影响:首先,如果他们认为他们打败了你,他们可能会继续前进,不理会你的代码。其次,如果你的作弊检测错误地认为忍者玩家正在黑客攻击,玩家仍然会正常看到他们在表格中的分数(即使其他玩家没有)。因此,误报并不重要,您可以使用更模糊的算法,例如这位球员的进步率与平均水平相比如何?他是不是得到了一堆糟糕的分数,然后突然变得不可思议?我的服务器是否发现了来自该用户的不寻常的点击模式?等等。

      您可能可以进行设置,以便逐步改进您的检测算法,并在您怀疑玩家后将其列入黑名单(以及将误报取消列入黑名单)。

      【讨论】:

      • 谢谢,非常原始的黑名单想法!
      【解决方案3】:

      您可能会面临两种可能的情况。让我从简单的开始:

      a) 如果 Web 应用程序设计为在页面加载后立即开始游戏,那么您的生活将会变得简单。发送游戏的脚本应该在数据库中加上游戏发送的时间。这将是开始时间。当客户端发送“级别已完成”消息时,将记录结束时间。由于在这两种情况下都在服务器端记录时间,因此您不需要客户端保持时间。但是,有一个问题。请参阅下面的捕获部分。

      b) 如果客户端加载了应用程序,但当用户点击“播放”等时游戏开始的时间要晚得多,那么您的生活将会变得更加困难。在这种情况下,您需要来自客户端的“关卡开始”和“关卡完成”消息。同样,将时间留在服务器而不是客户端会是一个更好的主意。但是,您需要确保客户端在开始游戏之前收到对“级别开始”消息的 ACK,以确保用户不会玩服务器未记录的游戏。 (“级别开始”消息可能永远不会到达服务器)。

      The Catch:您需要意识到对于在分数上作弊的用户没有任何保护可能! JS 是完全开放的,无论您如何实现对服务器的开始/结束调用,任何用户都可以编写脚本以在她希望使用的任何时间间隔向服务器发送类似的调用。即使您使用会话/cookie,这些也可以轻松复制。 (例如使用嗅探器)。因此,您必须意识到并接受 HTML/JS 架构和代码在这些限制内施加的设计限制。因此,最好的办法是为用户编写代码,而不是防止黑客发送恶意呼叫。让想要玩您游戏的人享受您的游戏乐趣,而不必担心黑客会在他们的分数上作弊 - 无论如何,他们不会成为您的目标受众。

      【讨论】:

      • 正如大家所说,从客户那里读取任何值都是不可信的。如果您真的想要使用来自客户端的时间,还可以跟踪 Crimson 提到的服务器上的时间,然后比较两个数量,允许差异差异并忽略控制限制之外的时间。
      【解决方案4】:

      首先,忘记从客户端获取经过的时间。任何恶意用户都可以更改发送的数据。

      服务器端必须是存储时间的唯一权限。在关卡开始时,将当前时间存储在 $_SESSION 中。在关卡结束时,从当前时间中减去它,即为关卡经过的时间。

      $_SESSION['start_time'] = time();
      
      $elapsed_time = time() - $_SESSION['start_time'];
      

      为了方便用户,您仍然可以通过 Javascript 显示经过的时间。对于客户端和服务器之间的时间差异(这是完全可能的),您可以通过在客户端访问服务器时获取 elapsed_time 来进行同步。

      如果关卡完成跨越多个会话(例如您开始关卡、离开站点并稍后再回来完成),您必须将其存储在持久数据存储(数据库)中。

      【讨论】:

        【解决方案5】:

        您可以在会话中使用时间戳来存储开始日期,然后在播放器完成时发送 make JavaScript 执行请求(但第二个时间戳也应该来自 PHP 或其他服务器端语言)。 唯一真正防弹的方法是不向用户显示任何内容,并要求他告诉你每一个动作,与服务器检查并发送回它允许他知道的内容。但这意味着延迟。

        【讨论】:

          【解决方案6】:

          您可以发出一个唯一的令牌,该令牌存储在用户的会话中,可供您的 Javascript 代码使用。启动 AJAX 请求时,将此令牌作为附加参数传递,以便服务器区分合法请求和虚假请求。

          这个令牌当然应该只对单个请求有效。 结合上述解决方案(基于服务器的时间检查等),您应该能够构建一个可靠的评分系统。

          【讨论】:

          • 我不知道这会有所帮助;客户端已经拥有令牌——他们修改请求中的有效负载,然后使用他们的有效令牌发送伪造的数据。令牌只能真正帮助防止第三方修改数据。
          【解决方案7】:

          嗯,想到这个问题给了我两个想法:

          1. 攻击你自己的服务器。 我的意思是,每 1 秒发送一次请求,这将保存分数。 这样,“黑客”就无法发送开始/结束时间并作弊。

          2. 在特定时间差异发出请求。 好的,假设我们开始播放,您可以在特定时间间隔(3.4 秒?)发送请求 如果请求不在那个时间范围内,那么用户是在作弊吗? 或至少被标记为可能的作弊者。

          3. 使用简单的字符串。 XD 对于发送到服务器的开始/结束时间,offcourse 加密。 您可以尝试jCryption 进行加密。

          正如其他人所说,它不是完全失败的证明(因为我们正在谈论客户端脚本),但至少它会使作弊变得更加困难。 不知道,这只是我的两分钱。

          【讨论】:

          • 不错的主意,但它可能会在扩展方面出现问题——如果您有 10k 个客户端都需要每秒执行一次服务器查询,那么事情可能会很快变糟。
          • 这就是为什么我称之为“攻击你自己的服务器”。 :)
          【解决方案8】:

          不可能让它 100% 防弹,只有基于客户端才能让它更难破解

          【讨论】:

            【解决方案9】:

            您可以在呈现页面时生成 GUID。您可以连接此 GUID、开始日期时间刻度、会话 ID,并计算它们的哈希值以在用户返回时验证数据。

            【讨论】:

            • 如何散列开始时间以防止客户端回复虚假的结束时间?
            • 在执行每个检查点请求时,您可以验证开始时间并测试您的哈希值。否则用户可能会发送虚假的开始时间。
            • 由于潜在的作弊者有你的哈希函数的 JS 代码,他可以复制并在他的时间戳欺骗代码中使用它。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-06-02
            • 2017-07-10
            • 1970-01-01
            • 2015-12-16
            • 1970-01-01
            • 2013-01-31
            相关资源
            最近更新 更多