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资源安全通信方式,可满足通常情况下的通信安全需求。

  • 相关阅读:
    strrchr
    tcpdump的源码分析
    C语言中字符串
    setsockopt、getsockopt详细介绍(转)
    linux下IPC通信
    setsockopt()用法(参数详细说明)(转)
    判断一个数是否为2的n次幂
    mysql 5.7.14 安装配置方法图文教程(转)
    JAVA中的protected(详解),以及和clone()方法有关的一些问题
    ASP.NET MVC 在控制器中接收视图表单POST过来的数据方法
  • 原文地址:https://www.cnblogs.com/scoluo/p/10191090.html
Copyright © 2011-2022 走看看