跳转到主要内容

安全

你的客户端软件一定会被人破解。对某些虚拟世界来说(比如那些完全没有游戏成分的),这未必有什么关系。对其余的虚拟世界,关系可就大了。

至少,这意味着客户端发给服务器的每一个数据包,都必须检查一遍,看它是否讲得通。硬件层与传输层的纠错机制本应保证,到达服务器的内容就是客户端发出去的内容——那又何必浪费时间,去检查根本不会出现的胡话?可事实是:正在跟服务器说话的,未必是一个货真价实的客户端。它可能只是在跟一段代码说话——那是某个玩家自己写的,用来冒充客户端,或者往客户端的数据包里插数据。要是服务器收到了讲不通的数据,却没有办法处理,那会怎么样?是不是已经有人学会了让服务器崩溃的本事?

这还只是说,那台服务器是你的。有时候,一群玩家会自己写一台服务器,然后说服客户端改去跟它说话。这样一来,他们就能设计和游玩自己的世界,而不玩你的世界——而且这一切分文不花 1!

虚拟世界的程序员没有义务让黑客的日子好过——他们可以使用加密、可以独占屏幕、可以把身份校验做得极不频繁,让数据包嗅探软件有可能漏掉它们——但他们的代码终究会被人逆向工程,人们终会弄清它到底是怎么回事。然后,他们就会把它改掉 2。

重要:凡是与虚拟世界里会发生什么有关的决定,都绝不能下放给客户端。任何决定都不行。就是任何决定都不行。

《空中勇士》(Air Warrior)最初的客户端会自己做必要的计算,判定一枪是打中了还是没打中。当时认为,玩家把准星精确对准目标、扣下扳机,却因为客户端显示目标在某个位置、而服务器认定它不在那儿,结果打了个空,这是不公平的。这种考虑非常值得称道——直到有人给客户端写了一个外挂:只要你一开火,它就发一个数据包,声称你打中了离你准星最近的那架飞机——不管它是不是真的在准星里。Kesmai 公司不得不推出一个补丁来修它。

程序员绝不该把关乎世界运转的代码放进客户端。一旦这么做了,就可能意味着重大、极大规模的欺诈。设计者只在一种情况下才需要为此操心:损害长时间没被发现,他们不得不拿出策略来修补它(比如,一群玩家给自己凭空发钱,再把这笔钱花出去,数额大到引发通货膨胀)。

设计者确实还得操心自动化游玩这类事。凡是要求反复、反复、反复地做类似动作的事,通常都容易自动化——很多情况下甚至用不着破解客户端,市面上现成的工具就能代劳。《网络创世纪》(Ultima Online)的制作系统枯燥到了这种地步:玩家发现有一种给打字员用的宏软件能让他们免于食指重复性劳损时,简直喜出望外。计算机下达命令的速度通常也比玩家快:有人为《MUD1》写了自己的客户端,把命令以极快的速度塞进线路,结果开玩 30 秒后,那个自动角色就站在那里,怀里抱满了凶悍的武器和其他有用装备,而其他人手里基本上还空空如也。

所以,设计者应当避免提出任何要求玩家把某个动作一遍又一遍、又一遍地做下去、中途不得喘息的设计(这也可能包括移动)。如果你确实想让某个动作花掉大量时间,那就让角色趁玩家离线时,把这件事当作后台任务来做。如果速度偶尔也很重要(比如出于戏剧性的原因),那就坚持让服务器程序员在处理任何单个玩家的命令之间加入延迟 3。如果需要某种程度的搜寻或探索(比如一道谜题),那就放上会移动的障碍或陷阱,好让程序没法轻易用蛮力法找出解法。

人们想自动化的,通常都是乏味的任务。如果你设计的某种东西,你料想许多玩家都会想把它自动化,那就不妨想一想:它本身会不会就没什么意思。举例来说,玩家如果自己动手画地图,对虚拟世界的理解会深刻得多,所以设计者也许想鼓励他们这么做。然而,画地图的实际操作枯燥得让人头脑发木,以至于(针对文字世界)出现了自动绘图程序:它们会试遍每个房间的每一条出口,直到生成一张完整的地图,然后就可以挂到网站上。如果你原本指望靠不在客户端里内置地图工具来激发探索的氛围,那这招没有奏效。

狡猾的玩家还可以用别的办法操纵客户端,让自己占上风。设想一个角色原地转 360° 的情形。客户端必须与服务器保持紧密而快速的联络,才能确保随着扫视的推进,手边随时都有显示世界所需的信息。否则,玩家看到的可能就是半屏空白,或者有角色从画面正中突然冒出来——而一瞬间之前它们还不在那儿。不过,正如前文所说,客户端通常不能指望与服务器之间有一条快到飞起的连接。

