撲克協會的會員個資怎麼保護?六層資料安全設計拆解
加入協會要填姓名、手機、生日,正式賽事還要驗證身分證件。這些資料被存到哪裡、怎麼保管,是每一位選手都該知道的事。本文拆解 HyperPoker 會員系統的六層資料安全設計:身分認證、加密儲存、金鑰保管、權限控制、檔案存取與傳輸加密。
註冊會員的時候要填姓名、手機、生日,正式賽事還要驗證身分證件。這些資料交出去之前會多想一下,是很合理的謹慎。
我們沒有打算用一句「請放心」帶過。資料保護是設計出來的,不是宣稱出來的,所以這篇直接把設計攤開講:從登入、儲存、金鑰、權限、檔案到傳輸,一共六層,每一層都有明確要擋掉的東西。 這套設計背後只有一個原則:每一層都獨立成立,不依賴其他層來生效。
第一層:我們沒有你的密碼
帳號密碼是最敏感的一類資料,因為很多人會在不同網站重複使用同一組。我們對這件事的處理方式是不經手:HyperPoker 沒有自己的密碼系統。
登入走的是業界標準的登入協定(OIDC),交給專門做身分認證的服務處理。你在那裡完成登入之後,我們收到的只是一張有數位簽章、會過期的通行證,我們驗證簽章是否為真、有沒有過期,就這樣。我們的資料庫裡沒有密碼欄位,也沒有密碼的雜湊值。
換句話說,我們的系統裡根本不存在密碼這項資產。 這是最乾淨的一種設計:不持有的東西,不需要防守。
第二層:存下來的證件號碼,不是原樣存放
身分證號這類資料不得不存,因為協會要核對本人、要發獎金。但「存下來」不代表「原樣存下來」。
證件號碼在寫入資料庫之前會先用 AES-256-GCM 加密。這是目前廣泛使用的對稱加密標準,銀行、政府和主要雲端服務都在用,GCM 這個模式除了加密還會附帶完整性驗證,資料被竄改一個位元都會驗不過。同一組號碼每次加密的結果都不一樣。
實際落在資料庫裡的樣子,大概是這種感覺:
| 環節 | 內容 | 說明 |
|---|---|---|
| 你輸入的 | A123456789 | 只在傳輸與驗證的當下以明文存在,不會以這個樣子落地。 |
| 資料庫裡的 | 9f2c04e1b7…d31a8c05f6 | 資料庫裡就是這串位元組。要把它還原成號碼,必須有另一個系統裡的金鑰。 |
這裡有個實務問題:加密之後就沒辦法用「這個證件號碼是否已經註冊過」去查詢了。我們的做法是另外存一組帶金鑰的雜湊指紋(HMAC-SHA256),而那把金鑰放在下一層要講的金鑰保管服務裡,不在資料庫裡。
差別在這裡:一般的雜湊只要拿到值,任何人都可以把所有可能的號碼算過一遍去對照,證件號碼的組合數量沒有大到能擋住這件事。帶金鑰的雜湊不行,少了那把金鑰,指紋既反推不回號碼,也沒辦法用事先算好的表去比對。所以系統可以判斷「是不是同一個人」,卻不需要把號碼解出來看,而這個能力也不會跟著資料庫一起被帶走。
第三層:鑰匙不跟鎖放在一起
加密只有在金鑰安全時才有意義。把金鑰寫在程式碼裡、或存在同一個資料庫的另一張表,等於把鑰匙插在門上。
我們的加密金鑰放在跟資料庫分開的金鑰保管服務裡,權限控管與存取紀錄都獨立。程式在啟動時向它取出金鑰,這一次取用會留下紀錄。金鑰不會寫在程式碼裡,也不跟會員資料放在同一套系統。
第四層:能看到的人越少越好
個資保護的實務重點之一,是控制資料在內部的流通範圍:系統回傳哪些欄位、日誌記錄多少內容、每個協會人員的帳號看得到什麼。這幾件事我們是這樣處理的:
- 欄位層級的封鎖。 加密後的位元組與比對用的指紋,在資料結構上就被標成不能輸出,不會出現在系統的回應裡。這不是靠人每次記得過濾,是在結構上就擋下來。
- 畫面上預設是遮罩的。 協會人員平常看到的是開頭兩碼、結尾三碼,中間打星號的形式(像
A1*****789),電子郵件同理。只有在核對待審申請時才看得到完整號碼,因為那一步就是在確認證件與本人相符。 - 日誌會主動塗掉敏感欄位。 系統維護一份明確的敏感欄位清單,涵蓋各種權杖、密碼、簽名影像、證件號碼、生日、聯絡方式等等,日誌在寫出去之前會先經過這份清單,把命中的欄位替換掉,而不是靠寫程式的人每次記得繞開它們。
- 協會之間互相看不到。 每一次會員資料查詢都必須帶著協會的識別碼,這是在資料存取層強制的,不是靠前端隱藏。A 協會的管理員沒有任何路徑可以讀到 B 協會的會員。
- 權限採「資源加動作」的細分模型,而且改動會留紀錄。 誰在什麼時候調整了誰的權限,寫進稽核日誌。這對防止外部攻擊沒有直接幫助,但它讓內部濫用變成可追查的事。
第五層:證件照片不放在公開的地方
上傳的證件照片與簽名影像屬於風險最高的一類,因為它們是圖像,看到就是看到,沒有遮罩的餘地。
- 檔案儲存分成公開與私有兩區,個資檔案一律進私有區。私有區不提供公開網址,讀取一律要走下面說的簽發流程,路徑本身不是取得檔案的憑據。
- 需要顯示的時候,系統才產生一組有時效的簽名網址,時間到自動失效。每一次讀取都是一次獨立簽發,沒有長期有效的路徑指向檔案。
- 上傳用的網址是一次性的,第一次寫入成功之後同一組網址就自動失效,每一次上傳都必須重新簽發。
- 檔名會先清洗過再落地,不接受原始檔名裡的特殊字元或路徑符號。
第六層:傳輸加密與入口防護
資料在傳輸過程中全程使用 TLS 加密,這是現在網站的基本要求,比較少被提到的是內部連線:我們的應用程式連到資料庫、連到快取服務時同樣走加密連線並驗證憑證,不是「反正在內網就明文傳」。
對外的入口有速率限制,同一個來源在短時間內反覆請求會被節流,大量自動化的試探因此變得不划算。協會也可以停用會員帳號,停用之後這個帳號就不能再做需要權限的操作。
六層疊在一起,實際達成什麼
這六層不是各做各的。把它們放在一起看,可以歸納出三個系統層級的性質,也是整套設計要達成的目標狀態:
密碼不存在於系統之中。 認證由外部身分服務負責,我們的資料庫裡沒有密碼,也沒有密碼的雜湊值,所以它不構成一項資產。
證件號碼在資料庫裡只以密文與帶金鑰的指紋形式存在。 還原它、或是拿指紋去比對,都需要另一個獨立系統裡的金鑰,兩者的權限控管與存取紀錄各自分開。
證件影像不放在任何可公開存取的位置。 每一次讀取都要重新簽發網址,而且會過期,沒有一條長期有效的路徑指向它。
這就是分層設計的價值:每一層都獨立成立,不依賴上一層永遠有效。資安也沒有終點,方法一直在演進,這六層是目前的狀態,之後只會再往上加。
你自己可以做的三件事
- 登入盡量使用 Google 這類第三方登入,並且在那個帳號上開啟兩步驟驗證。你的帳號安全會直接沿用它的防護。
- 上傳證件時只拍需要的那一面,避免同一張圖裡出現無關的其他證件或文件。
- 收到任何要求你提供完整證件號碼、驗證碼或登入連結的訊息,先確認來源。HyperPoker 官方不會用私訊向你索取這些東西。
對這篇的內容有疑問,或想回報你發現的安全問題,可以寫信到 support@hyperpoker.com。回報時請不要在信裡附上實際的證件資料。技術性的疑慮我們一律當作正經問題處理,因為問這種問題的人,通常是最認真在使用產品的人。
常見問題
- HyperPoker 會存我的登入密碼嗎?
- 不會。登入走業界標準的登入協定(OIDC),由專門的身分認證服務處理,我們的資料庫裡沒有密碼欄位,也沒有密碼的雜湊值。
- 身分證號碼是以什麼形式存在資料庫裡?
- 以 AES-256-GCM 加密後的密文形式存放,另外附一組帶金鑰的雜湊指紋(HMAC-SHA256)供系統比對是否為同一人。密文要還原成號碼、指紋要拿來比對,都需要另一個獨立系統裡的金鑰。
- 上傳的證件照片會被公開存取嗎?
- 不會。個資檔案一律存在私有區,沒有可以直接連過去的公開網址。需要顯示時才簽發一組有時效的網址,時間到自動失效。
- 協會櫃檯看得到我的完整身分證號碼嗎?
- 日常作業看到的是遮罩後的號碼,只留開頭兩碼與結尾三碼。核對待審申請時才會看到完整號碼,因為那一步就是在確認證件與本人相符。