背景

最近,某个运维同事找到我,说测试环境的某个域名(他也在负责维护),假设域名为test.baidu.com,以前呢,证书都是用的生产的证书,最近不让用了。问为啥呢,说不安全,现在在整改了,因为证书和私钥肯定要一起部署在服务器上,既然测试环境的服务器部署了生产上的证书,那也就是说私钥也部署在测试服务器上,那自然是不安全。咱们小公司嘛,就是这个样子的,管理不是很规范。

那现在也就是说,要给这个test.baidu.com这个域名,弄一个测试环境的证书。然后,他是运维嘛,办公电脑上装软件的限制比较多,就问我,能不能帮忙生成个test.baidu.com的证书给他,就那种自签名的就行了。

问题

我一想,我们之前有个环境测试https,搞过一个自签名证书,直接发给他就行了,然后他就拿去部署到nginx了。

ssl     on;
ssl_certificate comkey.crt;
ssl_certificate_key comkey.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1.2;

结果,过了两天,他说部署上去后,有个客户端调用的时候报错,说证书里有个字段的值没对。

我给他的证书里,如上图所示,subject alternative name的内容为:DNS NAME = ma-dev.example.com.cn,而他拿去部署的网站的域名为test.example.com.cn,导致客户端校验出错了,说能不能重新生成下证书给他。

我本来吧,不想弄的,因为我也忘了之前这个证书,怎么会包含这个字段,我也不知道这个字段啥意思。

到后面,还是接了这个事。

尝试

网上找了个教程:https://cloud.tencent.com/document/product/1552/111585

可惜,生成出来的证书,根本就没有那个certifacate subject alternative name字段。

他这个生成证书,其实分了三个核心步骤。证书呢,里面一般是包含了公钥,这个是公开的,浏览器拿到证书后,会检查证书,有一堆规则,比如:验证证书是由合法的root CA签发的,没过期,没吊销等,如果都没问题,就认为证书有效,就会取出证书中包含的各个信息,如公钥信息。

这个公钥和服务端私密保存的私钥(也就是key文件,一般会配置到nginx里),是一一对应的,一般私钥发生了泄露,这个证书就算是废了。

所以,回到我们的证书生成环节,也是我们先生成一个私密的key,如上面的openssl genrsa -out server.key 2048这步。

然后呢,用这个key,去生成一个证书签名请求文件(CSR)。

CSR(Cerificate Signing Request),即证书请求文件,是证书申请者在申请数字证书时,生成私钥的同时生成证书请求文件。证书申请者把CSR文件提交给证书颁发机构后,证书颁发机构使用其根证书私钥签名就生成了证书公钥文件。

这个CSR里,就要包含我们希望放进证书的各种内容,比如我们本文提到的certifacate subject alternative name这些字段等。CSR准备好了后,提交给各个CA机构,然后CA机构理论上来说,会核查你、你的网站等各种身份信息,核查无误后,就会用它这家CA的私钥,对你的CSR进行签名,然后就生成了一个它这家CA认可的证书了。

后续,你就拿着这个证书,传输给用户的浏览器,用户浏览器中,有这家CA的公钥,自然就能发现你这个证书确实是这家CA的私钥签发的,就认可你的证书,后续就能正常通信。

回到我们的问题,首先,我们就必须要保证CSR文件中,包含我们的certifacate subject alternative name字段才行。

生成csr

由于这会在家里,连不上公司vpn了(正好到期了),也没法演示之前的各种错误了。所以就直接记录一下各种正确的方法。

方法1: addext选项

这个选项是openssl的1.1.1版本才有的。查看版本:openssl version。一般来说,linux服务器的openssl版本升级还是非常慎重的,如果发现版本不支持,那么,有个好办法,直接在windows上安装高版本的openssl来生成csr也是一样的: http://slproweb.com/products/Win32OpenSSL.html 这里可以下载,如(Win64 OpenSSL v3.4.1)。

这个选项比较方便,选项的注释如下:

