WEBAPI enables data exchange encryption between client and server

Source: Internet
Author: User
Tags assert decrypt
This article mainly introduced the WEBAPI realizes the communication encryption method, has the very good reference value, below follows the small compilation together to look down





I. Scenario Description:



Title How effective, the smallest amount of existing code intrusion to achieve the client-server data exchange encryption?



Two. Explore:



1. Demand Analysis



The WEBAPI server has the following interfaces:

public class ApiTestController: ApiController
{
 // GET api / <controller> / 5
 public object Get (int id)
 {
  return "value" + id;
 }
}

ApiTestController
No encryption request

GET / api / apitest? Id = 10

Return result

response "value10"

The effect we want to achieve is:

Get / api / apitest? AWQ9MTA =
response InZhbHVlMTAi (decrypted "value10")

Or more encryption

2. Functional analysis

To make no changes to the existing code, we all know that all api controllers are initialized after the router is determined, so we should encrypt the GET parameters and POST parameters before the router.

Look at the webapi life cycle:

We see that there is a DelegationgHander layer for message processing before routing.

Because we want to decrypt the parameters for each request and encrypt the returned message, we aim at the MessageProcessingHandler

 //
 // Summary:
 // A base type for handlers which only do some small processing of request and / or
 // response messages.
 public abstract class MessageProcessingHandler: DelegatingHandler
 {
  //
  // Summary:
  // Creates an instance of a System.Net.Http.MessageProcessingHandler class.
  protected MessageProcessingHandler ();
  //
  // Summary:
  // Creates an instance of a System.Net.Http.MessageProcessingHandler class with
  // a specific inner handler.
  //
  // Parameters:
  // innerHandler:
  // The inner handler which is responsible for processing the HTTP response messages.
  protected MessageProcessingHandler (HttpMessageHandler innerHandler);

  //
  // Summary:
  // Performs processing on each request sent to the server.
  //
  // Parameters:
  // request:
  // The HTTP request message to process.
  //
  // cancellationToken:
  // A cancellation token that can be used by other objects or threads to receive
  // notice of cancellation.
  //
  // Return result:
  // Returns System.Net.Http.HttpRequestMessage.The HTTP request message that was
  // processed.
  protected abstract HttpRequestMessage ProcessRequest (HttpRequestMessage request, CancellationToken cancellationToken);
  //
  // Summary:
  // Perform processing on each response from the server.
  //
  // Parameters:
  // response:
  // The HTTP response message to process.
  //
  // cancellationToken:
  // A cancellation token that can be used by other objects or threads to receive
  // notice of cancellation.
  //
  // Return result:
  // Returns System.Net.Http.HttpResponseMessage.The HTTP response message that was
  // processed.
  protected abstract HttpResponseMessage ProcessResponse (HttpResponseMessage response, CancellationToken cancellationToken);
  //
  // Summary:
  // Sends an HTTP request to the inner handler to send to the server as an asynchronous
  // operation.
  //
  // Parameters:
  // request:
  // The HTTP request message to send to the server.
  //
  // cancellationToken:
  // A cancellation token that can be used by other objects or threads to receive
  // notice of cancellation.
  //
  // Return result:
  // Returns System.Threading.Tasks.Task`1.The task object representing the asynchronous
  // operation.
  //
  // exception:
  // T: System.ArgumentNullException:
  // The request was null.
  protected internal sealed override Task <HttpResponseMessage> SendAsync (HttpRequestMessage request, CancellationToken cancellationToken);
 }

MessageProcessingHandler
Three. Practice:

Now we will implement two versions of communication encryption and decryption functions in the future, set to version 1.0 base64 encryption, version 1.1 Des encryption

/// <summary>
 /// Encryption and decryption interface
 /// </ summary>
 public interface IMessageEnCryption
 {
  /// <summary>
  /// encryption
  /// </ summary>
  /// <param name = "content"> </ param>
  /// <returns> </ returns>
  string Encode (string content);
  /// <summary>
  /// decrypt
  /// </ summary>
  /// <param name = "content"> </ param>
  /// <returns> </ returns>
  string Decode (string content);
 }

IMessageEnCryption
Write version 1.0 base64 encryption and decryption

/// <summary>
 /// encryption and decryption only base64
 /// </ summary>
 public class MessageEncryptionVersion1_0: IMessageEnCryption
 {
  public string Decode (string content)
  {
   return content? .DecryptBase64 ();
  }

  public string Encode (string content)
  {
   return content.EncryptBase64 ();
  }
 }

MessageEncryptionVersion1_0
Write version 1.1 des encryption and decryption

/// <summary>
 /// Data encryption and decryption des
 /// </ summary>
 public class MessageEncryptionVersion1_1: IMessageEnCryption
 {
  public static readonly string KEY = "fHil / 4] 0";
  public string Decode (string content)
  {
   return content.DecryptDES (KEY);
  }
  public string Encode (string content)
  {
   return content.EncryptDES (KEY);
  }
 }

