從技術角度分析:如何實現抽卡是抽別人銀行卡這場「P0 級別的技術失誤」

你的信用卡已加入卡池

這封面圖是在B站看到,不知出自哪位大師之手。

前言

這個事件我猶豫了一下,想要不要在本站發佈,因為想必你們訪問也不是想看八卦,我也不是想激起什麼矛盾,但我最後發佈的原因是,我覺得有必要從現實的層面上看待一個產品從設計到落地,有什麼地方需要留意,我們該如何避免發生同類事故,如果真出事,會產生什麼後果。

事故背景

原來抽卡是指抽別人的銀行卡,這一點我是真沒想到。

2026年1月22日,由鷹角網絡開發的遊戲《明日方舟:終末地》(以下簡稱《終末地》)正式全面公測,這次中國大陸和海外同步上線的,而在首發當天國際服發生了重大事故。

瑞士奶酪理論示意圖
受影響用戶在 X 的貼文

在當天遊戲上線不久後,在 Reddit、Discord、X等社群平台紛紛出現詢問和投訴的文章,內容都是指自己的 PayPal 帳戶在未經自己授權的情況下無故扣款,並有人晒出自己的 PayPal 帳戶扣款紀錄,裡面涉及多個不同幣種,有美元、歐元、日元等。有受影響玩家涉及金額高達 1.5 萬歐元。

官方當日就事件發出的公告
官方當日就事件發出的公告

在事發後不久,運營商 GRYPHLINE(鷹角子公司)把 Paypal 支付功能關閉,當日晚上發佈了公告,指遊戲中的 Paypal 支付功能出現問題,現已把支付功能關閉,並且官方承諾會對所有異常消費發起全額退款處理,所有退款預計4小時內完成。

所以為什麼玩一個遊戲會被無故扣錢呢?

技術分析(以下由 Gemini 說明,這方面叔自愧不如)

這次事故在技術上被稱為「P0 級併發安全漏洞」,這是一個極為低級但致命的邏輯錯誤。它的核心就是「張冠李戴」,即把 A 的支付憑證,錯給了 B 的購買請求。這不是駭客攻擊,而是程式碼本身對「數據隔離」的嚴重失敗。

想像遊戲伺服器是一個非常忙碌的「收銀台」,為了處理數萬人的同時充值,伺服器需要多個「服務員(線程)」同時工作。正常的流程應該是「一個玩家一個本子」,但鷹角卻讓他們混用了數據。我分析了三種最可能導致這種「串號」的技術原因:

可能性一:程式碼內存汙染(公共的便條紙)

這是最常見的錯誤,稱為 「非線程安全」。開發者在程式碼中,錯誤地將玩家的 PayPal 密鑰(例如:self.token)定義成了所有線程共用的「公共變量」。當玩家 A 的請求正在處理時,玩家 B 的請求插隊進來,就會把這個公共變量覆蓋成 B 的密鑰。當 A 的流程繼續執行時,它讀取了桌上 B 的密鑰去扣款,造成直接盜刷。

可能性二:緩存的 Key 映射錯誤

為了加快讀取速度,遊戲伺服器會將玩家密鑰短暫存儲到一個高速緩存服務中。錯誤可能發生在:開發者在存儲這個密鑰時,使用了錯誤的「標籤」(Key)。例如,本該使用 paypal_token:User_A 來存儲,卻錯誤地使用了 paypal_token:Current_User 這個固定的 Key。後一個用戶的數據就直接覆蓋了前面用戶的數據,造成緩存數據的混亂,最終導致讀取錯誤的密鑰。

可能性三:資料庫事務隔離失敗

在極端情況下,錯誤也可能發生在數據庫層面。如果程式在讀取密鑰時,使用了過低的事務隔離級別,有可能在玩家 A 的交易還沒完全完成時,玩家 B 的請求就提前讀取到了 A 正在操作的不一致的「髒數據」。儘管這種情況不常見,但其本質依然是:系統錯誤地讓兩個獨立請求的數據發生了交叉污染。

無論是哪種技術細節,這次事故都指向同一個結論:支付系統沒有在底層架構上實現數據的絕對隔離。在金融系統中,任何一個數據點的共享或錯配,都會導致這種「零和博弈」的災難——一個人得到了免費的抽卡,另一個人失去了自己的銀行存款。