G:\openssl-test>openssl req -h
-addext val Additional cert extension key=value pair (may be given more than once)
openssl genrsa -out server.key 2048

保留原有的交互式方式,同时又能指定subjectAltName这些扩展字段。
openssl req -new -out server.csr -key server.key -addext "subjectAltName = DNS:test.baidu.com.cn"

生成的csr文件,我们可以查看:

openssl req -in server.csr -noout -text

网上也可以解码查看一个csr文件的内容:

https://www.sslshopper.com/csr-decoder.html

方法2: 配置文件

这个方法,我试了下,我的老版本OpenSSL 1.0.2k-fips也是支持的。

本来参考了:https://support.huawei.com/enterprise/zh/doc/EDOC1100296985?section=j025

结果发现行不通。

后面自己调整成全从配置文件中读了:

csr.conf:

[ req ]
default_bits = 2048
default_md = sha256
prompt = no
distinguished_name = req_distinguished_name
req_extensions = SAN [ req_distinguished_name ]
C = CN
ST = Sichuan
L = Chengdu
O = BAIDU
OU = IT
CN = test.baidu.com [ SAN ]
subjectAltName = @alt_names [ alt_names ]
DNS.1 = test.baidu.com
IP.1 = 192.168.1.1

命令如下:

openssl req -new -key server.key  -out server1.csr   -config csr.conf

目前这个调整后的配置,和我在下面这个教程中的差不多:

https://mp.weixin.qq.com/s/RYbdt2NY-kE3YE2THMnx9A

不过这个教程里的配置还要多一点点,且是通过指定环境变量OPENSSL_CONF的方式来指定配置文件:

