[設計案例] 授權碼 如何實作? #3, 數位簽章
摘要提示
- 問題意識: 授權碼如何證明「來源正確且未被竄改」是核心問題
- 倡議原則: 採公開演算法+私有金鑰的密碼學實務,而非自創加密
- 技術基礎: 使用非對稱式加密(RSA)與雜湊(Hash)實作數位簽章
- 簽章流程: 私鑰簽名資料雜湊,公鑰驗證以確認來源與完整性
- 金鑰管理: 正式環境應用 Key Container/CA;示例僅為演示用途
- 程式架構: TokenHelper 初始化金鑰庫、簽章 EncodeToken、驗章 DecodeToken
- 資料打包: 授權資料BSON序列化後與簽章以Base64合併傳遞
- 驗證邏輯: 驗安全性(VerifyData)與有效性(IsValidate)雙重檢查
- 實務應用: ASP.NET MVC5 啟動流程中強制驗授權以保護整站
- 風險警示: 私鑰外流即失去安全性;公私鑰XML差異需嚴格管控
全文重點
本文聚焦在授權碼驗真與防偽的設計實務,核心目的在於讓系統能辨識授權資訊確為「原廠發出且未被竄改」。作者強調資訊安全不應依賴「自製加密」或隱藏演算法,而是應採行經學界與產業驗證的公開演算法,配合僅由自己持有的金鑰來達成安全性與可審核性。基於此原則,本文採用非對稱式加密中的 RSA 與雜湊演算法,實作數位簽章以作為授權碼的「封條」。
數位簽章的精神是:以私鑰對資料的雜湊值進行簽名,任何人都能用對應公鑰驗證。驗證時,接收端對原始資料重新計算雜湊,同時用公鑰解開簽章取得寄件方雜湊,兩者相同即可確認資料未被竄改且確為私鑰持有人所發出。本文也以三種情境對對稱式與非對稱式加密做直觀說明,進而點出數位簽章在「證明來源與完整性」上的關鍵價值。
在程式實作上,作者以 .NET 的 RSACryptoServiceProvider 搭配 SHA256 雜湊,提供一套 TokenHelper:初始化階段讀入站台私鑰與友站公鑰,內部以字典快取金鑰供後續使用。EncodeToken 會將授權物件(TokenData)序列化為 BSON,計算簽章後以「資料Base64 + 分隔字元 + 簽章Base64」形式打包輸出。DecodeToken 則先解包與反序列化,再以 Token 的 SiteID 取出對應公鑰做 VerifyData 驗章,最後再依 Token 自帶規則(IsValidate)驗授權有效性,形成「安全性驗證」與「授權規則驗證」的雙層防護。若格式不正確、站台未知、簽章不符或授權過期,皆會拋出相對應例外,阻止系統繼續。
金鑰管理是實務關鍵。作者明確指出示例程式為了教學方便採用檔案/XML載入,不建議用於正式環境;建議採 OS 提供的 Key Container 與 CA 機制發放/管理金鑰,避免私鑰外流風險。文中亦舉出包含私鑰與僅含公鑰的 RSA XML 差異,提醒讀者務必嚴控私鑰。
最後,作者示範如何在 ASP.NET MVC5 專案啟動時強制驗授權:將 TokenData、SiteID、私鑰與公鑰清單配置於 appsettings.json,於 Startup.Configure 中初始化 TokenHelper 並解碼/驗證授權,若驗證失敗即拋例外中止啟動,確保未授權或偽造的情況下網站無法對外服務。文末提供完整範例程式碼的 GitHub 連結,便於讀者實作與延伸。
整體而言,本文將數位簽章的概念落實為可複用的授權碼方案,兼顧「來源可信、內容完整、啟動阻斷」三要點,並提醒金鑰管理在整體安全設計中的核心地位。
段落重點
資料的封條: 數位簽章 原理說明
作者先從安全設計的基本觀念出發,指出「不要發明自家加密」與「公開演算法+私有金鑰」的正確路徑,理由是程式碼難以長期保密,且安全性應建立在金鑰秘密而非演算法秘密。接著簡述對稱與非對稱式加密差異,並以 RSA 為例說明一對金鑰的用途:私鑰需嚴格保護,公鑰可公開分發。透過情境對比,作者分別說明對稱式在軍事廣播的一對多通訊(如電影模仿遊戲中的 Enigma),以及非對稱式在一對一通訊的身分驗證與機密性。重點落在第三個情境:數位簽章。簽章流程為對原始資料計算雜湊,使用私鑰簽名雜湊,接收端再以公鑰還原雜湊並與自己計算的雜湊比對,若一致即證明資料未改且確為私鑰持有人發出。此機制既能提供來源鑑別與完整性驗證,又具法規與業界實務基礎,適合作為授權碼的「防偽封條」。
實作說明: 數位簽章 + 授權碼 實作
本文以 RSA 數位簽章為核心,將授權碼序列化後簽名,部署於網站設定。啟動時先驗章,通過才依授權開啟功能。程式面向上,使用 RSACryptoServiceProvider 與 SHA256CryptoServiceProvider,並以 TokenHelper 封裝初始化、簽章與驗章。Init 支援兩種方式:從金鑰目錄載入XML或直接給定XML字串,將各站的 RSACryptoServiceProvider 快取於字典中;同時保留當前站台的含私鑰實例以供簽章。作者展示含私鑰與僅公鑰的 RSA XML 例子,強調私鑰欄位(如P、Q、D等)外流的嚴重性。EncodeToken 將 TokenData 以 BSON 序列化成位元組陣列,呼叫 SignData(data, hashAlg) 產生簽章,最後以Base64組裝「資料|簽章」字串回傳。DecodeToken 先拆分Base64、復原資料並反序列化成Token物件,執行 IsValidate 確認授權規則(如日期/範圍等),再以 Token.SiteID 取公鑰執行 VerifyData 驗章,雙關卡都通過才算有效。過程中針對格式錯誤、未知站台、簽章不符、授權失效等情境,拋出特定例外以利診斷。作者也提醒在正式環境應以 Key Container/CA 管理金鑰,示例的檔案式載入僅供教學,勿直接沿用於生產。
實際應用: ASP.NET MVC5 啟動時檢查授權碼
在 ASP.NET MVC5 專案中,作者將授權驗證前置到網站啟動流程,未通過即中止整站啟動,確保防線前移。設定面在 appsettings.json 增設 License 區段,包含:TokenData(序列化+簽章的授權碼)、SiteID、SitePrivateKey(僅示例用,正式環境不建議)、以及 PublicKeyStore(可驗證之站台公鑰清單)。於 Startup.Configure 中讀取該區段,建立字典並呼叫 TokenHelper.Init 載入金鑰,隨即解碼並驗證 SiteLicenseToken。若驗證成功,網站如常啟動;若超出授權期限,會拋 TokenNotValidateException;若內容遭竄改或來源不明,會拋 TokenNotSecureException;若格式不合或站台未知,亦會有相應錯誤。作者附上執行截圖,展示正常、過期與竄改三種狀態的系統反應。最後提供 GitHub 連結,供讀者取得完整解決方案。此實作展示了如何用數位簽章把「授權驗真」與「站點啟動」強耦合,將未授權風險在最早期阻斷,同時維持程式碼結構清晰與可維護性。
資訊整理
知識架構圖
- 前置知識:
- 基本密碼學觀念:對稱式/非對稱式加密、金鑰、公私鑰、Hash/雜湊
- .NET 加解密基礎:RSACryptoServiceProvider、HashAlgorithm(SHA-256)
- 序列化/反序列化概念(JSON/BSON)
- ASP.NET MVC 應用程式啟動流程(Startup 配置)
- 核心概念:
- 數位簽章:以私鑰對資料雜湊值簽名、以公鑰驗簽,確保來源與完整性
- RSA 非對稱式加密:公鑰/私鑰成對,私鑰嚴格保護,公鑰可廣泛發佈
- 授權碼架構:序列化後的 Token + 簽章 合包;啟動時驗簽與驗證授權規則
- 金鑰管理:Key Container/CA 供應、私鑰保護、避免明文文件存放
- 安全與驗證流程:SignData/VerifyData、Hash 選型(SHA-256)、例外處理
- 技術依賴:
- RSA 數位簽章依賴 Hash(如 SHA-256)產生資料摘要
- 授權驗證依賴序列化格式(BSON)與一致的資料模型 TokenData
- 啟動驗證依賴設定來源(appsettings.json)與組件初始化(TokenHelper.Init)
- 公鑰信任依賴可信發佈與/或 CA 管理
- 應用場景:
- 軟體授權驗證:確保授權碼由原廠簽發且未被竄改
- 服務間通訊:以數位簽章驗明來源,確保傳輸完整性
- 配置檔保護:對配置內容簽章,部署端只持公鑰驗簽
- 啟動守門機制:Web 應用啟動前驗授權,未通過即中止
學習路徑建議
- 入門者路徑:
- 了解非對稱加密與數位簽章基本原理(公鑰/私鑰、Hash、簽名/驗簽)
- 熟悉 .NET 的 RSACryptoServiceProvider 與 HashAlgorithm(SHA256)
- 以簡單範例:對一段文字做 SignData/VerifyData,體會流程
- 進階者路徑:
- 實作 TokenData 的序列化(BSON/JSON)、簽章打包與驗簽拆包
- 設計例外處理流程(格式錯誤/驗簽失敗/授權失效/站點不存在)
- 導入 Key Container 或憑證(X.509/CA)管理,替代 XML 明文金鑰
- 實戰路徑:
- 在 ASP.NET MVC/ASP.NET Core Startup 早期階段初始化 TokenHelper,載入 SiteID/私鑰/公鑰庫/Token
- 啟動時驗簽與檢核 Token 授權規則,未通過則終止啟動流程
- 建置公鑰發布與輪替機制;金鑰外洩演練與應變(撤銷、重新簽發)
關鍵要點清單
- 數位簽章原理: 以私鑰對資料雜湊簽名、以公鑰驗證,確保來源與完整性 (優先級: 高)
- RSA 金鑰配對: 公鑰可公開、私鑰嚴格保護;演算法公開、靠金鑰保密 (優先級: 高)
- Hash 選擇(SHA-256): 簽章對象是資料的雜湊值,避免大資料直接簽章 (優先級: 高)
- SignData/VerifyData: .NET 中簽名與驗簽的核心 API 流程 (優先級: 高)
- Token 結構與序列化: 將 TokenData 序列化(BSON)+ 簽章合包(Base64 分段) (優先級: 高)
- 啟動期授權檢核: 在 Startup 初始化並驗簽,授權不通過即中止啟動 (優先級: 高)
- 金鑰管理實務: 使用 OS Key Container/憑證與 CA,避免 XML 明文存放 (優先級: 高)
- 公鑰信任來源: 公鑰應自可信來源(CA/受控通道)獲取與維運 (優先級: 中)
- 例外處理設計: TokenFormat/TokenNotSecure/TokenNotValidate/TokenSiteNotExist (優先級: 中)
- 配置式注入: appsettings.json 提供 TokenData/SiteID/私鑰/公鑰庫 (優先級: 中)
- 多站台公鑰庫: 以字典緩存多站台公鑰,支援跨站驗簽 (優先級: 中)
- 序列化一致性: 序列化與反序列化需一致,確保驗簽資料位元完全相同 (優先級: 中)
- 私鑰外洩風險: 私鑰外流即失去身份不可否認性,必須輪替與撤銷 (優先級: 高)
- 安全與可維運性: 拒絕自創加密法,採用標準演算法與成熟函式庫 (優先級: 高)
- 日誌與監控: 對授權失敗與驗簽錯誤記錄並警示,以利排錯與安全稽核 (優先級: 低)