Login Server for Massive User Sinlge login server with multiple game servers

Login Server / Game Server

要寫一個 Login Server 要考慮。

  1. Player 在 Login 時,和 Login Server 的傳輸是加密的,但遊玩時 Player 連線 Game Server 資料一般都不加密。
  2. Login 完成後,玩家的連線要如何從 Login Server 安全的轉移到 Game Server。
  3. 如果有帳號密碼 (也就是不使用 Google / Facebook 這類第三方認證),密碼儲存的安全問題。

Before Login, We need to Create a account

Login Server 是 SSL Server,使用者用 SSL 將新建立的 ID 和 Password 傳送到 Login Server,傳輸過程可以信任。但我們不能假設 Hacker 沒辦法直接取得 Login Server 內的密碼資料。所以儲存密碼時,要同時使用下面幾種安全措施。

Slow Hash Algorithm

密碼一定要經過 hash 在儲存,不能用明碼,如果 hacker 直接取得 Login Server 硬碟裡的資料時,拿到的也只是 hash 過的東西,非使用者真正的密碼。

但是如果是快速的 hash function,hacker 可以用窮舉法(Brute force 或俗稱暴力法) 嘗試 hash 所有的文字的排列組合找出使用者密碼,所以需要使用慢速的演算法拖累窮舉法的速度,就算 hacker 超有耐心,使用的硬體超強,我們發現密碼被 hack 後時還有時間通知使用者讓他們修改其他的帳號的密碼,這是對使用者隱私安全負責的做法。

一般常用的 slow hash algorithm 是 Bcrypt w/ 12+ factor,而 SHA-512 之類的運算速度太快,不該使用。

Salt

有種對付 Hash 的方法叫 Rainbow Table Attack,它是事前就花大量的時間建立 Hash 前和 Hash 後的字串表。所以當 Hacker 取得了伺服器的 hashed password 後,它不用去拿所有的文字排列組合跑 hash function,而是直接查表,就能很快的知道 hash 前的密碼是甚麼。

對抗 Rainbow Table Attack 的措施叫 Salt,它是一串亂數產生的字串,每組密碼配對的 salt 都不同。在 hash 前,我們把 salt 和 password 連起來,然後再將組合後的字串 hash 儲存。

Salt 和 Password 是一起儲存在 Login Server 的資料庫裡的,如果 hacker 有辦法取得 password,就有辦法取得 salt。所以 salt 不是 rainbow table attack 的完全防禦,但是夠長的 salt (至少要和 hash 結果一樣長) 會讓 rainbow table 變的超級巨大、甚至難以產生,因此和 hash 對抗窮取法一樣,是增加難度爭取時間的東西。

Pepper

Salt 和 Pepper 聽名字就知道是類似的功能,只是 Salt 是寫在資料庫裡,每組密碼不同,Pepper 是寫死在 code 中,只有固定一組,算是錦上添花的東西。結合字串一般是 Pepper + Password + Salt,要反過來也行,沒有實質上的差別。

Step 1: Login Server Verifies User ID / Password

Login 的第一步是使用者利用 SSL 將 ID/Password 傳到 Login Server,Login Server 認證無誤後,要做下面幾件事:

  1. 選擇 Game Server (如果有 load balancing 的需求的話)
  2. 記錄此位使用者 Login 的時間
  3. 記錄此位使用者的 IP Address
  4. 亂數產生一組字串 (token)
  5. 將 Game Server 的 ip address 和剛剛產生的 token 回傳給使用者

Step 2: User Sends User ID and Token to Game Server

取得 Login Server 給的 Game Server ip address 後,使用者可以用明碼 (socket) 連線 Game Server,然後使用者將 Login Server 的 Token 和 User ID 傳給 Game Server。

Step 3: Game Server Verify User ID / Token

Game Server 取得使用者的 User ID 和 Token 後

  1. Game Server 用 SSL 將 User ID / Token 和 User IP address 傳給 Login Server
  2. Login Server 確認 User ID / Token 是否和自己之前提供給使用者的一樣
  3. Login Server 確認 User IP address 是否和之前連線的 IP 一致
  4. Login Server 用之前紀錄的時間檢查 Token 是否過期 (一分鐘足以完成 Login 了)
  5. 如果沒過期,IP 正確,且收到的 User ID / Token 也和 Login Server 之前產生的一樣,就告知 Game Server 此位使用者是安全的。

Step 4: Game Server Feedback Result to User

如果 Login 成功,Game Server 可以繼續遊戲邏輯。如果 Login 失敗,告知使用者並結束連線。

Random Data

Salt 和 Token 都需要產生亂數字串,產生亂數字串要小心安全等級問題。像 C 的 rand() 之類的 API 都只是查亂數表,意思是同樣的亂數表所產生的 sequence 是永遠一樣的,這並不符合網路安全的需求。就算是用 srand() 這種可以產生亂數種子依照時間更改不同的亂數表,它依然沒有達到網路安全的需求規範。如果 Login Server 有用 openssl 的話,可以用 RAND_bytes() 加上 base64 編碼產生安全的亂數字串。