MessageEncryptionVersion1_1
Attach a basic encapsulation class for encryption and decryption

public static class EncrypExtends
 {
  // default key vector
  private static byte [] Keys = {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF};
  internal static string Key = "* @ & $ (@ # H";

  //// <summary>
  /// DES encrypted string
  /// </ summary>
  /// <param name = "encryptString"> string to be encrypted </ param>
  /// <param name = "encryptKey"> Encryption key, requires 8 bits </ param>
  /// <returns> The encrypted string is returned after the encryption is successful, and the source string is returned if the encryption fails </ returns>
  public static string EncryptDES (this string encryptString, string encryptKey)
  {
   try
   {
    byte [] rgbKey = Encoding.UTF8.GetBytes (encryptKey.Substring (0, 8));
    byte [] rgbIV = Keys;
    byte [] inputByteArray = Encoding.UTF8.GetBytes (encryptString);
    DESCryptoServiceProvider dCSP = new DESCryptoServiceProvider ();
    MemoryStream mStream = new MemoryStream ();
    CryptoStream cStream = new CryptoStream (mStream, dCSP.CreateEncryptor (rgbKey, rgbIV), CryptoStreamMode.Write);
    cStream.Write (inputByteArray, 0, inputByteArray.Length);
    cStream.FlushFinalBlock ();
    return Convert.ToBase64String (mStream.ToArray ());
   }
   catch
   {
    return encryptString;
   }
  }
  //// <summary>
  /// DES decryption string
  /// </ summary>
  /// <param name = "decryptString"> string to be decrypted </ param>
  /// <param name = "decryptKey"> Decryption key, requires 8 bits, same as encryption key </ param>
  /// <returns> Successful decryption returns the decrypted string, failure to return to the source string </ returns>
  public static string DecryptDES (this string decryptString, string key)
  {
   try
   {
    byte [] rgbKey = Encoding.UTF8.GetBytes (key.Substring (0, 8));
    byte [] rgbIV = Keys;
    byte [] inputByteArray = Convert.FromBase64String (decryptString);
    DESCryptoServiceProvider DCSP = new DESCryptoServiceProvider ();
    MemoryStream mStream = new MemoryStream ();
    CryptoStream cStream = new CryptoStream (mStream, DCSP.CreateDecryptor (rgbKey, rgbIV), CryptoStreamMode.Write);
    cStream.Write (inputByteArray, 0, inputByteArray.Length);
    cStream.FlushFinalBlock ();
    return Encoding.UTF8.GetString (mStream.ToArray ());
   }
   catch
   {
    return decryptString;
   }
  }
  public static string EncryptBase64 (this string encryptString)
  {
   return Convert.ToBase64String (Encoding.UTF8.GetBytes (encryptString));
  }
  public static string DecryptBase64 (this string encryptString)
  {
   return Encoding.UTF8.GetString (Convert.FromBase64String (encryptString));
  }
  public static string DecodeUrl (this string cryptString)
  {
   return System.Web.HttpUtility.UrlDecode (cryptString);
  }
  public static string EncodeUrl (this string cryptString)
  {
   return System.Web.HttpUtility.UrlEncode (cryptString);
  }
 }

EncrypExtends
OK! At this point, 80% of our previous work has been completed, and the implementation of the encryption and decryption function of the HTTP request message in and out has begun.

We temporarily define the encrypted version information as the api_version value in the HTTP header to determine which method is used for encryption and decryption.

header example:

Api_version: 1.0

Api_version: 1.1