为了解决这个问题,《无尽的任务》(EverQuest)的服务器被配置成向客户端发送超出其严格所需的信息:玩家想转身时,附近物体的位置早已在手,显示起来就不会有延迟。为此,客户端会被告知附近一切物体与玩家的位置——不只是那个角色“看得见”的那些——外加一些别的顺手小信息,比如它们身上带着哪些东西、还有多少生命值。世界的地形数据也一直常驻在玩家的 PC 上。

这是一个高效的做法:任何人都可以毫无顾忌地旋转镜头或以别的方式改变视角,而不会碰上画面错位。然而,不少玩家很快就意识到:既然信息就在那儿,那么不管用不用得上,都可以把它显示出来。他们写了程序,把附近每个人、每样东西都以雷达读数的形式呈现出来。mobiles(活动体)再也没法从背后偷袭他们;他们也不用再猜哪一只身上带着战利品。其中一个这样的程序 ShowEQ 实在太好用,Verant 不得不禁止使用它(这又成了它众多公关灾难中的一起 4)。

被破解的甚至未必是客户端。《网络创世纪》用 PC 显卡来控制亮度,这意味着爱钻空子的玩家可以绕开客户端(把伽马校正调高),在本来应该一片漆黑的时候换来满眼白昼。打埋伏再合适不过了!

只要有可能,设计者就应当坚决要求:发给客户端的任何数据项,都不得携带超出玩家角色有权知道范围的信息。不过,客户端编程本来就是一门谈不上精确的科学,很可能总有些额外信息必须提前发过去,哪怕只是 CD-ROM 上的纹理贴图。设计者应当事先被告知这一点,以便相应调整自己的设计。如果你明知玩家反正会弄清附近所有物体都在哪儿,那就干脆正式地把这些信息交给他们,同时确保它派不上多大用场。如果你想让他们时刻提着心,那就让新的 mobiles 凭空瞬移出来。

好,那么,你的程序员向你保证:客户端里没有本该放在服务器里的东西,只有少数几处你可以绕着设计过去。这么一来,安全问题这就算解决了!

唉,你明知道并没有。你自己的设计本身就可能存在安全问题。

举例来说,假设你(已经认定固定价格不是好主意)让经济系统根据当地的供需来决定商品价格。再假设,它允许人们按单件的价格批量买卖。正常情况下,这不会出问题:如果有 300 把剑在售,那么你按 20 UOC 5 买一把,还是按每把 20 UOC 买 10 把,都没有区别。剑剩得越少,价格就涨得越高,这正是你想要的效果——买下 10 把之后,新价格可能是 22 UOC。你会把回购价定得远低于出售价,这样,谁要是想把刚花 200 UOC 买来的 10 把剑卖回去,拿到的可能只有 110 UOC,而不是 220 UOC。

到目前为止,一切正常。

可是,碰上高成本、低产量的商品,又会怎样?也许本地的钻石矿每周只挖出五颗钻石。五颗全在时,钻石市场的价格是 1,000 UOC;只剩一颗时,价格飙到 4,000 UOC;一颗都没有时,就是供给枯竭了。在这种情形下,一颗钻石能按多少钱卖回钻石市场?即便按买入价打五折,也至少是 2,000 UOC。于是,如果有人以每颗 1,000 UOC 一次买下全部五颗,再以每颗 2,000 UOC 一次全部卖回,他们每做一笔就赚 5,000 UOC。你的设计送了他们一台引擎,想造多少钱就造多少钱!呃啊!

虚拟世界允许某件事、而设计者巴不得它不被允许,这种情况就叫 exploit(可被利用的漏洞)。exploit——设计层面的 bug——能在一夜之间毁掉一个虚拟世界 6。

撇开 exploit 不谈,玩家还有很多办法把设计者的一番好意扭到别处去。身份盗窃——在现实生活里冒充别人——相当容易,但基本上不是设计者的责任 7。角色盗窃——在虚拟世界里冒充别人的角色——则不该容易,因为这是设计者的责任。尤其是,如果两个玩家可以用相同的名字给角色命名,那么之后其中一个成功冒充了另一个,设计者就有一部分责任。这个“名字问题”在第 3 章里有相当深入的讨论。

所以,你的设计一定会出 bug。玩家会找到它们,并从里面把能捞的好处统统捞走。就算他们立刻就上报了,他们也会觉得,凭这份诚实,你欠他们一份人情。那你该怎么办?

