2012-08-15 19 views
8

Quiero utilizar alguna forma de encriptación "simple" que sea razonablemente segura pero de muy baja fricción en términos de impacto en el proceso de desarrollo.Cifrado ASP.Net MVC y WebAPI

Supongamos que tengo ambos lados de la conversación en un cliente <> situación del servicio web. Mi aplicación es una aplicación de Windows Phone/win8/silverlight/desktop y el servidor es ASP.Net MVC o WebAPI.

En mi mente, quiero algo tan simple como: -

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

como algún tipo de parámetro de configuración en el cliente y el servidor. Además, una rutina de autenticación devolverá y almacenará alguna forma de clave pública.

Haciendo esto habilitará el 'modo de encriptación' y dará como resultado que cualquier solicitud http sea encriptada & hash de la manera seleccionada usando las claves provistas. El resultado final es que cualquier elemento que se detecte en las máquinas locales, proxy o remotas no podrá ver los datos sin la clave y el método de descifrado. En el servidor, los datos se descifran usando la misma clave antes de presionar las acciones del controlador.

Además de intercambiar llamadas HttpRequest/WebClient para algo como EncryptedHttpRequest y agregar el enlace apropiado en el lado MVC/WebAPI, el resto del código de cliente y las acciones del controlador ignorarían el hecho de que los datos fueran encriptados.

¿Me falta algo o podría configurar no ser así de simple? Por lo que he buscado, no hay nada que ofrezca este nivel de simplicidad, así que me imagino que me estoy perdiendo un gran defecto en mi lógica.

+0

Reinventando SSL/TLS ?? – Aliostad

+0

El problema es qué fácil es que los ataques de hombre en el medio usen herramientas como Fiddler. – DannyT

Respuesta

8

He hecho esto con éxito. No es demasiado difícil y funciona bien. Lo uso para activar una licencia para un producto. Lo más importante es que realmente controle el cliente y el servidor; nadie puede extraer su clave privada de su código en el cliente.

Paso 1: Crear un método de acción del controlador MVC que no tiene argumentos:

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

Paso 2: En el controlador sólo tiene que utilizar el HttpRequest.InputStream a ponerme en contacto con los bytes enviados desde el cliente .

var stream = this.HttpContext.Request.InputStream;

Paso 3: Cree un CryptoStream para deserializar.

He incluido la creación de ejemplos de cifrado y descifrado aquí. SharedSecret es un byte [] de longitud suficiente (512 bytes) de bytes aleatorios. ¡Esto es lo que protege!

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

Paso 4: Utilice su CryptoStream otro lector corriente para descifrar.

Utilizo un XmlReader para que todo mi código de serialización existente pueda funcionar en claro (al leer/escribir en el disco o base de datos en el servidor) o encriptado (cuando se transmite).

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

Paso 5: formular una respuesta segura en su controlador.

Esto está haciendo lo contrario de los pasos 1-4 para encriptar su objeto de respuesta. Luego, simplemente escribe tu respuesta encriptada a una secuencia de memoria y la devuelve como un resultado de archivo. A continuación, he mostrado cómo hago esto para mi objeto de respuesta de licencia.

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

Paso 6: Poner en práctica su respuesta la petición del cliente.

Puede utilizar las clases HttpWebRequest o WebClient para formular la solicitud. Aquí hay un par de ejemplos del código que uso.

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

Resumen y Consejos

  • Utilice las corrientes en la solicitud/respuesta en el cliente y el servidor se comuniquen los datos octava-binarios
  • Uso CryptoStream junto con un algoritmo de cifrado (consideran usando la posibilidad de encriptación más fuerte) y una buena clave privada para encriptar datos cuando los serializa/deserializa.
  • Asegúrese de verificar el tamaño y formato a todos los datos entrantes con el cliente y el servidor (evitar desbordamientos de búfer y lanzar excepciones temprana)
  • proteger su clave privada en el cliente utilizando la ofuscación, si es posible (echar un vistazo a la obfustactor de alta mar)
+2

¡Gran solución! Pero la respuesta de Aliostad es más práctica y directa :) –

+0

Perfecto para la máquina embebida de Linux para comunicar la base de datos con esta implementación. – NTMS

18

Todo lo que está buscando se puede lograr simplemente usando HTTPS. Simplemente compre un certificado (o use un certificado autofirmado) y allí está su encriptación.

No reinventar la rueda.

+3

Usando Fiddler es fácil descifrar la comunicación HTTPS. http://docs.telerik.com/fiddler/Configure-Fiddler/Tasks/DecryptHTTPS –