為什麼只有 PayPal 出事?

這次事故更精準地暴露了問題:錯誤只在負責處理 PayPal 交易的程式碼模組裡。

原因是 PayPal 的「綁定協議」需要伺服器長期暫存一個「扣款密鑰(Billing Agreement Token)」。

而像 Google Play 或 Apple Pay,因為它們不需伺服器長期持有密鑰,支付環節是單獨隔離的,所以沒有犯這個錯誤,成功避開了這場災難。

事故的連鎖反應

最可怕的是這個錯誤被「無限抽卡」利用後帶來的連鎖災難:

  1. 玩家 A 發現自己沒扣錢但拿到了道具,開始瘋狂點擊購買。
  2. 每點擊一次,伺服器就隨機抓取一名受害者 B/C/D 的銀行卡扣款。
  3. 這導致了受害者被在極短時間內連續盜刷,金額飆升到 1.5 萬歐元這種天文數字。
  4. 被盜刷的玩家戶口因為「高頻異常交易」被銀行風控凍結,誤判為「洗黑錢」,生活陷入困境。

這是一次業界罕見的 P0 級(最高級別)技術事故,它不僅是金錢的損失,更是對軟體工程基本原則的嚴重違背,應當作為所有後端開發者的反面教材。

系統修復與防範建議(以下依然由 Gemini 說明)

要徹底根除這類 P0 級漏洞,單純修復變量定義是不夠的。開發團隊必須從「代碼規範」到「測試流程」進行全方位的重構。針對上述的邏輯錯誤,我們提出了以下三種必須執行的技術改進方案,以確保用戶資產的絕對安全。

改進方案一:嚴格的變量作用域控制(使用 ThreadLocal)

最根本的解決方式是從代碼層面隔離數據。開發者應強制棄用任何形式的「全局變量」來存儲用戶狀態。在 Java 或 Python 等後端語言中,應使用 ThreadLocal 或將變量限制在 Request Scope(請求級別作用域)內。確保變量與當前處理的線程生命週期綁定,請求結束即銷毀,從物理上杜絕「A 用戶讀取 B 用戶變量」的可能性。

改進方案二:高併發的壓力測試(Race Condition 模擬)

常規的功能測試無法發現這類問題,必須引入「併發競爭測試」。測試團隊需要編寫腳本,模擬數千個線程在 同一毫秒 內發起支付請求(即模擬 Race Condition)。通過腳本驗證:當線程 A 發起 PayPal 請求時,線程 B 是否能干擾其返回結果。只有在極限併發下數據依然保持一致,系統才算合格。

改進方案三:引入分佈式鎖與冪等性檢查

為了防止緩存層面的錯誤,必須在支付接口引入「分佈式鎖(Distributed Lock)」。當玩家 A 的 ID 正在進行支付操作時,鎖定該 ID 相關的所有緩存寫入權限。同時,利用 UUID 為每一個支付請求生成唯一的「流水號」,數據庫在扣款前必須校驗該流水號是否匹配,防止同一筆訂單被錯誤地關聯到不同人的賬戶上。

技術修復只是第一步,建立對金融交易的敬畏之心才是關鍵。所有的支付代碼上線前,都必須經過雙人交叉審計(Code Review),並在與生產環境完全隔離的沙盒(Sandbox)中完成不少於 72 小時的穩定性測試。

最後的保險:自動熔斷機制

人為的錯誤無法完全避免,因此系統需要最後一道防線——「自動熔斷(Circuit Breaker)」。

監控系統應實時分析交易數據,一旦檢測到以下異常指標,應立即自動切斷支付服務:

  1. 單一時間窗口內,退款或報錯率超過 1% 的閾值。
  2. 同一 PayPal Token 在極短時間內出現跨賬戶調用。
  3. 用戶投訴關鍵詞(如「盜刷」、「沒買」)在客服後台激增。

這次事故的教訓是慘痛的:在涉及真金白銀的代碼裡,永遠不要假設環境是安全的,必須假設每一個變量都可能被污染,並據此建立防禦體系。

🍔 【白話文比喻】如何測試才不會「炸廚房」?

我們可以把測試過程想像成「餐廳出餐」的演練:

1. 錯誤的測試:慢條斯理的「試吃會」

