我已经成功地做到了。这不是太难并且效果很好。我用它来激活产品的许可证。最重要的是您真正控制客户端和服务器 - 没有人可以从客户端上的代码中提取您的私钥。
第 1 步:创建一个不带参数的 MVC 控制器操作方法:
[HttpPost] public ActionResult Activate() { ... }
第 2 步:在控制器中,只需使用 HttpRequest.InputStream 来获取从客户端发送的字节。
var 流 = this.HttpContext.Request.InputStream;
第 3 步:创建 CryptoStream 以进行反序列化。
我在这里包含了创建加密和解密示例。sharedSecret 是一个足够长(512 字节)的随机字节的 byte[] - 这就是您要保护的!
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 混淆器)