exploit 无法杜绝,但你可以采取措施,把它们的数量和影响压到最低。检测与恢复至关重要。只要可能,就把一切都记录下来。在《MUD2》里,玩家经常抱怨线路噪声 8 切断了他们与游戏的连接,害得他们的角色一命呜呼。实行一套“全部记录”的策略(玩家的输入/输出记录,加上服务器的所有决定),一下子就把问题解决了——十次里有九次,玩家会被揭穿:直到巨龙把他们烧成灰、野狼咬掉他们的脑袋、或者别的什么的那一刻,他们都还活动得好好的;因此,他们那些慷慨激昂的复活请求,等同于作弊。

对于占用大量带宽的虚拟世界来说——比如图形化的游戏世界——这种程度的记录并不总是做得到。有两种做法,但哪一种都不太令人满意:一是存下事件(据此可以还原出确切的情境),二是存下客户端通信(据此可以得到玩家实际看到的画面)。这两种做法都会产生海量、且难以检索的数据。在事态发展的过程中,客服管理员也许能窥探 9 玩家,这可以部分缓解问题;但如果他们赶到现场时已经太晚,那么除了日志,就只剩在场的中立证人这一个办法了(这种证人想必一抓一大把)。

检测出可能的 bug 与 exploit 很重要,但这本身还不够。当事情真的不幸出了岔子时,纠正后果的能力应当永远都在手边(哪怕这意味着从定时备份里把角色数据库整个重装一遍)。发现事情出错的能力不完整,只是不方便;恢复受损数据的能力不完整,则是失职 10。

设计虚拟世界的满足感,有一部分就在于看着自己的造物不断演化,看着里面发生一些你未曾预料、却又完全说得通的事。不过,随之而来的一个不太走运的后果是:发生的事里,总有一些你会巴不得它没发生,还不得不动手去修。你备下的应急预案越多越好,但你永远也不可能把一切都覆盖到。

不过,既然你要的就是不可预测,那它真来了,你也别抱怨。


  1. 例子包括《无尽的任务》的 EQemu(http://www.eqemu.net/)和 EthernalQuest(http://www.ethernalquest.com),以及《网络创世纪》的 Sphere(http://www.sphereserver.com/)、UOX(http://www.uox3dev.net/)和 Epsilon(http://www.epsilon.escend.net/)。更多例子见 The Smithys Anvil(http://www.smithysanvil.com/)。 ↩︎

  2. 开发者所说的 arms race(军备竞赛),指的就是这个。 ↩︎

  3. 其实更时髦的做法不是强制延迟,而是让服务器——甚至其他客户端——来做抽查,看有没有人在作弊。不用说,如果客户端有权举报谁在作弊,它们迟早会被破解,用来诬告无辜的玩家。 ↩︎

  4. Verant 修改了最终用户许可协议,赋予自己搜查你家 PC 的权利,去寻找在他们看来可能妨碍《无尽的任务》正常运行的软件。随之而来的全面反抗,帮他们重新考虑了这个做法。 ↩︎

  5. 货币单位(Units of Currency,UOC)。 ↩︎

  6. 当然,任何类型的模拟软件都会出现这种问题,只不过在虚拟世界里为害最烈。我在一款单机贸易游戏(Ascaron 的《贵族》,The Patrician)里发现过一个与钻石例子类似的 exploit,靠它,我在苦战五年之后终于通关。到了《贵族 2》(The Patrician II),他们把这个问题修掉了。 ↩︎

  7. 2000 年,我在《无尽的任务》里花了好几个月建立声望,尽管那段时间我一次都没有玩过这款游戏。有人假扮成我,而别人居然信了。 ↩︎

  8. 早年间,调制解调器没有硬件纠错功能。电话线噼啪作响,数据也跟着噼啪作响。 ↩︎

  9. 马修·隆巴德(Matthew Lombard)与特雷莎·迪顿(Theresa Ditton),《一切的核心:临场感的概念》(At the Heart of It All: The Concept of Presence)。洛杉矶,《Journal of Computer-Mediated Communication》,南加利福尼亚大学(University of Southern California),1997 年 9 月。http://www.ascusc.org/jcmc/vol3/issue2/lombard.html。关于虚拟世界的专门描述,见约翰·托厄尔(John Towell)与伊丽莎白·托厄尔(Elizabeth Towell),《基于文本的网络化虚拟环境即“MUDs”中的临场感》(Presence in Text-Based Networked Virtual Environments or “MUDs.”)。《Presence: Teleoperators and Virtual Environments》第 6 卷第 5 期。马萨诸塞州剑桥,MIT Press,1997 年 10 月。http://www.fragment.nl/mirror/various/Towell_et_al.1997.Presence_in_MUDs.htm。 ↩︎

  10. 而一旦玩家意识到你手里没有准确的事件快照,那才是真正开始出问题的时候。 ↩︎