[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no [req_distinguished_name]
C = PH
ST = Manila
L = Quezon
O = HCL
CN = test.baidu.com [v3_req]
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names [alt_names]
DNS.1 = test.baidu.com
这里明确说了,会覆盖 OPENSSL_CONF 环境变量中的配置。
-config filename
this allows an alternative configuration file to be specified, this overrides the compile time filename or any specified in the OPENSSL_CONF environment variable.

生成自签名证书

如果大家是生成csr,提交给CA去生成证书,就不涉及这部分。这部分主要是生成自签名证书的时候遇到的问题。

我之前的时候,遇到的最大问题其实就是生成证书,明明看到csr里面都是有我们需要的选项的,但是,证书里就没了。其实就是因为,没指定一个叫extfile的选项,这里说了,不指定的话,不会添加任何扩展到证书里。

man x509

-extfile filename
file containing certificate extensions to use. If not specified then no extensions are added to the certificate.

这里也说下正确的方法。

方法1

参考了:

https://security.stackexchange.com/questions/150078/missing-x509-extensions-with-an-openssl-generated-certificate

和csr一样,生成证书时,也可以指定一个配置文件:

# ssl-extensions-x509.cnf

[v3_ca]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName = IP:127.0.0.1, IP:192.168.73.120, IP:192.168.73.121

可以看到,文件里包含了一个段,叫:v3_ca

在下面的命令中,我们同时指定配置文件,且指定要使用的段名:

[root@VM-0-6-centos ssltest]# openssl x509 -req -in server.csr -out server.crt -signkey server.key  -days 3650 -extensions v3_ca -extfile ./ssl-extensions-x509.cnf
Signature ok
subject=/C=CN/ST=Sichuan/L=Chengdu/O=BAIDU/OU=IT/CN=test.baidu.com
Getting Private key

证书就生成了,我们查看下证书:

 openssl x509 -in server.crt -text -noout

我们在linux中看下对应的注释:

man x509

方法2

上面的方法1,是显式指定,也可以不指定具体的段,仅指定配置文件:

https://mp.weixin.qq.com/s/ce-QN78xwRSTN3ZgWIvQAg

创建一个文件:cert.conf

authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = test.baidu.com
openssl x509 -req    -in server.csr  -out server.crt   -signkey server.key  -days 365     -sha256 -extfile cert.conf

我们查看下,也是ok的:

jdk1.8中如何校验SAN字段

我这里拿deepseek网站来举例吧,我们通过浏览器,能看到它的证书的SAN字段:

可以看到,内容为:

Not Critical
DNS Name: *.deepseek.com
DNS Name: deepseek.com

接下来,看如下的代码:

	public static void main(String[] args) throws IOException {
URL url = new URL("https://www.deepseek.com/");
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(10000);
connection.setReadTimeout(3000);
int responseCode = connection.getResponseCode();
System.out.println(responseCode);
}

我们平时可能习惯了忽略证书校验,如:

今天我们就简单看看,不忽略的话,是在什么地方校验的。

在收到服务端返回的证书的消息时,会进入以下代码:

然后使用默认的trustManager(sun.security.ssl.X509TrustManagerImpl)来校验服务端证书:

接着进入如下方法,校验server和校验client的方法一样,只是最后一个参数不同,false就是校验服务端:

然后如下代码,就要开始校验:我们请求时的域名为www.deepseek.com,那么证书到底是不是匹配呢,是不是www.deepseek.com的证书呢?

我们一路深入到如下方法,自始至终,参数就两个,一个是请求的域名(其实是取了客户端握手消息时携带的SNI字段,正好就是我们请求的域名,所以,就算我们使用https加密,网管也是知道我们在上什么网站的),一个是返回的证书:

接下来,从证书中获取了SAN字段,这是个集合:

最后就是遍历这个集合,看看是否匹配我们请求的域名,最终呢,www.deepseek.com就匹配上了SAN中的*.deepseek.com这条,所以,这个校验就算是ok了。

我们也就大概知道了SAN字段的用法,以及它为什么重要了。

参考文档

https://mp.weixin.qq.com/s/ce-QN78xwRSTN3ZgWIvQAg

https://stackoverflow.com/questions/6194236/openssl-certificate-version-3-with-subject-alternative-name

https://stackoverflow.com/questions/58845805/error-creating-csr-in-openssl-using-subjectaltname-othername

https://security.stackexchange.com/questions/150078/missing-x509-extensions-with-an-openssl-generated-certificate

https证书中的subject alternative name字段作用及如何生成含该字段的证书的更多相关文章

  1. 【java细节】Java代码忽略https证书:No subject alternative names present

    https://blog.csdn.net/audioo1/article/details/51746333

  2. JDK安全证书的一个错误消息 No subject alternative names present的解决办法

    我使用Java消费某网站一个Restful API时,遇到这个错误: 21:31:16.383 [main] DEBUG org.springframework.web.client.RestTemp ...

  3. java.security.cert.CertificateException: No subject alternative names present

    背景:在开发一个项目中,要调用一个webservice服务,之前设置的是http协议,项目中采用jdk自带的wsimport工具生成的客户端代码; 后来,需求变更要求兼容https协议的webserv ...

  4. 使用HttpClient携带证书报错_Certificate for <IP> doesn't match any of the subject alternative names:[域名]

    使用HttpClient携带pfx证书通过Https协议发送SOUP报文调用WebService接口时报如下错误: Exception in thread "main" javax ...

  5. Chrome:不受信任的证书----openssl签发带Subject Alternative Name的证书

    Chrome下自签名证书提示无效的问题 发现chrome验证证书很严格,必须带有Subject Alternative Name.签发csr时,修改openssl.cnf : vi /etc/ssl/ ...

  6. MVC图片上传详解 IIS (安装SSL证书后) 实现 HTTP 自动跳转到 HTTPS C#中Enum用法小结 表达式目录树 “村长”教你测试用例 引用provinces.js的三级联动

    MVC图片上传详解   MVC图片上传--控制器方法 新建一个控制器命名为File,定义一个Img方法 [HttpPost]public ActionResult Img(HttpPostedFile ...

  7. Aandroid 解决apk打包过程中出现的“Certificate for <jcenter.bintray.com> doesn't match any of the subject alternative names: [*.aktana.com, aktana.com]”的问题

    有时候,apk打包过程中会出现“Certificate for <jcenter.bintray.com> doesn't match any of the subject alterna ...

  8. 用HttpClient发送HTTPS请求报SSLException: Certificate for <域名> doesn't match any of the subject alternative names问题的解决

    最近用server酱-PushBear做消息自动推送,用apache HttpClient做https的get请求,但是代码上到服务器端就报javax.net.ssl.SSLException: Ce ...

  9. 自签证书 doesn't match any of the subject alternative names

    出现这个的原因是https中的域名或者IP,与证书中登记的不一致. 如果是自签证书的话,可以根据具体需要重新生成证书. 还有一种解决方案是在java中跳过这个检查. 绕过检查分两类,一个是绕过证书在C ...

  10. https学习笔记三----OpenSSL生成root CA及签发证书

    在https学习笔记二,已经弄清了数字证书的概念,组成和在https连接过程中,客户端是如何验证服务器端的证书的.这一章,主要介绍下如何使用openssl库来创建key file,以及生成root C ...

随机推荐

  1. Qt编写安防视频监控系统21-摄像机管理

    一.前言 摄像机管理在整个系统中是数据库部分最核心的,只有添加了摄像机信息,才能进行加载,生成树状列表等,摄像机表信息的字段内容改过好几次,有可能后期还需要修改,目前摄像机表信息主要包括摄像机编号.摄 ...

  2. Qt编写地图综合应用18-地图模式

    一.前言 除了传统的街道图地图外,默认的一般都是街道图,还有卫星图.三维图等,其中又有叠加层,比如叠加路况图层和路网图层等,最近去了多家的地图官网看对应的api接口,总体上感觉现在都往2.5D或者3D ...

  3. IDEA中基于SSM框架进行web开发部署项目到Tomcat时报错:Error:Cannot build artifact '******:war exploded' because it is included into a circular depency的解决办法

    在Idea中使用Maven创建父子工程,第一个Model的那个项目可以很好的运行,在创建一个Model运行时报这个错.原因是tomcat部署了多个Web项目,可能最开始是两个项目的配置文件混用用,最后 ...

  4. nvm的安装与使用,多个node版本同时使用

    nvm的介绍 nvm全英文也叫node.js version management,是一个nodejs的版本管理工具.nvm和npm都是node.js版本管理工具,为了解决node.js各种版本存在不 ...

  5. 深入剖析数据删除操作:DELETE 语句的使用与管理实践

    title: 深入剖析数据删除操作:DELETE 语句的使用与管理实践 date: 2025/1/8 updated: 2025/1/8 author: cmdragon excerpt: 数据删除( ...

  6. 10.3 - AM - 模拟赛 总结

    复盘 T1 很水,一道异或求和,但是某两位仁兄因没打括号而死. T2 很水,一道字符串处理,但是我和某位仁兄因没特判而死(虽然没有 hack 掉我,所以我理论上还是满分). T3 不水,看了很久,没想 ...

  7. MySQL 开发规范

    建表规约 1.[强制]每张表必须设置一个主键ID,并且这个主键ID要自增(在满足需要的情况下尽量短),除非是分库分表 理解:由于InnoDB存储引擎决定了需要有一个主键,而且这个主键ID是自增的话可以 ...

  8. RabbitMQ-要点简介

    Windows下安装RabbitMQ RabbitMQ是流行的开源消息队列系统,用erlang语言开发,RabbitMQ是AMQP(高级消息队列协议)的标准实现. 要安装RabbitMQ,首先要安装E ...

  9. ClickHouse介绍-示例

    示例 GitHub 事件数据集 数据集包含了GitHub上从2011年到2020年12月6日的所有事件,大小为31亿条记录.下载大小为75 GB,如果存储在使用lz4压缩的表中,则需要多达200 GB ...

  10. w3cschool-Linux 命令大全

    Linux关机命令和重启命令说明 在Linux中,常用的关机命令shutdown.halt.poweroff.init:重启命令有:reboot.本文将主要为大家带来一些常用的关机命令以及各种关机命令 ...