原本的測試可能像這樣:

  • 測試員 A 扮演顧客,慢慢走進店裡點了一份套餐。
  • 廚師(伺服器) 慢慢切菜、擺盤、收錢。
  • 結果: 一切正常,收錢正確,菜也好吃。
  • 盲點: 這種測試環境太「優雅」了。現實世界不是只有一個客人,而是成千上萬人同時衝進來。

2. 應該要做的測試:瘋狂的「自助餐搶購演習」(併發測試)

為了抓出這種「張冠李戴」的錯誤,正確的測試應該要這樣搞:

  • 模擬場景: 找 1,000 個臨演(虛擬機器人),在同一秒鐘全部衝進餐廳大喊「我要結帳」!
  • 觀察重點:
    • 廚師會不會因為太忙,左手拿著 A 的信用卡,右手卻刷了 B 的帳單?
    • 廚房的傳票(數據)會不會滿天飛,導致把桌號 5 的龍蝦送到了桌號 3?
  • 合格標準: 哪怕場面再混亂,A 的錢只能買 A 的飯。只要有一單搞錯,這個系統就不能上線。

3. 最後的保險絲:裝一個「防爆開關」(熔斷機制)

除了測試,系統還需要一個緊急開關,就像家裡的「保險絲」。

  • 現實情況: 這次事故中,玩家被連續盜刷了幾萬歐元,系統卻還在傻傻地扣款。
  • 正確做法: 系統應該要有一個像「銀行風控」一樣的警報器。
  • 設定規則: 「如果同一個人的 PayPal 在 1 分鐘內被使用了 5 次以上」或者「如果不一樣的帳號都在刷同一張卡」。
  • 觸發動作: 警報響起,直接「拉閘斷電」!強制停止所有交易。
  • 比喻: 這就像如果一個客人在 10 秒內吃了 50 個漢堡,餐廳經理應該立刻報警並停止上菜,而不是繼續給他塞漢堡。

個人想法

《終末地》我是有玩的,是好玩的,但同時毛病也很多,這個不在本文章討論範圍。關於 Paypal 支付事件,我首次是在群看到,沒多大留意,直到後來我上巴哈才發現事情很大條。

我一開始還只是把當瓜看,我看到有巴哈網友說「你的信用卡已進入卡池。」,我是笑了出來,我是沒想到這麼刺激,原來抽卡是這個意思,這腦洞......讓我嘆為觀止(震驚)。

後來我再仔細看事情經過,我慢慢笑不出來,我不理解啊,這裡簡單自我介紹,叔的代碼很拉,我現在水平頂多是寫一個 hello world 程式,簡單說就是無法獨自編程,小破站是依賴 AI 幫忙重構完成,它佔了很大功勞。

我為什麼會笑不出來呢?

如果你不會編程,你也沒玩這個遊戲,你當樂子看是挺歡快的。但當我看到說拿別人的卡扣款,這.......簡單說就是 A 抽卡,B 買單,我是不會手搓代碼,但架構能力,邏輯還是有的,就...我很不理解,於是我去問 AI。

它和我說是開發方問題,然後它向我解釋這個漏洞是如何發生的,程式碼為什麼沒能將「這是 A 的 Token」和「這是 B 的請求」兩者嚴格地綁定在一起。我看完後是覺得匪夷所思的,久久不能平靜,我是真想不出來, 這是......這種感覺以前發生過許多回,我是越想越詫異。

瑞士奶酪理論示意圖
瑞士奶酪理論示意圖

Davidmack - 自己的作品, CC BY-SA 3.0, wiki 連結

這是一個典型的瑞士奶酪模型,從開發 -> 測試 -> 上線,每一層都存在漏洞,層層穿透,最終導致了這次事故。

這個 BUG 是隱蔽的,不容易測出來,但同時它也是一個低級錯誤,說明開發團隊缺乏充足經驗。

有沒有可能是 Paypal 問題?

不可能,如果真是 PayPal 的問題,那麼所有使用 PayPal 支付服務的平台都會出事,但事實上只有《終末地》出了問題,這說明問題出在遊戲開發上。

有沒有可能是編程語言的問題?

這是我在網上看到有人說是 Go 語言的 Bug 導致。回答是不可能,這不是語言問題,是編程邏輯錯誤,像是一個人說話不清,你不會歸因到語種上。

後續影響

這起事故在國內國外沒有引起大規模的關注,這對官方本身算是不幸中的大幸,但對玩家而言還是有不少影響。

