2012-08-15 26 views
8

私は、開発プロセスへの影響の点で、合理的に安全ですが非常に低い「シンプルな」暗号化を利用したいと考えています。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側で適切なフックを追加する以外は、他のすべてのクライアントコードとコントローラのアクションは、データが暗号化されていることを知らないでしょう。

私は何かを見逃していますか、これは簡単ではありませんか?私が検索した限りでは、このレベルのシンプルさを提供するものは何もないので、私は自分のロジックに欠けている欠点を逃していると思いますか?

+0

SSL/TLSを再発明する?? – Aliostad

+0

問題は、中間攻撃でフィドラーのようなツールを使用している人がいかに簡単かです。 – DannyT

答えて

8

私はこれを成功させました。あまりにも難しくなく、うまくいきます。私はそれを使って製品のライセンスを有効にします。最も重要なことは、あなたが本当にクライアントとサーバーを制御できることです。だれもクライアントのコードから秘密鍵を抽出することはできません。

ステップ1:

[HttpPost]  public ActionResult Activate()  { ... } 

ステップ2:コントローラにだけ、クライアントから送信されたバイトのネタを取得するためにHttpRequest.InputStreamを使用する引数をとらないMVCコントローラのアクションメソッドを作成します。 。

var stream = 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社obfustactorを見てみましょう難読化を使用してクライアント上の秘密鍵を保護
  • (バッファオーバーランを回避し、早期に例外をスロー)のサイズをチェックして、クライアントとサーバへのすべての着信データをフォーマットすることを確認します)
+2

素晴らしいソリューション!しかし、Aliostadの答えは、より実用的で簡単です:) –

+0

組み込みLinuxマシンには、この実装でデータベースを通信するのに最適です。 – NTMS

18

あなたが探しているのは、単にHTTPSを使用するだけです。証明書を購入するか(または自己署名証明書を使用する)、あなたの暗号化があります。

ホイールを再発明しないでください。

+3

Fiddlerを使用すると、HTTPS通信を簡単に復号化できます。 http://docs.telerik.com/fiddler/Configure-Fiddler/Tasks/DecryptHTTPS –