我正在創建一個包含簡單JavaScript遊戲的Web應用程序。玩家玩完遊戲後,會將高分發送到服務器並保存。
在特定時間段後,得分最高的玩家將獲得獎賞。
安全發送高分並防止客戶端發送“假”高分的方法?
當前,我們正在使用:
- Https。
- 在每個遊戲之前提供服務器隨機令牌,並在遊戲結束後隨分數發送。 li>
我正在創建一個包含簡單JavaScript遊戲的Web應用程序。玩家玩完遊戲後,會將高分發送到服務器並保存。
在特定時間段後,得分最高的玩家將獲得獎賞。
安全發送高分並防止客戶端發送“假”高分的方法?
當前,我們正在使用:
服務器無法完全信任從客戶端接收到的任何數據,因此很難驗證高分。
以下是一些選擇:
混淆客戶端代碼和到服務器的流量。這是最簡單的選項-仍然可能作弊,但可能不值得任何人花費時間。
將游戲的全部或部分重播發送到服務器進行驗證。玩家的舉動可以在服務器上運行以確定合法分數。這將適用於某些遊戲,而不適用於其他遊戲。
將游戲邏輯和驗證移至服務器。客戶端只需將每個動作中繼到服務器,並在其中進行驗證並更新遊戲狀態。
這取決於遊戲的工作方式,人們的遊戲可能性會作弊,以及您是否在乎他們。
如果您的攻擊者是網絡層上的中間人攻擊者,那麼https就足夠了。但是不幸的是,您的攻擊者是客戶端,所以這毫無意義。
防作弊遊戲的第一規則:永遠不要信任客戶端!客戶掌握在敵人的手中。
JavaScript遊戲在用戶的網絡瀏覽器中運行。眾所周知,作為Web開發人員,如今每個Web瀏覽器都帶有內置調試器,該調試器可以在應用程序運行時查看和更改所有變量。用戶可以在提交分數之前簡單地使用調試器來更改其分數。您無法採取任何措施來防止這種情況。借助基於瀏覽器的遊戲,您甚至無法在其上使用第三者反作弊工具(該工具具有可疑價值,並且無論如何在倫理上都值得懷疑)。
唯一的對策是實施所有值得操縱的遊戲機制在服務器上。客戶端除了將用戶的命令轉發到服務器並根據服務器的消息可視化遊戲玩法外,什麼都不做。實際的遊戲玩法應該在作弊者無法到達的服務器上進行。
是的,這意味著您將不得不從頭開始重新設計遊戲的軟件架構。這也意味著您將必須添加一些預測和內插代碼,以使網絡滯後現像不那麼明顯。這也意味著您將需要更好的服務器硬件和更好的服務器Internet連接。但是,當您想要一款不作弊的在線遊戲時,這是唯一的選擇。
要獲得可靠的遊戲高分,您需要的是“ 工作證明”,或者更恰當的稱呼為遊戲證明。
工作證明/遊戲是在完成遊戲之前很難計算的任何數據,但是在完成遊戲之後很容易計算並且很容易被服務器驗證。例如,對於數獨遊戲,工作證明就是解決難題的方法。
不幸的是,在許多遊戲中都沒有通用的方法來集成合適的遊戲證明系統。並非總是可以在不調整或重新調整遊戲玩法的情況下集成遊戲證明,或者將排行榜的範圍限制為僅可以包含足夠安全的遊戲證明的元素。
遊戲證明遊戲開始於服務器為遊戲的RNG發行種子。然後,客戶將必須找到與球員已經簽發的種子相匹配的比賽證明。在許多遊戲中,可以通過將游戲的解決方案以高分提交的方式提交到服務器來形成遊戲證明,在其他遊戲中,可能需要根據遊戲和證明的不同程度來記錄整個遊戲會話的詳細程度。您正在使用的遊戲。
遊戲證明需要具有抗重玩性(一個玩家不應使用另一位玩家的已完成遊戲來簡化自己的遊戲證據的計算)。這將游戲證明限制在遊戲中,其中存在一些隨機性,即玩家不能只是重複使用另一位玩家的遊戲證明,而且也不能具有過多的不確定性行為,以致無法驗證該遊戲。
證明的玩法也很有限。例如,在數獨遊戲中,不可能證明玩家解決難題所需的時間。遊戲證明也不能總是區分玩家自己玩的遊戲和編寫了為他們玩遊戲的腳本的玩家。
我只想提到有解決此問題的一種方法,但是您可能無法使用它;該解決方案稱為“同態加密”,它允許客戶端執行已知的計算而無需確切知道他們正在使用什麼值,並且服務器可以檢查所計算值的結構以證明客戶端不只是發送回一個隨機字符串,但實際上是根據提供的幾個值構建而成的。
問題是,它是 slow 還是 incomplete ,其中“ incomplete”的意思是“未包含所有邏輯原語”。通常,它是一個部分系統,允許進行一些加密和解密操作E(),D()以及一些複雜的操作⊕,使得
D(E(A)⊕E(B)) = A + B,
等。
因此,讓我們看一下如何解決某些遊戲的問題。考慮一個“熄燈”類型的遊戲,在該遊戲中,您按下六角形網格的 N 十六進制,然後每個都切換其狀態和周圍狀態。這是那些“印刷機”上的可交換代數,因此在給定的解決方案中,總共不超過N個印刷機,加上每個十六進制僅取決於初始狀態加上其自身的印刷機加上其周圍的6個十六進制。 / p>
由於我們的同態加密方案僅允許+,而不能進行XOR,因此我們為每個hex分配了一個3位計數器,用於對其進行翻轉的次數。 (客戶端軟件會自動將十六進制的每兩次按縮小到一次按。)因此,實際的翻轉動作是位矢量,
001 001 000 000 000 001 001 001 000 001 001 000 000 ... 000 00000000 00000001
換句話說,它們在翻轉的這3位字段中每個都有1,在某些16位計數器中還有1。
我們使用同態加密方案對所有這些加密,然後將它們分別發送給客戶端,然後客戶端將根據我們發送回的這些加密值計算出的加密值發送給我們。然後,我們將其解密,並將解密後的值與位串
001 001 001 001 ... 001 11111111 00000000
進行比較,並與初始遊戲進行比較狀態與這8個計數器位的0相鄰。
如果他們向我們發送一個隨機值,則我們接受它的機會是2 -(N + 8) sup>,因此他們通過測試的唯一有用方法是使用我們為它們提供的值以某種允許的組合使用。它們可以訪問一些由於整數溢出而不允許直接執行的操作,但是我們總是可以使字段的寬度大於3位,以使這些計數器的使用成本更高。但是我們從來沒有傳遞過他們各自的按鈕,更不用說重放歷史了:我們接受了一個向量,上面寫著“這是我如何翻轉網格”,這是每個人都在警告您的“超級不安全的事情”,但是我們這樣做的方式是,如果他們沒有訪問密鑰就無法完成我們擔心的事情。
相反,您在加密投票中會看到這種事情,您需要確保投票機的安全性。不會自發給愛麗絲1000票。
客戶端的所有內容都可以被欺騙。因此答案是否定的。謝謝@盧克公園
我的建議更多是混淆技術,對於許多用戶來說可能是一個令人沮喪的障礙。但是,無論是高級用戶還是堅定的用戶,仍然可以分析您的源代碼以重現結果。
使用 Hashids之類的工具來創建分數的哈希值,並將其發送到您的服務器請求中以及明文得分。用戶ID的字符串值可以是用於編碼得分的哈希值的鹽,如果共享,則使哈希值無用。在服務器端,您可以解碼該哈希並將結果與發送的純文本分數進行比較,以確保它們符合預期。