聊一聊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.crt、server.p12、server.crt、server.key、client.p12和 client2.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_client 和 ssl_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
参考资料
- https://michielsioen.be/2020-10-17-mutual-ssl-linux/
- https://docs.nginx.com/nginx/admin-guide/security-controls/securing-http-traffic-upstream/
- https://learn.microsoft.com/en-us/iis/manage/configuring-security/how-to-set-up-ssl-on-iis
聊一聊HTTPS双向认证的简单应用的更多相关文章
- HTTPS 双向认证构建移动设备安全体系
HTTPS 双向认证构建移动设备安全体系 对于一些高安全性要求的企业内项目,我们有时希望能够对客户端进行验证.这个时候我们可以使用Https的双向认证机制来实现这个功能. 单向认证:保证server是 ...
- Tomcat 配置 HTTPS双向认证
Tomcat 配置 HTTPS 双向认证指引说明: � 本文档仅提供 Linux 操作系统下的指引 � 在阅读本指引前请您在 Linux 部署 JDK 和 Tomcatserver为了 Tomcat ...
- httpd设置HTTPS双向认证
去年用tomcat.jboss配置过HTTPS双向认证,那时候主要用的是JDK自带的keytool工具.这次是用httpd + openssl,区别比较大 在网上搜索了很多文章,发现全面介绍的不多,或 ...
- Https双向认证Android客户端配置
Https .cer证书转换为BKS证书 公式https://blog.csdn.net/zww986736788/article/details/81708967 keytool -importce ...
- Android Https双向认证 + GRPC
keywords:android https 双向认证android GRPC https 双向认证 ManagedChannel channel = OkHttpChannelBuilder.for ...
- 双向认证 HTTPS双向认证
[微信支付]微信小程序支付开发者文档 https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=4_3 HTTPS双向认证使用说明 ...
- https双向认证訪问管理后台,採用USBKEY进行系统訪问的身份鉴别,KEY的证书长度大于128位,使用USBKEY登录
近期项目需求,须要实现用USBKEY识别用户登录,採用https双向认证訪问管理后台管理界面,期间碰到过一些小问题,写出来给大家參考下. 1:前期准备工作 USBKEY 硬件:我买的是飞天诚信 epa ...
- nodejs之https双向认证
说在前面 之前我们总结了https的相关知识,如果不懂可以看我另一篇文章:白话理解https 有关证书生成可以参考:自签证书生成 正题 今天使用nodejs来实现https双向认证 话不多说,直接进入 ...
- SpringBoot服务间使用自签名证书实现https双向认证
SpringBoot服务间使用自签名证书实现https双向认证 以服务server-one和server-two之间使用RestTemplate以https调用为例 一.生成密钥 需要生成server ...
- Keytool配置 Tomcat的HTTPS双向认证
Keytool配置 Tomcat的HTTPS双向认证 证书生成 keytool 简介 Keytool是一个Java数据证书的管理工具, Keytool将密钥(key)和证书(certificates) ...
随机推荐
- K8S节点选择器案例
#给节点打上标签 [root@lecode-k8s-master deployment]# kubectl label no lecode-dev-001 hostname=lecode-dev-00 ...
- MediatRPC - 基于MediatR和Quic通讯实现的RPC框架,比GRPC更简洁更低耦合,开源发布第一版
大家好,我是失业在家,正在找工作的博主Jerry.作为一个.Net架构师,就要研究编程艺术,例如SOLID原则和各种设计模式.根据这些原则和实践,实现了一个更简洁更低耦合的RPC(Remote Pro ...
- python编程学习方法及计算机基础理论
**从零开始学习编程 ** 一.学习前语 在学习python之前首先先说几点学习建议,首先是培养自己能解决问题的能力: 1.遇到问题时给自己设置一个解决该问题的时间限制 0-5min:自己解决问题(百 ...
- 爬虫之xpath插件下载与安装
目录 简介: 下载xpath文件 打开chrome浏览器 点击右上角小圆点 更多工具.阔展程序 拖拽xpath插件放到阔展程序 如果失效,再次拖拽 关闭浏览器重新打开 按ctrl+shift+x 出现 ...
- 【Shell案例】【wc记录单词长度、for循环和if、awk文本分析工具】7、打印字母数小于8的单词
描述写一个 bash脚本以统计一个文本文件 nowcoder.txt中字母数小于8的单词. 示例:假设 nowcoder.txt 内容如下:how they are implemented and a ...
- 不用USB,通过adb无线调试安卓手机页面
以前真机调试手机页面,都是使用数据线连接手机和电脑,近日身边没有USB数据线,折腾了下如何不依赖数据线只用无线调试手机页面,教程如下. 本教程适用于安卓11以及以上版本.否则应该使用USB数据线连接. ...
- 精华推荐 | 【深入浅出RocketMQ原理及实战】「性能原理挖掘系列」透彻剖析贯穿RocketMQ的事务性消息的底层原理并在分析其实际开发场景
什么是事务消息 事务消息(Transactional Message)是指应用本地事务和发送消息操作可以被定义到全局事务中,要么同时成功,要么同时失败.RocketMQ的事务消息提供类似 X/Open ...
- Linux下“减速”查看日志的方法
Linux下"减速"查看日志的方法 需求场景 今天查看日志,有个需求,需要按照指定"速率"输出日志信息到终端屏幕上,方便查看. 这个需求日常应该也经常会碰到,比 ...
- 第三章 --------------------XAML的属性和事件
1.XAML注释是什么样子的? 在之前的章节有提起过,但是这一节我还是想系统的学习XAML,XAML的注释如下 <!-- //这其中填写注释 --> Notice:在注释的部分编译器是不编 ...
- 使用IDEA创建一个maven的web项目并部署到tomcat上
目录 1.创建一个maven项目 2.为项目添加配置文件 3.创建一些类和jsp页面 4.将项目部署到tomcat 1.创建一个maven项目 打开IDEA,File--New--Project 选择 ...