/// <summary>
 /// API message request processing
 /// </ summary>
 public class JoyMessageHandler: MessageProcessingHandler
 {
  /// <summary>
  /// Processed when a request is received
  /// </ summary>
  /// <param name = "request"> </ param>
  /// <param name = "cancellationToken"> </ param>
  /// <returns> </ returns>
  protected override HttpRequestMessage ProcessRequest (HttpRequestMessage request, CancellationToken cancellationToken)
  {
   if (request.Content.IsMimeMultipartContent ())
    return request;
   // Get the api_version version number in the request header
   var ver = System.Web.HttpContext.Current.Request.Headers.GetValues ("api_version") ?. FirstOrDefault ();
   // Get the encrypted object according to the api_version version number, if it is null, no encryption is required
   var encrypt = MessageEncryptionCreator.GetInstance (ver);
   if (encrypt! = null)
   {
    // read the data in the request body
    string baseContent = request.Content.ReadAsStringAsync (). Result;
    // Get encrypted information
    // compatible with body: encrypted data and body: code = encrypted data
    baseContent = baseContent.Match ("(code =) * (? <code> [\\ S] +)", 2);
    // URL decoded data
    baseContent = baseContent.DecodeUrl ();
    // Decrypt data with encrypted object
    baseContent = encrypt.Decode (baseContent);
    string baseQuery = string.Empty;
    if (! request.RequestUri.Query.IsNullOrEmpty ())
    {
     // same body
     // read request url query data
     baseQuery = request.RequestUri.Query.Substring (1);
     baseQuery = baseQuery.Match ("(code =) * (? <code> [\\ S] +)", 2);
     baseQuery = baseQuery.DecodeUrl ();
     baseQuery = encrypt.Decode (baseQuery);
    }
    // Reset the decrypted URL to a URL request
    request.RequestUri = new Uri ($ "{request.RequestUri.AbsoluteUri.Split ('?') [0]}? {baseQuery}");
    // Reset the decrypted BODY data
    request.Content = new StringContent (baseContent);
   }
   return request;
  }
  /// <summary>
  /// When processing the response to the client
  /// </ summary>
  /// <param name = "response"> </ param>
  /// <param name = "cancellationToken"> </ param>
  /// <returns> </ returns>
  protected override HttpResponseMessage ProcessResponse (HttpResponseMessage response, CancellationToken cancellationToken)
  {
   // var isMediaType = response.Content.Headers.ContentType.MediaType.Equals (mediaTypeName, StringComparison.OrdinalIgnoreCase);
   var ver = System.Web.HttpContext.Current.Request.Headers.GetValues ("api_version") ?. FirstOrDefault ();
   var encrypt = MessageEncryptionCreator.GetInstance (ver);
   if (encrypt! = null)
   {
    if (response.StatusCode == HttpStatusCode.OK)
    {
     var result = response.Content.ReadAsStringAsync (). Result;
     // return message for encryption
     var encodeResult = encrypt.Encode (result);
     response.Content = new StringContent (encodeResult);
    }
   }
   return response;
  }
 }

JoyMessageHandler
Finally add our message processing to the container in webapiconfig

public static class WebApiConfig
 {
  public static void Register (HttpConfiguration config)
  {
   // Web API configuration and services
   // Configure Web API to use bearer token authentication only.
   config.SuppressDefaultHostAuthentication ();
   config.Filters.Add (new HostAuthenticationFilter (OAuthDefaults.AuthenticationType));
   // Web API routing
   config.MapHttpAttributeRoutes ();
   config.Routes.MapHttpRoute (
    name: "DefaultApi",
    routeTemplate: "api / {controller} / {id}",
    defaults: new {id = RouteParameter.Optional}
   );
   // Add custom message processing
   config.MessageHandlers.Add (new JoyMessageHandler ());
  }
 }

WebApiConfig
Writing unit tests:

[TestMethod ()]
  public void GetTest ()
  {
   var id = 10;
   var resultSuccess = $ "\" value {id} \ "";
   // not encrypted
   Trace.WriteLine ($ "without encryption.");
   var url = $ "api / ApiTest? id = {id}";
   Trace.WriteLine ($ "get url: {url}");
   var response = http.GetAsync (url) .Result;
   var result = response.Content.ReadAsStringAsync (). Result;
   Assert.AreEqual (result, resultSuccess);
   Trace.WriteLine ($ "result: {result}");
   // Use scheme 1 encryption
   Trace.WriteLine ($ "encryption case one.");
   url = $ "api / ApiTest? code =" + $ "id = {id}". EncryptBase64 (). EncodeUrl ();
   Trace.WriteLine ($ "get url: {url}");
   http.DefaultRequestHeaders.Clear ();
   http.DefaultRequestHeaders.Add ("api_version", "1.0");
   response = http.GetAsync (url) .Result;
   result = response.Content.ReadAsStringAsync (). Result;
   Trace.WriteLine ($ "result: {result}");
   result = result.DecryptBase64 ();
   Trace.WriteLine ($ "DecryptBase64: {result}");
   Assert.AreEqual (result, resultSuccess);
   // Use scheme 2 encrypted communication
   Trace.WriteLine ($ "encryption case one.");
   url = $ "api / ApiTest? code =" + $ "id = {id}". EncryptDES (MessageEncryptionVersion1_1.KEY) .EncodeUrl ();
   Trace.WriteLine ($ "get url: {url}");
   http.DefaultRequestHeaders.Clear ();
   http.DefaultRequestHeaders.Add ("api_version", "1.1");
   response = http.GetAsync (url) .Result;
   result = response.Content.ReadAsStringAsync (). Result;
   Trace.WriteLine ($ "result: {result}");
   result = result.DecryptDES (MessageEncryptionVersion1_1.KEY);
   Trace.WriteLine ($ "DecryptBase64: {result}");
   Assert.AreEqual (result, resultSuccess);
  }

ApiTestControllerTests
So far the function is complete ..

4. Thought extension

For a more secure solution, you can generate a different private key for each user and use AES encryption and decryption

【related suggestion】

1. ASP.NET Free Video Tutorial

2. Geek Academy ASP.NET Video Tutorial

3.ASP.NET Tutorial

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.