2012-08-15 21 views
8

Chcę wykorzystać jakąś formę "prostego" szyfrowania, które jest dość bezpieczne, ale ma bardzo niskie tarcie pod względem wpływu na proces rozwoju.ASP.Net MVC i szyfrowanie WebAPI

Załóżmy, że posiadam obie strony konwersacji w kliencie <> sytuacja usług sieciowych. Moja aplikacja to aplikacja Windows phone/win8/silverlight/desktop, a serwer to ASP.Net MVC lub WebAPI.

W moim umyśle, chcę coś tak prostego jak: -

<security encryption="off|sometype|someothertype"> 
    <privatekey>12345MyKey54321</privatekey> 
</security> 

jako pewnego rodzaju parametru konfiguracyjnego na klienta i serwera. Dodatkowo procedura uwierzytelniania zwróci i zapisze pewną formę klucza publicznego.

W ten sposób zostanie włączony "tryb szyfrowania" i wszystkie żądane żądania HTTP zostaną zaszyfrowane & za pomocą dostarczonych klawiszy. Wynik końcowy, polegający na tym, że coś zostanie wciągnięte na maszyny lokalne, proxy lub zdalne, nie będzie w stanie wyświetlić danych bez klucza i metody deszyfrowania. Na serwerze dane są odszyfrowywane za pomocą tego samego klucza przed naciśnięciem akcji kontrolera.

Oprócz wywoływania wywołań HttpRequest/WebClient dotyczących czegoś takiego jak EncryptedHttpRequest i dodawania odpowiedniego haka po stronie MVC/WebAPI, wszystkie inne działania kodu klienta i kontrolera byłyby nieświadome faktu, że dane zostały zaszyfrowane.

Czy brakuje mi czegoś lub może się ustawić, że nie jest to takie proste? O ile szukałem, nic nie oferuje takiego poziomu prostoty, więc myślę, że brakuje mi jakiejś luki w mojej logice?

+0

Ponowne wynalezienie SSL/TLS ?? – Aliostad

+0

Problem polega na tym, jak łatwo człowiek w środkowych atakach używa narzędzi takich jak Skrzypek. – DannyT

Odpowiedz

8

Zrobiłem to z powodzeniem. Nie jest to zbyt trudne i działa dobrze. Używam go do aktywacji licencji na produkt. Najważniejszą rzeczą jest to, że naprawdę kontrolujesz klienta i serwer - nikt nie może wyodrębnić twojego klucza prywatnego z twojego kodu na kliencie.

Krok 1: Utwórz metody działania kontroler MVC, która pobiera żadnych argumentów:

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

Krok 2: W kontrolerze wystarczy użyć HttpRequest.InputStream dostać Ahold bajtów wysłanych od klienta .

var strumień = this.HttpContext.Request.InputStream;

Krok 3: Utwórz strumień kryptograficzny do deserializacji.

Załączam tutaj tworzenie przykładów szyfrowania i odszyfrowywania. SharedSecret to bajt [] o wystarczającej długości (512 bajtów) losowych bajtów - to jest to, co chronisz!

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;   
} 

Krok 4: Użyj CryptoStream inny czytnik strumienia do odszyfrowania.

Używam XmlReader tak, że cały mój istniejący kod serializacji może działać w czystej formie (podczas odczytu/zapisu na dysku lub w bazie danych na serwerze) lub w postaci zaszyfrowanej (podczas przesyłania).

using (var reader = XmlReader.Create(decryptionStream, settings))    { ... } 

Krok 5: Sformułuj bezpieczną odpowiedź w kontrolerze.

Wykonuje to w odwrotnej kolejności z kroków 1-4, aby zaszyfrować obiekt odpowiedzi. Następnie po prostu zapisz zaszyfrowaną odpowiedź do strumienia pamięci i zwróć ją jako wynik pliku. Poniżej pokazałem, jak to zrobić dla mojego obiektu odpowiedzi na licencję.

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;   
} 

Krok 6: Wprowadź odpowiedź na żądanie klienta.

Możesz użyć HttpWebRequest lub klas WebClient do sformułowania żądania. Oto kilka przykładów z kodu, którego używam.

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); 
} 

Podsumowanie i Wskazówki

  • pomocą strumieni we wniosku/odpowiedzi na klienta i serwera do komunikowania danych binarnych oktet-strumieniowych
  • Używaj CryptoStream wraz z algorytmu szyfrowania (rozważyć przy użyciu najsilniejszego możliwego szyfrowania) i dobry klucz prywatny do szyfrowania danych podczas serializacji/deserializacji.
  • Pamiętaj, aby sprawdzić rozmiar i format wszystkich przychodzących danych do klienta i serwera (uniknij przepełnienia bufora i wyrzuć wyjątki wcześniej)
  • Chroń swój prywatny klucz na kliencie za pomocą zaciemniania, jeśli to możliwe (spójrz na oblepiciela DeepSea)
+2

Świetne rozwiązanie! Ale odpowiedź Aliostada jest bardziej praktyczna i prosta :) –

+0

Idealny do wbudowanej maszyny linux do komunikowania bazy danych z tą implementacją. – NTMS

18

Wszystko, czego szukasz, można uzyskać po prostu za pomocą protokołu HTTPS. Po prostu kup certyfikat (lub użyj certyfikatu z podpisem własnym) i masz szyfrowanie.

Nie wynajduj ponownie koła.

+3

Korzystanie z Fiddlera jest łatwe do odszyfrowania komunikacji HTTPS. http://docs.telerik.com/fiddler/Configure-Fiddler/Tasks/DecryptHTTPS –