首页 > 其他分享 >聊一聊HTTPS双向认证的简单应用

聊一聊HTTPS双向认证的简单应用

时间:2023-02-15 23:33:35浏览次数:45  
标签:key certificate 证书 server ssl 聊一聊 client HTTPS 认证

目录

背景

在三方接口对接中,偶尔会遇到需要传递证书的情况,这种方式其实是在SSL握手过程中会同时验证客户端和服务器的身份,这就是我们常说的 双向认证

双向认证需要服务器和客户端提供身份认证,只能是服务器允许的客户方能访问,安全性相对于要高一些。

下面老黄用几个小例子来演示一下双向认证的简单应用。

准备工作

由于离不开证书,所以我们需要提前生成好几个证书,这里用 OpenSSL 来生成一个自签名的。

2 个根证书,1 个服务端证书,2个不是同一个根证书下面的客户端证书

# 根证书
openssl genrsa -out ca.key 4096
openssl req -new -key ca.key -out ca.csr -days 365
openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt -days 365

# 服务端证书
openssl genrsa -out server.key 4096
openssl req -new -key server.key -out server.csr -days 365
openssl x509 -req -in server.csr -out server.crt -CA ca.crt  -CAkey ca.key  -CAcreateserial -days 365
openssl pkcs12 -export -in server.crt -inkey server.key -out server.p12

# 客户端证书
openssl genrsa -out client.key 4096
openssl req -new -key client.key -out client.csr -days 365
openssl x509 -req -in client.csr -out client.crt -CA ca.crt  -CAkey ca.key  -CAcreateserial -days 365
openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12

最后会有下面几个文件要在后面的演示中用到: ca.crtserver.p12server.crtserver.keyclient.p12client2.p12

下面先来看看 ASP.NET Core 直接对外的情况,也就是不依赖 nginx 或 IIS 的情况。

ASP.NET Core

基于 minimal api 来演示,主要是在 ConfigureKestrel 做处理。

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.ConfigureKestrel(x => 
{
    x.Listen(IPAddress.Any, 443, listenOptions =>
    {
        var serverCertificate = new X509Certificate2("server.p12", "abc123");
        var httpsConnectionAdapterOptions = new HttpsConnectionAdapterOptions()
        {
            // must provide a valid certificate for authentication
            ClientCertificateMode = ClientCertificateMode.RequireCertificate,
            SslProtocols = System.Security.Authentication.SslProtocols.Tls12,
            
            ClientCertificateValidation = (cer, chain, error) =>
            {
                // valid the client certificate by you way.
                return CusSSLLib.CaHelper.Valid(cer, chain, error);
            },
            ServerCertificate = serverCertificate
        };
        listenOptions.UseHttps(httpsConnectionAdapterOptions);
    });
});

这里最核心的是 HttpsConnectionAdapterOptions

ServerCertificate 设置成我们上面生成的服务端证书。

ClientCertificateMode 设置成 RequireCertificate,表示客户端在调用的时候必须要传递证书。

ClientCertificateValidation 就是验证客户端证书的逻辑,这里可以自定义,示例里面的验证逻辑主要针对不被信任的根证书做了验证。

首先是从资源文件读取了根证书,然后再去判断客户端证书是否匹配。

internal static string CA_DATA = System.Text.Encoding.UTF8.GetString(CAResource.ca).Replace("-----BEGIN CERTIFICATE-----", "")
             .Replace("-----END CERTIFICATE-----", "")
             .Replace("\r", "")
             .Replace("\n", "");

public static bool Valid(X509Certificate2 certificate, X509Chain chain, SslPolicyErrors policy)
{
    // the root certificate
    var validRootCertificates = new[]
    {
         Convert.FromBase64String(CA_DATA),
    };

    foreach (var element in chain.ChainElements)
    {
        foreach (var status in element.ChainElementStatus)
        {
            // untrusted root certificate
            if (status.Status == X509ChainStatusFlags.UntrustedRoot)
            {
                if (validRootCertificates.Any(x => x.SequenceEqual(element.Certificate.RawData)))
                {
                    continue;
                }
            }

            return false;
        }
    }

    return true;
}

到这里的话,服务端已经可以了。

这个时候从浏览器访问,大概会看到这个提示。

下面写个控制台用 HttpClient 来访问看看。

void DoOk()
{
    var handler = new HttpClientHandler();
    handler.ClientCertificateOptions = ClientCertificateOption.Manual;
    handler.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls | SslProtocols.None | SslProtocols.Tls11;
    try
    {
        // add client certificate
        var crt = new X509Certificate2(Path.Combine(Directory.GetCurrentDirectory(), "client.p12"), "123456");
        handler.ClientCertificates.Add(crt);
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
    }

    handler.ServerCertificateCustomValidationCallback = (message, cer, chain, errors) =>
    {
        // valid server certificate
        return CusSSLLib.CaHelper.Valid(cer, chain, errors);
    };

    var client = new HttpClient(handler);
    var url = "https://localhost/WeatherForecast";
    var response = client.GetAsync(url).Result;
    Console.WriteLine(response.IsSuccessStatusCode);
    var result = response.Content.ReadAsStringAsync().Result;
    Console.WriteLine(result);
}

这里要注意,由于服务端用的证书也是自己签名的,所以这里的验证也要放开,想省事的话,可以直接 return true;,不过并不建议这样操作。

下面是运行的结果,是可以正常访问并返回结果的。

我们再换一张不是同一个根证书的客户端证书。

不出意外的不能正常访问。

