zoukankan      html  css  js  c++  java
  • Self Host WebApi服务传输层SSL加密(服务器端+客户端调用)

     

    接上篇《WebApi服务URI加密及验证的两种方式》,在实际开发中,仅对URI进行加密是不够的,在传输层采用SSL加密也是必须的。

    如果服务寄宿于IIS,那对传输层加密非常简单仅需要配置一下项目属性开启SSL即可,所用的证书也是IIS帮你搞定(默认443端口证书),基本就是傻瓜式配置后即可强制使用HTTPS访问资源。

    而在Self Host WebApi服务中使用传输层SSL加密,则需要自己手动绑定服务器端的证书,并且在服务器端对客户端Request验证其是否为HTTPS访问方式;在客户端也需要对原有(上一篇)代码做一些小小的补充。

    服务端:

    服务端的工作分为服务器证书绑定,以及WebApi自宿主代码修改。

    1:服务器证书绑定

        关于如何在服务器端绑定一个自签名的证书,网上有很多资料,这里只是简要记录一下要点。因为认证机构颁发的证书都需要钱,开发测试过程中不需要购买证书,只需要在测试端口绑定一个自签名证书即可。

    step 1: 找一个可用的证书指纹

        我是在开发环境下的IIS(服务器证书)中找的一个已安装的证书,即IIS Express Development Certificate。找到详细信息中的指纹(一串16进制加密数字),复制备用;

    step 2:拿到项目的UUID,我就用的sln文件中该项目的UUID;

    step 3:以管理员权限运行cmd,为指定端口绑定一个自签名的证书

        netsh命令不再详述,只给出这里需要用到得3个命令:

               1)端口7777绑定证书:netsh http add sslcert ipport=0.0.0.0:7777 certhash=8239ff15609faaa25f55d07931e78bee96bbXXXX appid={FAE04EC0-301F-11D3-BF4B-00C04F79EFBC},运行后如果绑定成功,将提示“成功添加SSL证书”;

          其中,certhash即step1复制的指纹,appid即step2的uuid;  

        2)端口7777证书删除:netsh http delete sslcert ipport=0.0.0.0:7777,运行成功后如果成功删除该端口上绑定的证书,则将提示“成功删除SSL证书”;

        3)查看SSL证书:netsh http show sslcert,执行后将列出机器上所有端口绑定的证书,找到端口7777的证书,将能看到证书哈希及应用程序ID信息,与之前添加的一致。

    2:Web API 自宿主服务器端代码修改

    服务器端的代码修改包括:1)uri的scheme验证,确保资源访问必须采用ssl加密;2)自宿主服务器启动监听uri改为https字头。

    scheme验证仍然采用与上篇文章相同的方法,即实现一个新的HttpMessageHandler,并将其注入到消息处理管道中:

    技术分享
     1     public class HttpsGuard : DelegatingHandler
     2     {
     3         protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
     4         {
     5             if (!request.RequestUri.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.CurrentCultureIgnoreCase))
     6             {
     7                 var response = new HttpResponseMessage(HttpStatusCode.BadRequest)
     8                 {
     9                     Content = new StringContent("Https is required for security reason")
    10                 };
    11                 return Task.FromResult(response);
    12             }
    13             return base.SendAsync(request, cancellationToken);
    14         }
    15     }
    View Code

    修改Startup的Configuration,将上面的HttpMessageHandler注入:

    技术分享
     1         public void Configuration(IAppBuilder app)
     2         {
     3             // Configure Web API for self-host. 
     4             var config = new HttpConfiguration();
     5             config.Routes.MapHttpRoute(
     6                 name: "DefaultApi",
     7                 routeTemplate: "api/{controller}/{action}/{param}",
     8                 defaults: new { id = RouteParameter.Optional }
     9             );
    10             //注入response handler
    11             config.MessageHandlers.Add(new ResponseHandler());
    12             //注入httpmessagehandler用于验证request是否均采用SSL加密传输
    13             config.MessageHandlers.Add(new HttpsGuard());
    14             //允许WebApi的跨域访问 - 测试条件下允许所有域的跨域访问
    15             var cors = new EnableCorsAttribute("*", "*", "*");
    16             config.EnableCors(cors);
    17 
    18             app.UseWebApi(config);
    19         }
    View Code

    服务器启动则改为如下:

    技术分享
    1 var urlBase = new UriBuilder("HTTPS", ip, 7777).Uri;
    2 
    3 var server = WebApp.Start<Startup>(url: urlBase.AbsoluteUri);
    View Code

    以上三部分修改完成后,对web api服务端代码的修改完毕,可以启动服务,正常开始监听本地7777端口。此时如果在浏览器中访问,则会提示证书失效,是否继续访问等等大家熟悉的场景。

    客户端:

    如何远程调用SSL通信加密后的Web Api资源

    以上步骤完成后,直接在客户端经由上一篇所重写的HttpClient访问加密后的资源,一般会报一个“基础连接已经关闭: 未能为 SSL/TLS 安全通道建立信任关系。”这样的错(我的VS是中文版的),产生这个错误的原因是因为服务器上7777端口绑定的证书错了(因为我们搞了个自签名的测试证书),或者证书过期了啊什么的,也都会出现这个问题,总之就是证书不受信任了。绑定一个有效的受信证书就不会有这个问题了(没试过)。这里为了方便开发及测试,需要对客户端代码做如下修改,目的就是不验证证书的有效性,即接受所有证书的认证。

    新增如下方法:

    技术分享
    private static bool AcceptAllCertifications(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certification, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
    {
            return true;
    }
    View Code

    在base.SendAsync(request, cancellationToken)之前,调用下这个方法:

    ServicePointManager.ServerCertificateValidationCallback += RemoteCertificateValidate;

    即可。

    或者不需要新增这个方法,直接在base.SendAsync(request, cancellationToken)之前新增一句:ServicePointManager.ServerCertificateValidationCallback += delegate { return true; };即可,简单粗暴,信任所有证书。

    以上步骤完成之后,即可通过

    var myResponse = myClient.GetAsync("https://192.168.1.166:7777/api/test/GetUser/id=123123&name=jiakai").Result;

    类似的URI访问服务器资源。经测试,SSL加密后的客户端-服务器通信消息,在fiddler中无法抓取到包(网上有fiddler抓取https通信包的各种方法,不较真了)。

    经过上篇与本篇的通信加密方法,即可建立一套基本的web api资源安全通信方式,可满足通常情况下的通信安全需求。

  • 相关阅读:
    windows 按时自动化任务
    Linux libusb 安装及简单使用
    Linux 交换eth0和eth1
    I.MX6 GPS JNI HAL register init hacking
    I.MX6 Android mmm convenient to use
    I.MX6 GPS Android HAL Framework 调试
    Android GPS GPSBasics project hacking
    Python windows serial
    【JAVA】别特注意,POI中getLastRowNum() 和getLastCellNum()的区别
    freemarker跳出循环
  • 原文地址:https://www.cnblogs.com/scoluo/p/10191090.html
Copyright © 2011-2022 走看看