目次
はじめに: " >1. シナリオはじめに:
web
サーバーには次の

WebApiで通信暗号化を実現

Mar 12, 2017 pm 04:17 PM

1. シナリオはじめに:

既存のコードの侵入を最小限に抑えて、クライアントとサービスサーバー間のデータ交換を効果的に暗号化する方法

2. 要件分析

web

api

サーバーには次の

インターフェース

があります:

public class ApiTestController : ApiController
{    // GET api/<controller>/5
    public object Get(int id)
    {        return "value" + id;
    }
}
ログイン後にコピー

ApiTestController

暗号化されたリクエストはありません GET / ?id=10

結果を返す

レスポンス "value10"

達成したい効果は次のとおりです:

Get /api/apitest?aWQ9MTA=
response InZhbHVlMTAi (復号化された "value10")

以上

その他

暗号化メソッド

2. 関数分析

既存のコードに変更を加えたくない場合は、ルーターが決定された後にすべての API コントローラーが初期化されることがわかっているため、その前に GET パラメーターと POST パラメーターを設定する必要があります。ルーターの暗号化が必要です

webapiの

ライフサイクル

の図を見てください:

メッセージ処理のためのrouting

ルーティングの前にDelegationgHander層があることが分かります。各メッセージを処理する必要がある リクエストはパラメータの復号化のために処理され、返されたメッセージは暗号化されるため、MessageProcessingHan

dler

    //
    // 摘要:    //     A base type for handlers which only do some small processing of request and/or    //     response messages.
    public abstract class MessageProcessingHandler : DelegatingHandler
    {        //
        // 摘要:        //     Creates an instance of a System.Net.Http.MessageProcessingHandler class.
        protected MessageProcessingHandler();        //
        // 摘要:        //     Creates an instance of a System.Net.Http.MessageProcessingHandler class with        //     a specific inner handler.        //
        // 参数:        //   innerHandler:        //     The inner handler which is responsible for processing the HTTP response messages.
        protected MessageProcessingHandler(HttpMessageHandler innerHandler);        //
        // 摘要:        //     Performs processing on each request sent to the server.        //
        // 参数:        //   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.        //
        // 返回结果:        //     Returns System.Net.Http.HttpRequestMessage.The HTTP request message that was        //     processed.
        protected abstract HttpRequestMessage ProcessRequest(HttpRequestMessage request, CancellationToken cancellationToken);        //
        // 摘要:        //     Perform processing on each response from the server.        //
        // 参数:        //   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.        //
        // 返回结果:        //     Returns System.Net.Http.HttpResponseMessage.The HTTP response message that was        //     processed.
        protected abstract HttpResponseMessage ProcessResponse(HttpResponseMessage response, CancellationToken cancellationToken);        //
        // 摘要:        //     Sends an HTTP request to the inner handler to send to the server as an asynchronous        //     operation.        //
        // 参数:        //   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.        //
        // 返回结果:        //     Returns System.Threading.Tasks.Task`1.The task object representing the asynchronous        //     operation.        //
        // 异常:        //   T:System.ArgumentNullException:        //     The request was null.
        protected internal sealed override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
    }
ログイン後にコピー

MessageProcessingHandler


の3つを目指します。 :

これからは、まず通信暗号化と復号化機能の 2 つのバージョンを実装します。バージョン 1.0 Base64 暗号化とバージョン 1.1 Des 暗号化です

 1     /// <summary> 2     /// 加密解密接口 3     /// </summary> 4     public interface IMessageEnCryption 5     { 6         /// <summary> 7         /// 加密 8         /// </summary> 9         /// <param name="content"></param>10         /// <returns></returns>11         string Encode(string content);12         /// <summary>13         /// 解密14         /// </summary>15         /// <param name="content"></param>16         /// <returns></returns>17         string Decode(string content);18     }
ログイン後にコピー

IMessageEnCryption

バージョン 1.0 Base64 暗号化を書き込みますと復号化

 1     /// <summary> 2     /// 加解密 只做 base64 3     /// </summary> 4     public class MessageEncryptionVersion1_0 : IMessageEnCryption 5     { 6         public string Decode(string content) 7         { 8             return content?.DecryptBase64(); 9         }10 11         public string Encode(string content)12         {13             return content.EncryptBase64();14         }15     }
ログイン後にコピー

MessageEncryptionVersion1_0

暗号化と復号化のバージョン 1.1 の作成

 1     /// <summary> 2     /// 数据加解密 des 3     /// </summary> 4     public class MessageEncryptionVersion1_1 : IMessageEnCryption 5     { 6         public static readonly string KEY = "fHil/4]0"; 7         public string Decode(string content) 8         { 9             return content.DecryptDES(KEY);10         }11 12         public string Encode(string content)13         {14             return content.EncryptDES(KEY);15         }16     }