不过上面这种情况在实际应用的时候会偏少一点,大部分还是会挂在反向代理或云负载均衡上面的。

下面先来看看 nginx 的吧。

nginx 反向代理

webapi 这一块,创建一个项目,有一个可以访问的接口即可,不用添加其他东西,因为证书这一块的内容都是在 nginx 那一层做了,webapi做原来该做的事情即可。

下面是 nginx 的配置文件

server {
        listen       443 ssl;
        server_name  localhost;

        # server certificate
        ssl_certificate  /etc/nginx/ssl/server.crt;
        ssl_certificate_key /etc/nginx/ssl/server.key;

        # root certificate
        ssl_client_certificate /etc/nginx/ssl/ca.crt;
        # open client certificate verify
        ssl_verify_client on;
        ssl_session_timeout  5m;            

        location / {
            proxy_pass http://webapi;
            index  index.html;
        }
    }

重点关注 ssl_verify_clientssl_client_certificate

一个是配置开启客户端证书的认证,一个是验证的客户端证书的关键。

这里的 ssl_client_certificate 用了根证书,为的是可以验证多个客户端证书,当然这里也可以用客户端证书。

把 webapi 和 nginx 都运行起来。

这个时候访问,就会提示, No required SSL certificate was sent。

用上面的控制台程序,再访问看看。

正确的证书,可以正常返回,错误的证书会返回 400 The SSL certificate error。

基于反向代理的话,操作起来就简单了一点。

如果是云负载均衡,只需要按他们的要求上传对应的证书即可。

讲了 nginx,不讲讲 IIS,好像有点说不过去。

那就再看看 IIS 的配置吧。

IIS 部署

在 Windows 服务器安装好 IIS 和托管捆绑包后,要先把我们的根证书安装到可信的根证书里面。

然后进行部署,绑定好服务端证书后,确认可以正常访问。

然后进行双向认证的配置。

在对应站点上面的 SSL 配置,把 要求 SSL必需 两个勾上即可。

后面再访问的时候,就会提示选择证书

选择正确的证书后就可以正常访问了。

然后我们再用前面的控制台程序访问,结果如下。

可以发现和前面的结果是一样的,不同的是错误返回的内容不一样。

上面提到的都是一些自建的场景,其实对云负载均衡的结合使用也是 OK 的。

总结

双向认证,在一些安全要求比较高的场景下,用途还是比较大的,相比较单向认证的话会麻烦一些。

本文示例代码:https://github.com/catcherwong-archive/2023/tree/main/MutualTLSAuthentication

参考资料

标签:key,certificate,证书,server,ssl,聊一聊,client,HTTPS,认证
From: https://www.cnblogs.com/catcher1994/p/17122324.html

相关文章

  • 真正“搞”懂HTTPS协议17之TLS握手
    经过前两章的学习,我们知道了通信安全的定义以及TLS对其的实现~有了这些知识作为基础,我们现在可以正式的开始研究HTTPS和TLS协议了。嗯……现在才真正开始。我记得......
  • 无法加载源 https://api.nuget.org/v3/index.json 的服务索引
    .net6之后,不会随项目生成packages文件夹,将项目拷贝到无联网的电脑上用VS打开时,会出现nuget还原失败的情况,只需要把原电脑中的用户文件夹下的.nuget文件夹拷贝过去,放到对应......
  • 【git】解决git clone时fatal: unable to access ‘https://gitee.com/XXX.git/‘: Th
    一、前言我的电脑一直录入的是我的gitee账号,平常和同事协作开发,gitpull、gitclone等git操作都没有报错过。但是,今天要gitclone另一个gitee账号的项目代码,出现报错403(如......
  • HttpServlet源码分析
    HttpServlet源码分析概念HttpServlet类是专门为Http协议准备的在哪个包下:jakarta.servlet.http.HttpServlet到目前为止我们接触了servlet规范中的哪些接口?jakart......
  • Github学生认证具体步骤
    具体步骤展示一、进入相关的申请地址地址在此:https://education.github.com/pack/二、选中右上方的Student,然后选择第二个选项在我们已经注册号Github账户的情况下,会......
  • WHQL认证多少钱?微软WHQL认证流程
    WHQL认证多少钱是很多驱动程序开发者关心的。虽然WHQL认证微软不收取费用,但是认证过程中,需要搭建多种类型的系统环境完成兼容性测试,需要按微软要求完成微软WHQL认证流程,这对......
  • jwt配置文件 drf-jwt源码执行流程 自定义用户实现jwt的签发和认证 simpleui 权限控制(
    昨日内容回顾#1接口文档的编写-1word,md编写---->存放位置:存放共享文件平台,git上-2第三方的接口文档编写平台-3公司自己开发,使用开源搭建yapi......
  • 62、PAM认证机制
    PAM介绍PAM:可插入式认证模块,是实现认证工作的一个模块。sun公司1995年开发,PAM只关注如何为服务验证用户的API,通过提供一些动态链接库和一套统一的API,将系统提供的服务和......
  • 真正“搞”懂HTTPS协议16之安全的实现
    上一篇噢,我们搞明白了什么是安全的通信,这个很重要,特别重要,敲黑板!!然后,我们还学了HTTPS到底是什么,以及HTTPS真正的核心SSL/TLS是什么。最后我们还聊了聊TLS的实现,也......
  • HTTPS基础原理和配置-2
    〇、概述作为概述,以下是本文要讲的内容。HTTPS是什么?每个人都可能从浏览器上认出HTTPS,并对它有好感。然后再讲一遍基础知识,再详细讲一下协议版本,密码套件(CipherSuites......