玩家方面

關於退款方面,官方好像1個小時左右就立馬停止支付通道,當天公告會發起全額退款,處理還是很及時的,因為受影響的玩家是一定拿到的,但他們損失不僅是錢,他們帳戶有可能會被凍結,因為帳戶短時間高頻進行多次交易,而且涉及多國幣種。

這種情況下銀行會認為帳戶有異常操作或洗錢嫌疑,然後凍結帳戶,玩家就算拿到退款也沒用,因為帳戶被凍結了,無法提取。

鷹角網絡方面

先提退款,PayPal 的規則通常是:當發生退款(Refund)時,PayPal 不會退還當初收取的那筆手續費(通常是 3%-4% + 固定費用),比如誤扣100刀,Paypal 手續費為4刀 ,鷹角實收96刀,退款時鷹角是要吐回100刀給玩家。

其次,這個事故會也影響 Paypal 平台,有部份玩家可能會直接找銀行申請 Chargeback 把錢討回來,Paypal 是要先把錢墊付給玩家,然後回頭再向鷹角討回,這其中一定會產生賠償糾紛。

還有部份玩家誤會是支付平台的鍋,人家平台後續還要不要和你鷹角合作,搞這麼一出,不會明面上打官司,但私下會經常聊天喝咖啡。

歐盟法律(GDPR)可能會對 GRYPHLINE(鷹角的子公司)進行巨額罰款,GDPR 要求企業必須實施足夠的技術和組織措施來確保數據的安全性,還有數據處理的公平性與目的限制。這次支付事件就是未經用戶授權便進行消費動作,這已觸犯了這兩個核心條款。但這個機率較低,因為官方有及時處理。

其他方面

短期內所有國產遊戲在海外發行都會受到審查收緊和信用污名化,因為此時事故非常惡劣,上面 AI 指這個事故是 P0 級是因為最高只是 P0,但實際程度是達到 P-1 / P-2。

鷹角網絡會破產嗎?

鷹角網絡不會破產,子公司 GRYPHLINE 也短期內不會破產,鷹角會全力保住它,因為在海外宣發已經投了許多錢,沉沒成本巨大,它們不會輕易放棄,然而未來幾年的財報都不會太好看就是。

鷹角網絡會賠20億嗎?

最近流行什麼斬殺線理論,官方不會賠這麼多錢的,但賠是一定的,不會20億那麼誇張,幾百到幾千萬這個區間吧。上千萬是比較壞的走向,但不是沒可能,但幾百萬是跑不掉。

結語

我寫這篇文章原因不是要黑遊戲,我自己本身有玩過《明日方舟》,所以《終末地》公測時我也去體驗,遊戲......不差,甚至可以說精良,但也有許多毛病,有點像一坨華麗的......。

扯遠了,寫這篇文章原因是這兩年發生許多事,有些明顯是人禍,像之前香港大火,內地預制菜風波,到現在這個遊戲支付事故,都有些共通點,都忽略隱性成本。

什麼是隱性成本?公關、安全、維護這些都是,企業都不重視,甚至降本增笑,首先想到的都是這些部門,因為它們不能在財報上帶來增益,覺得這個東西不賺錢,於是花很多錢投入營銷宣發。

鷹角這回也是,這次事故他們還下了一步臭棋,在條款中新增要玩家自願集體訴訟,前把充值的人得罪,後把其他潛在用戶也得罪,這......我不理解。

信息安全方面,很多人,包括我以前也是,忽略了其重要性,以為不出事就沒事,不出事是因為有人在默默做事,讓它不出事,因為一旦出事就是災難級的,所謂「善戰者無赫赫之功」,你只顧著賺錢,卻不顧口袋裡的破洞。看現在,這些宣發還要不要做呢,宣發再多也收不來錢,一個遊戲最賺錢的時間來這一出。

再嘮叨一句,從商業層面,你的信用破產了是很難再談合作的,這個信用值也是隱性成本,是一個隱形戶口,所以這次事故是可以載入「屎冊」。

關於作者:BiscuitMiner

熱愛遊戲,喜歡模擬和策略類型的遊戲,動作類遊戲也喜歡玩,但相對玩得很菜,許多時連第一關都打不過去。理想是成為一枚魔法獅。

留言 (0)