用于JavaScript游戏的服务器端高分记录

7

我正在使用Javascript实现一个简单的游戏,并希望有一个在线高分榜,以便玩家可以相互竞争。我有两个问题:

  1. 为此目的我需要什么最简单的服务器端程序?我不需要一个完整的“Web应用程序”,只需要一个简单的程序来接收POST请求,更新数据库并返回得分列表。我熟悉Django。您有什么建议吗?
  2. 如何使高分榜相对安全?我知道要使其对于能力强、专注的黑客防御困难,但我不希望任何有访问JavaScript源代码权限的人都能够轻松地提交虚假得分。有什么工具可以做到这一点吗?

2
一个简单的PHP脚本就可以了,我想。如果你想要能够轻松从JavaScript更新它,不太确定如何使高分榜更加安全... - Skilldrick
顺便说一句,你的SICP笔记写得很好 - 当我开始阅读这本书时,它们非常有用... - Skilldrick
@Skilldrick:干杯!我猜这是任何基于JS的高分游戏都会遇到的问题吧?它应该以某种方式传输到服务器。 - Eli Bendersky
7个回答

5
这将是确保高分数安全的一项艰巨任务。仅仅确保分数来自您的页面是不够的,因为如果JavaScript函数是 submitHighScore(n) ,那么他们可以在该页面的地址栏中键入javascript:submitHighScore(10000000),并使其起作用。
可能会想到一些哈希函数,生成与游戏中某些级别相匹配的特定代码。提交分数时,还将提交此哈希值,因此用户必须达到该级别才能获得相应的分数。
另一个选择是让游戏获取一种仅在短时间内有效的密钥,因此随着游戏进展,密钥将更改,然后将分数间歇性地提交到中央服务器。
请记住,真正有决心的人总是可以跟踪发送到您数据的数据并进行反编译。
您可以采取Broderbund的方法,向玩家提问验证问题,以确保他们确实通过了所说的级别...例如“上一级别的怪物是什么颜色?”

1
颜色并不是那么重要 - 记住你的用户群中可能有相当一部分是色盲者。 - Sean Vieira

3
为了安全地提交分数,需要对其进行签名(在签名和发送之前还需要确保分数没有被伪造,但这是另一个问题)。
将秘密隐藏在JS代码中,并向服务器发送“highscore”+“hash(highscore + secret)”。哈希可以使用MD5/SHA1 - 在JS实现中很容易找到。
当然,如果有人仔细分析JS代码,它就不会起作用,但至少某人无法通过篡改HTTP流量来提交虚假高分。
关于在JS中隐藏东西:
您不能真正地隐藏它(它最终像DRM一样徒劳无功),但是您可以尽力混淆它并使调试痛苦。
1. 不要将秘密放置在源代码中的文字中 - 在运行时结合几个函数、局部和全局变量计算出来。 2. 缩小所有代码,删除源映射。 3. 添加一些不做任何事情但似乎很重要的代码,以使调试更加混乱。 4. 不要将任何内容放在全局范围内,而是依靠共享的可变状态通过传递闭包和数组来实现。 5. 依赖于日期和定时器引起竞争条件,如果在调试器中暂停,则使您的代码产生错误结果(只需不要让它太紧,以便在较慢的计算机上运行)。
如果游戏是确定性的(如益智游戏),则用户可以提交以获胜所需的步骤(用户的输入)形式的高分日志,您可以在服务器上重放该日志以计算分数。
这将把攻击从查找/模拟提交分数函数转变为编写AI或黑客游戏本身以使其更容易玩(但仍在其基本规则内)。

你如何在JS中“隐藏”一个“秘密”?它对每个用户都可见吗? - Steven M

1

1.) 任何能够与数据库通信并理解JSON或其他格式的CGI脚本都可以完成工作。

然而,如果您熟悉Django,则在Django之上构建服务器将是最简单的选择,因为您需要学习的内容以及需要编写的应用程序代码量相对较少。如果您从头开始编写看似简单的CGI脚本,它可能会变得相当复杂。

我发现django-piston是一个方便的Django应用程序,可以快速编写REST风格的API服务器。它支持JSON,因此应该很容易与您的JavaScript游戏进行接口。

2.) 最普通的黑客将采取重放攻击及其变体:窥视页面源代码并执行JavaScript函数,拦截HTTP请求并重新发送它(使用Firefox附加组件Tamper Data应该很容易)。

为了抵消前者,您可以混淆源代码和HTTP正文;

  • 缩小JavaScript代码
  • 使用Base64或其他编码算法对发送到服务器的消息进行编码

可以通过要求所有更新请求包含最近从服务器获取的一次性密码(维基百科文章中的“会话令牌”)来防止后者。


3
Base64并不能防止任何人窃取数据。它不是加密方式。Base64编码的数据很容易被辨认出来并且很容易解码。 - Kornel

1
我正在考虑这个问题。对我来说,最合理的解决方案似乎是:
1)使用会话来防止在游戏外篡改分数表。
2)记录游戏中的每个操作并将其发送到分数服务器。然后,服务器将计算这些操作是否实际给出了该分数。如果您还记录了玩游戏所花费的时间,您可以进一步减少攻击者打破您的游戏的机会。这也将使您能够制作像街机服务器上具有高分表的重播脚本,并且在可疑的分数情况下,您可以观看回放并自行决定分数是否真实。作弊者必须使用聪明的机器人来玩您的游戏-除非您有一个为真正奖品而设的游戏,否则没有人会尝试那么努力。
如果作弊者甚至不分析您的代码,会话将阻止他。如果他阅读了您的代码,他很快就会打破任何类似于散列分数,秘密,令牌等的东西。但是,如果您使游戏日志脚本足够彻底,他会放弃。

0
回答你的问题:
1.) 这取决于你的环境和编码偏好。PHP、Python、ASP.NET 是几个我想到的。既然你已经知道 Python(从你的个人资料中可以看出),你可以使用 Python CGI 脚本来完成这个任务,或者使用 Python 的许多框架之一(Zope、Django、Pylons 等)。
请参见:http://www.python.org/doc/essays/ppt/sd99east/index.htm 了解有关 Python CGI 的信息。
2.) 一些安全技巧:(没有绝对安全的)
  • 在 HTML 中隐藏文本框,并使用编码值,服务器检查匹配 cookie,以确保高分数来自您的页面。
  • 服务器脚本仅接受特定域的值

重放攻击看起来会来自特定域名(即使提交已被篡改)。 - Kornel

0

您可以使用上述方法之一的组合,也可以要求用户注册才能发布高分。未注册用户可以查看其当前得分与现有高分的比较,但为了在线发布您的高分,您必须已经使用注册帐户登录或在应用程序更新分数时提供它。

类似于“您的最高分是X,在高分表中排名###。要在线发布此分数,请先注册。”的简单消息。


但这并不能阻止用户伪造包含虚假高分的请求。该账户可以轻松地被利用来实现这一点。 - Luqus

0
我认为更好的方法是直接在Django应用程序的Python文件中进行分数计算,而不是在JavaScript文件中计算。您可以通过POST请求将数据发送到与您的数据基础进行比较,然后计算分数并将其存储在数据基础中。这样,您就不会将分数在网络上传输到服务器,这是完全安全的,因为您只是在本地处理数据。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接