ASP.Net MVC & WebAPI 加密
我想利用某種形式的“簡單”加密,這種加密相當安全,但在對開發過程的影響方面摩擦非常小。
假設我在客戶端 <> Web 服務情況下擁有對話的雙方。我的應用程序是 windows phone/win8/silverlight/desktop 應用程序,伺服器是 ASP.Net MVC 或 WebAPI。
在我看來,我想要一些簡單的東西: -
<security encryption="off|sometype|someothertype"> <privatekey>12345MyKey54321</privatekey> </security>作為客戶端和伺服器上的某種形式的配置參數。此外,身份驗證常式將返回並儲存某種形式的公鑰。
這樣做將啟用“加密模式”,並使用提供的密鑰以選定的方式對任何 http 請求進行加密和散列。最終結果是在本地、代理或遠端機器上嗅探到的任何東西都無法在沒有密鑰和解密方法的情況下查看數據。在伺服器上,數據在執行控制器操作之前使用相同的密鑰進行解密。
除了將 HttpRequest/WebClient 呼叫換成 EncryptedHttpRequest 之類的呼叫並在 MVC/WebAPI 方面添加適當的鉤子之外,所有其他客戶端程式碼和控制器操作都將不知道數據已加密的事實。
我是否遺漏了什麼或者設置不是這麼簡單?據我搜尋,沒有什麼能提供這種簡單程度的東西,所以我認為我的邏輯中遺漏了一些巨大的缺陷?
我已經成功地做到了。這不是太難並且效果很好。我用它來啟動產品的許可證。最重要的是您真正控制客戶端和伺服器 - 沒有人可以從客戶端上的程式碼中提取您的私鑰。
第 1 步:創建一個不帶參數的 MVC 控制器操作方法:
[HttpPost] public ActionResult Activate() { ... }第 2 步:在控制器中,只需使用 HttpRequest.InputStream 來獲取從客戶端發送的字節。
var 流 = this.HttpContext.Request.InputStream;
第 3 步:創建 CryptoStream 以進行反序列化。
我在這裡包含了創建加密和解密範例。sharedSecret 是一個字節
$$ $$足夠長(512 字節)的隨機字節——這就是你所保護的!
public CryptoStream CreateEncryptionStream(Stream writeStream) { TripleDESCryptoServiceProvider cryptoProvider = new TripleDESCryptoServiceProvider(); PasswordDeriveBytes derivedBytes = new PasswordDeriveBytes(this._sharedSecret, null); CryptoStream cryptoStream = new CryptoStream(writeStream, cryptoProvider.CreateEncryptor(derivedBytes.GetBytes(16), derivedBytes.GetBytes(16)), CryptoStreamMode.Write); return cryptoStream; } public CryptoStream CreateDecryptionStream(Stream readStream) { TripleDESCryptoServiceProvider cryptoProvider = new TripleDESCryptoServiceProvider(); PasswordDeriveBytes derivedBytes = new PasswordDeriveBytes(this._sharedSecret, null); CryptoStream cryptoStream = new CryptoStream(readStream, cryptoProvider.CreateDecryptor(derivedBytes.GetBytes(16), derivedBytes.GetBytes(16)), CryptoStreamMode.Read); return cryptoStream; }第 4 步:使用您的 CryptoStream 另一個流閱讀器進行解密。
我使用 XmlReader 以便我所有現有的序列化程式碼可以明文工作(在讀取/寫入伺服器上的磁碟或數據庫時)或加密(在傳輸時)。
using (var reader = XmlReader.Create(decryptionStream, settings)) { ... }第 5 步:在控制器中製定安全響應。
這與步驟 1-4 相反,以加密您的響應對象。然後,您只需將加密響應寫入記憶體流並將其作為文件結果返回。下面,我展示瞭如何為我的許可證響應對象執行此操作。
var responseBytes = GetLicenseResponseBytes(licenseResponse); return File(responseBytes, "application/octet-stream"); private byte[] GetLicenseResponseBytes(LicenseResponse licenseResponse) { if (licenseResponse != null) { using (MemoryStream memoryStream = new MemoryStream()) { this._licenseResponseSerializer.Write(memoryStream, licenseResponse); return memoryStream.ToArray(); } } return null; }第 6 步:實施您的客戶請求響應。
您可以使用 HttpWebRequest 或 WebClient 類來製定請求。這是我使用的程式碼中的幾個範例。
byte[] postBytes = GetLicenseRequestBytes(licenseRequest); HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(licenseServerUrl); request.Method = "POST"; request.ContentType = "application/octet-stream"; request.Proxy = WebRequest.DefaultWebProxy; using (Stream requestStream = request.GetRequestStream()) { requestStream.Write(postBytes, 0, postBytes.Length); } return request; private LicenseResponse ProcessHttpResponse(HttpWebResponse response) { if ((response.StatusCode == HttpStatusCode.OK) && response.ContentType.Contains("application/octet-stream")) { var stream = response.GetResponseStream(); if (stream != null) { var licenseResponse = this._licenseResponseSerializer.Read(stream); return licenseResponse; } } return new LicenseResponse(LicensingResult.Error); }總結和提示
- 使用客戶端和伺服器上的請求/響應中的流來通信二進制八位字節流數據
- 在序列化/反序列化數據時,使用 CryptoStream 以及加密算法(考慮使用最強的加密可能性)和良好的私鑰來加密數據。
- 確保檢查所有傳入客戶端和伺服器的數據的大小和格式(避免緩衝區溢出和儘早拋出異常)
- 如果可能,使用混淆來保護您客戶端上的私鑰(查看 DeepSea 混淆器)
您所尋找的一切都可以通過簡單地使用 HTTPS 來實現。只需購買證書(或使用自簽名證書),就可以進行加密。
不要重新發明輪子。