ログイン後にコピー

MessageEncryptionVersion1 _1


暗号化と復号化のための基本的なカプセル化クラスが添付されています


 1     public static class EncrypExtends 2     { 3  4         //默认密钥向量 5         private static byte[] Keys = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF }; 6         internal static string Key = "*@&$(@#H"; 7  8         //// <summary> 9         /// DES加密字符串10         /// </summary>11         /// <param name="encryptString">待加密的字符串</param>12         /// <param name="encryptKey">加密密钥,要求为8位</param>13         /// <returns>加密成功返回加密后的字符串,失败返回源串</returns>14         public static string EncryptDES(this string encryptString, string encryptKey)15         {16             try17             {18                 byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 8));19                 byte[] rgbIV = Keys;20                 byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString);21                 DESCryptoServiceProvider dCSP = new DESCryptoServiceProvider();22                 MemoryStream mStream = new MemoryStream();23                 CryptoStream cStream = new CryptoStream(mStream, dCSP.CreateEncryptor(rgbKey, rgbIV), CryptoStreamMode.Write);24                 cStream.Write(inputByteArray, 0, inputByteArray.Length);25                 cStream.FlushFinalBlock();26                 return Convert.ToBase64String(mStream.ToArray());27             }28             catch29             {30                 return encryptString;31             }32         }33         //// <summary>34         /// DES解密字符串35         /// </summary>36         /// <param name="decryptString">待解密的字符串</param>37         /// <param name="decryptKey">解密密钥,要求为8位,和加密密钥相同</param>38         /// <returns>解密成功返回解密后的字符串,失败返源串</returns>39         public static string DecryptDES(this string decryptString, string key)40         {41             try42             {43                 byte[] rgbKey = Encoding.UTF8.GetBytes(key.Substring(0, 8));44                 byte[] rgbIV = Keys;45                 byte[] inputByteArray = Convert.FromBase64String(decryptString);46                 DESCryptoServiceProvider DCSP = new DESCryptoServiceProvider();47                 MemoryStream mStream = new MemoryStream();48                 CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateDecryptor(rgbKey, rgbIV), CryptoStreamMode.Write);49                 cStream.Write(inputByteArray, 0, inputByteArray.Length);50                 cStream.FlushFinalBlock();51                 return Encoding.UTF8.GetString(mStream.ToArray());52             }53             catch54             {55                 return decryptString;56             }57         }58         public static string EncryptBase64(this string encryptString)59         {60             return Convert.ToBase64String(Encoding.UTF8.GetBytes(encryptString));61         }62         public static string DecryptBase64(this string encryptString)63         {64             return Encoding.UTF8.GetString(Convert.FromBase64String(encryptString));65         }66         public static string DecodeUrl(this string cryptString)67         {68             return System.Web.HttpUtility.UrlDecode(cryptString);69         }70         public static string EncodeUrl(this string cryptString)71         {72             return System.Web.HttpUtility.UrlEncode(cryptString);73         }74     }
ログイン後にコピー

EncrypExtends

OK! 到此我们前题工作已经完成了80%,开始进行HTTP请求的 消息进和出的加密解密功能的实现.

我们暂时将加密的版本信息定义为 HTTP header头中 以 api_version 的value 来判别分别是用何种方式加密解密

header例:

  api_version: 1.0

  api_version: 1.1

 


 1     /// <summary> 2     ///  API消息请求处理 3     /// </summary> 4     public class JoyMessageHandler : MessageProcessingHandler 5     { 6  7         /// <summary> 8         /// 接收到request时 处理 9         /// </summary>10         /// <param name="request"></param>11         /// <param name="cancellationToken"></param>12         /// <returns></returns>13         protected override HttpRequestMessage ProcessRequest(HttpRequestMessage request, CancellationToken cancellationToken)14         {15             if (request.Content.IsMimeMultipartContent())16                 return request;17             // 获取请求头中 api_version版本号18             var ver = System.Web.HttpContext.Current.Request.Headers.GetValues("api_version")?.FirstOrDefault();19             // 根据api_version版本号获取加密对象, 如果为null 则不需要加密20             var encrypt = MessageEncryptionCreator.GetInstance(ver);21 22             if (encrypt != null)23             {24                 // 读取请求body中的数据25                 string baseContent = request.Content.ReadAsStringAsync().Result;26                 // 获取加密的信息27                 // 兼容 body: 加密数据  和 body: code=加密数据28                 baseContent = baseContent.Match("(code=)*(?<code>[\\S]+)", 2);29                 // URL解码数据30                 baseContent = baseContent.DecodeUrl();31                 // 用加密对象解密数据32                 baseContent = encrypt.Decode(baseContent);33 34                 string baseQuery = string.Empty;35                 if (!request.RequestUri.Query.IsNullOrEmpty())36                 {37                     // 同 body38                     // 读取请求 url query数据39                     baseQuery = request.RequestUri.Query.Substring(1);40                     baseQuery = baseQuery.Match("(code=)*(?<code>[\\S]+)", 2);41                     baseQuery = baseQuery.DecodeUrl();42                     baseQuery = encrypt.Decode(baseQuery);43                 }44                 // 将解密后的 URL 重置URL请求45                 request.RequestUri = new Uri($"{request.RequestUri.AbsoluteUri.Split('?')[0]}?{baseQuery}");46                 // 将解密后的BODY数据 重置47                 request.Content = new StringContent(baseContent);48             }49 50             return request;51         }52 53         /// <summary>54         /// 处理将要向客户端response时55         /// </summary>56         /// <param name="response"></param>57         /// <param name="cancellationToken"></param>58         /// <returns></returns>59         protected override HttpResponseMessage ProcessResponse(HttpResponseMessage response, CancellationToken cancellationToken)60         {61             //var isMediaType = response.Content.Headers.ContentType.MediaType.Equals(mediaTypeName, StringComparison.OrdinalIgnoreCase);62             var ver = System.Web.HttpContext.Current.Request.Headers.GetValues("api_version")?.FirstOrDefault();63             var encrypt = MessageEncryptionCreator.GetInstance(ver);64             if (encrypt != null)65             {66                 if (response.StatusCode == HttpStatusCode.OK)67                 {68                     var result = response.Content.ReadAsStringAsync().Result;69                     // 返回消息 进行加密70                     var encodeResult = encrypt.Encode(result);71                     response.Content = new StringContent(encodeResult);72                 }73             }74 75             return response;76         }77 78     }
ログイン後にコピー

JoyMessageHandler

 

最后在 webapiconfig 中将我们的消息处理添加到容器中

 


 1     public static class WebApiConfig 2     { 3         public static void Register(HttpConfiguration config) 4         { 5             // Web API 配置和服务 6             // 将 Web API 配置为仅使用不记名令牌身份验证。 7             config.SuppressDefaultHostAuthentication(); 8             config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType)); 9 10             // Web API 路由11             config.MapHttpAttributeRoutes();12 13             config.Routes.MapHttpRoute(14                 name: "DefaultApi",15                 routeTemplate: "api/{controller}/{id}",16                 defaults: new { id = RouteParameter.Optional }17             );18 19             // 添加自定义消息处理20             config.MessageHandlers.Add(new JoyMessageHandler());21 22         }23     }
ログイン後にコピー

WebApiConfig

 

编写单元测试:


 1  [TestMethod()] 2         public void GetTest() 3         { 4             var id = 10; 5             var resultSuccess = $"\"value{id}\""; 6             //不加密 7             Trace.WriteLine($"without encryption."); 8             var url = $"api/ApiTest?id={id}"; 9             Trace.WriteLine($"get url : {url}");10             var response = http.GetAsync(url).Result;11             var result = response.Content.ReadAsStringAsync().Result;12             Assert.AreEqual(result, resultSuccess);13             Trace.WriteLine($"result : {result}");14 15             //使用 方案1加密16             Trace.WriteLine($"encryption case one.");17 18             url = $"api/ApiTest?code=" + $"id={id}".EncryptBase64().EncodeUrl();19 20             Trace.WriteLine($"get url : {url}");21 22             http.DefaultRequestHeaders.Clear();23             http.DefaultRequestHeaders.Add("api_version", "1.0");24             response = http.GetAsync(url).Result;25 26             result = response.Content.ReadAsStringAsync().Result;27 28             Trace.WriteLine($"result : {result}");29 30             result = result.DecryptBase64();31 32             Trace.WriteLine($"DecryptBase64 : {result}");33 34             Assert.AreEqual(result, resultSuccess);35 36             //使用 方案2 加密通讯37             Trace.WriteLine($"encryption case one.");38             39             url = $"api/ApiTest?code=" + $"id={id}".EncryptDES(MessageEncryptionVersion1_1.KEY).EncodeUrl();40 41             Trace.WriteLine($"get url : {url}");42 43             http.DefaultRequestHeaders.Clear();44             http.DefaultRequestHeaders.Add("api_version", "1.1");45             response = http.GetAsync(url).Result;46 47             result = response.Content.ReadAsStringAsync().Result;48 49             Trace.WriteLine($"result : {result}");50 51             result = result.DecryptDES(MessageEncryptionVersion1_1.KEY);52 53             Trace.WriteLine($"DecryptBase64 : {result}");54 55             Assert.AreEqual(result, resultSuccess);56         }
ログイン後にコピー

ApiTestControllerTests

 至此为止功能实现完毕..

 四.思想延伸

要想更加安全的方案,可以将给每位用户生成不同的 private key , 利用AES加密解密

 

以上がWebApiで通信暗号化を実現の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

C言語で特殊文字を処理する方法 C言語で特殊文字を処理する方法 Apr 03, 2025 pm 03:18 PM

C言語では、以下などのエスケープシーケンスを通じて特殊文字が処理されます。\ nはラインブレークを表します。 \ tはタブ文字を意味します。 ESACEシーケンスまたは文字定数を使用して、Char C = '\ n'などの特殊文字を表します。バックスラッシュは2回逃げる必要があることに注意してください。さまざまなプラットフォームとコンパイラが異なるエスケープシーケンスを持っている場合があります。ドキュメントを参照してください。

C文字列におけるcharの役割は何ですか C文字列におけるcharの役割は何ですか Apr 03, 2025 pm 03:15 PM

Cでは、文字列でCharタイプが使用されます。1。単一の文字を保存します。 2。配列を使用して文字列を表し、ヌルターミネーターで終了します。 3。文字列操作関数を介して動作します。 4.キーボードから文字列を読み取りまたは出力します。

C言語でさまざまなシンボルを使用する方法 C言語でさまざまなシンボルを使用する方法 Apr 03, 2025 pm 04:48 PM

c言語のシンボルの使用方法は、算術、割り当て、条件、ロジック、ビット演算子などをカバーします。算術演算子は基本的な数学的操作に使用されます。割り当てと追加、下位、乗算、除算の割り当てには、条件操作に使用されます。ポインター、ファイル終了マーカー、および非数値値。

C言語のcharとwchar_tの違い C言語のcharとwchar_tの違い Apr 03, 2025 pm 03:09 PM

C言語では、charとwchar_tの主な違いは文字エンコードです。CharはASCIIを使用するか、ASCIIを拡張し、WCHAR_TはUnicodeを使用します。 Charは1〜2バイトを占め、WCHAR_Tは2〜4バイトを占有します。 charは英語のテキストに適しており、wchar_tは多言語テキストに適しています。 CHARは広くサポートされており、WCHAR_TはコンパイラとオペレーティングシステムがUnicodeをサポートするかどうかに依存します。 CHARの文字範囲は限られており、WCHAR_Tの文字範囲が大きく、特別な機能が算術演算に使用されます。

マルチスレッドと非同期C#の違い マルチスレッドと非同期C#の違い Apr 03, 2025 pm 02:57 PM

マルチスレッドと非同期の違いは、マルチスレッドが複数のスレッドを同時に実行し、現在のスレッドをブロックせずに非同期に操作を実行することです。マルチスレッドは計算集約型タスクに使用されますが、非同期はユーザーインタラクションに使用されます。マルチスレッドの利点は、コンピューティングのパフォーマンスを改善することですが、非同期の利点はUIスレッドをブロックしないことです。マルチスレッドまたは非同期を選択することは、タスクの性質に依存します。計算集約型タスクマルチスレッド、外部リソースと相互作用し、UIの応答性を非同期に使用する必要があるタスクを使用します。

C言語でCharを変換する方法 C言語でCharを変換する方法 Apr 03, 2025 pm 03:21 PM

C言語では、charタイプの変換は、キャスト:キャスト文字を使用することにより、別のタイプに直接変換できます。自動タイプ変換:あるタイプのデータが別のタイプの値に対応できる場合、コンパイラは自動的に変換します。

C言語でchar配列の使用方法 C言語でchar配列の使用方法 Apr 03, 2025 pm 03:24 PM

Char Arrayは文字シーケンスをC言語で保存し、char array_name [size]として宣言されます。アクセス要素はサブスクリプト演算子に渡され、要素は文字列のエンドポイントを表すnullターミネーター「\ 0」で終了します。 C言語は、strlen()、strcpy()、strcat()、strcmp()など、さまざまな文字列操作関数を提供します。

C言語合計の機能は何ですか? C言語合計の機能は何ですか? Apr 03, 2025 pm 02:21 PM

C言語に組み込みの合計機能はないため、自分で書く必要があります。合計は、配列を通過して要素を蓄積することで達成できます。ループバージョン:合計は、ループとアレイの長さを使用して計算されます。ポインターバージョン:ポインターを使用してアレイ要素を指し示し、効率的な合計が自己概要ポインターを通じて達成されます。アレイバージョンを動的に割り当てます:[アレイ]を動的に割り当ててメモリを自分で管理し、メモリの漏れを防ぐために割り当てられたメモリが解放されます。

See all articles