ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

SSL单向/双向认证详解

2022-08-26 23:03:50  阅读:197  来源: 互联网

标签:crt nginx 证书 单向 pem SSL 详解 key 服务器


1、单向认证和双向认证

单向认证 SSL 协议的具体过程

①客户端的浏览器向服务器传送客户端 SSL 协议的版本号,加密算法的种类,产生的随机数,以及其他服务器和客户端之间通讯所需要的各种信息。

②服务器向客户端传送 SSL 协议的版本号,加密算法的种类,随机数以及其他相关信息,同时服务器还将向客户端传送自己的证书。

③客户利用服务器传过来的信息验证服务器的合法性,服务器的合法性包括:证书是否过期,发行服务器证书的 CA 是否可靠,发行者证书的公钥能否正确解开服务器证书的“发行者的数字签名”,服务器证书上的域名是否和服务器的实际域名相匹配。如果合法性验证没有通过, 通讯将断开;如果合法性验证通过,将继续进行第四步。

④用户端随机产生一个用于后面通讯的“对称密码”,然后用服务器的公钥(服务器的公钥从步骤②中的服务器的证书中获得)对其加密,然后将加密后的“预主密码”传给服务器。

⑤如果服务器要求客户的身份认证(在握手过程中为可选),用户可以建立一个随机数然后对其进行数据签名,将这个含有签名的随机数和客户自己的证书以及加密过的“预主密码”一起传给服务器。

⑥ 如果服务器要求客户的身份认证,服务器必须检验客户证书和签名随机数的合法性,具体的合法性验证过程包括:客户的证书使用日期是否有效,为客户提供证书的 CA 是否可靠,发行CA 的公钥能否正确解开客户证书的发行 CA 的数字签名,检查客户的证书是否在证书废止列表(CRL)中。检验如果没有通过,通讯立刻中断;如果验证通过,服务器将用自己的私钥解开加密的“预主密码 ”,然后执行一系列步骤来产生主通讯密码(客户端也将通过同样的方法产生相同的主通讯密码)。

⑦服务器和客户端用相同的主密码即“通话密码”,一个对称密钥用于 SSL 协议的安全数据通讯的加解密通讯。同时在 SSL 通讯过程中还要完成数据通讯的完整性,防止数据通讯中的任何变化。

⑧客户端向服务器端发出信息,指明后面的数据通讯将使用的步骤⑦中的主密码为对称密钥,同时通知服务器客户端的握手过程结束。

⑨服务器向客户端发出信息,指明后面的数据通讯将使用的步骤⑦中的主密码为对称密钥,同时通知客户端服务器端的握手过程结束。

⑩SSL 的握手部分结束,SSL 安全通道的数据通讯开始,客户和服务器开始使用相同的对称密钥进行数据通讯,同时进行通讯完整性的检验。

 

双向认证 SSL 协议的具体过程

① 浏览器发送一个连接请求给安全服务器。

② 服务器将自己的证书,以及同证书相关的信息发送给客户浏览器。

③ 客户浏览器检查服务器送过来的证书是否是由自己信赖的 CA 中心所签发的。如果是,就继续执行协议;如果不是,客户浏览器就给客户一个警告消息:警告客户这个证书不是可以信赖的,询问客户是否需要继续。

④ 接着客户浏览器比较证书里的消息,例如域名和公钥,与服务器刚刚发送的相关消息是否一致,如果是一致的,客户浏览器认可这个服务器的合法身份。

⑤ 服务器要求客户发送客户自己的证书。收到后,服务器验证客户的证书,如果没有通过验证,拒绝连接;如果通过验证,服务器获得用户的公钥。

⑥ 客户浏览器告诉服务器自己所能够支持的通讯对称密码方案。

⑦ 服务器从客户发送过来的密码方案中,选择一种加密程度最高的密码方案,用客户的公钥加过密后通知浏览器。

⑧ 浏览器针对这个密码方案,选择一个通话密钥,接着用服务器的公钥加过密后发送给服务器。

⑨ 服务器接收到浏览器送过来的消息,用自己的私钥解密,获得通话密钥。

⑩ 服务器、浏览器接下来的通讯都是用对称密码方案,对称密钥是加过密的。


上面所述的是双向认证 SSL 协议的具体通讯过程,这种情况要求服务器和用户双方都有证书。单向认证 SSL 协议不需要客户拥有 CA 证书,具体的过程相对于上面的步骤,只需将服务器端验证客户证书的过程去掉,以及在协商对称密码方案,对称通话密钥时,服务器发送给客户的是没有加过密的 (这并不影响 SSL 过程的安全性)密码方案。这样,双方具体的通讯内容,就是加过密的数据,如果有第三方攻击,获得的只是加密的数据,第三方要获得有用的信息,就需要对加密 的数据进行解密,这时候的安全就依赖于密码方案的安全。而幸运的是,目前所用的密码方案,只要通讯密钥长度足够的长,就足够的安全。这也是我们强调要求使 用 128 位加密通讯的原因。

 

2、证书扩展名

在开发和测试阶段,使用的是自签的证书。在找自签CA证书操作流程的时候,会有很多的文件扩展名,如pem,der,csr.cer.crt.p12,pfx,jks等,刚开始接触的话很容易混淆,因此先来看下证书的扩展名。

DER: .DER = DER扩展用于二进制DER编码证书。这些文件也可能承载CER或CRT扩展。
PEM:使⽤Base64 ASCII进⾏编码的纯⽂本格式,是以“ - BEGIN …”前缀的ASCII(Base64)数据。
KEY:.KEY 扩展名用于公钥和私钥,常见使用于私钥。也可以被编码为二进制DER或ASCII PEM。
CSR:证书签名请求。CSR文件是申请SSL证书时所需要的一个数据文件。
CRT:CRT扩展用于证书。 证书可以被编码为二进制DER或ASCII PEM。 CER和CRT扩展几乎是同义词。 最常见的于Unix 或类Unix系统。通俗来讲,.CRT文件常在Linux系统使用,包含公钥和主体信息。
CER:.CRT的替代形式,您可以在微软系统环境下将.CRT转换为.CER(.both DER编码的.CER,或base64 [PEM]编码的.cer)。通俗来讲,就是.CER扩展文件是DER编码,并且.CER文件常在Windows系统使用。
P12:P12证书全称是PKCS#12。是一种交换数字证书的加密标准,用来描述个人身份信息。p12证书包含了私钥、公钥并且有口令保护,在证书泄露后还有最后一道保障——证书口令,不知道正确的证书口令无法提取秘钥(文件的扩展名能够为pfx或p12)​
PFX:PFX也是由PKCS#12标准定义,包含了公钥和私钥的二进制格式的证书形式,以pfx做为证书文件后缀名(文件的扩展名能够为pfx或p12)
JKS:JKS是JAVA的keytools证书工具支持的证书私钥格式

 

3、实战

openssl准备环境

 

使用openssl version查看openssl版本,如果没有安转openssl,可以执行 yum install openssl 安装

 

nginx环境准备

我们使用nginx来进行https的双向认证,首先我们需要安装nginx并附带SSL模块,在linux下安装nginx,首先需要安装 gcc-c++编译器。然后安装nginx依赖的pcre和zlib包。最后安装nginx即可。

1.先安装gcc-c++编译器

yum install gcc-c++
yum install -y openssl openssl-devel


2.再安装pcre包

yum install -y pcre pcre-devel


3.再安装zlib包

yum install -y zlib zlib-deve


4.nginx安装

#在/usr/local/下创建文件nginx文件

mkdir /usr/local/nginx

 

#在网上下nginx包上传至Linux(https://nginx.org/download/),也可以直接下载

wget https://nginx.org/download/nginx-1.19.9.tar.gz

 

#解压并进入nginx目录

tar -zxvf nginx-1.19.9.tar.gz

cd nginx-1.19.9


#使用nginx默认配置

./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-pcre

 

#编译安装

make

make install

 

#查找安装路径

whereis nginx


#
进入sbin目录,可以看到有一个可执行文件nginx,直接./nginx执行就OK了。

./nginx

 

#查看是否启动成功

ps -ef | grep nginx

 

 

 

#然后在网页上访问自己的IP就可以了默认端口为80(出现如下欢迎界面就成功了!)

 

 

 

 

 

自签CA证书

1、生成根证书

#创建证书存放的⽬录

mkdir ssl 

 

#进⼊证书存放⽬录

cd ssl 

 

#生成私钥

openssl genrsa -out ca.key 2048 #⽣成根证书私钥


#查看一下ca.key 的内容,可以看到

 

 

 

 

 

 

 

#可以将ca.key转为pem文件

openssl rsa -in ca.key -out ca-key.pem

再查看一下ca-key.pem文件,内容和ca.key是相同的

 

#生成根证书

openssl req -new -x509 -days 3650 -key ca.key -out ca.crt

-days设置证书有效时间,这里我们设置10年
生成证书时要输入一些个体信息
证书生成后,可以查看ca.crt的内容

 

 

 

#也可以将ca.crt转为pem文件

openssl x509 -in ca.crt -out ca-crt.pem

再查看一下ca-crt.pem文件,内容和ca.crt是相同的

 

#编码类型转换

PEM编码转为DER编码

 

openssl x509 -in ca-crt.pem -outform der -out ca-crt.der

 

DER转为PEM

openssl x509 -in ca-crt.der -inform der -outform pem -out ca-crt.pem

(提示:要转换KEY文件也类似)


der二进制编码的文件不能直接查看,可以使用命令查看.der文件

openssl x509 -in ca-crt.der -inform der -text -noout

 

2、生成服务端证书

为了便于理解和操作,这里统一使用pem编码,并统一生成pem格式扩展文件

#生成服务端私钥

# 生成pem扩展名的私钥
openssl genrsa -out server-key.pem 2048
# 2048表示生成的私钥为2048位,一般使用2048位相对比较安全

 

#将.pem扩展名私钥转为.key

openssl rsa -in server-key.pem -out server.key

再查看server.key 和server.pem 私钥内容是相同的

 

#生成服务端证书签名请求文件

#注意这⾥的common name必须是需要访问的域名,其他的内容可以和根证书填写的⼀样
openssl req -new -key server-key.pem -out server-csr.pem

 

 

 

#可以将server-csr.pem转为.csr扩展名

openssl req -in server-csr.pem -out server.csr 或直接修改扩展名 .pem为.csr

 

#根据签发请求⽣成服务端证书

openssl x509 -req -sha256 -in server-csr.pem -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650 -out server-crt.pem

 

 

 

#可以将server-crt.pem转为.crt扩展名

openssl x509 -outform pem -in server-crt.pem -out server.crt

 

#生成服务端pfx或p12证书

openssl pkcs12 -export -in server.crt -inkey server.key -out server.pfx

 

注:在将.pem扩展文件转为key,csr,crt文件的时候,先查看文件内容
包含 -----BEGIN RSA PRIVETE KEY ----- 的内容可以导出转换.key扩展名的文件
包含 -----BEGIN CERTIFICATE REQUEST ----- 的内容可以导出转换.csr扩展名的文件
包含 -----BEGIN CERTIFICATE ----- 的内容可以导出转换.crt扩展名的文件

 

3、生成客户端证书
客户端证书⽣成步骤和服务端基本⼀样,需要注意的就是在⽣成签发请求的时候填写的信息中,comm name也要是访问的域名。

#生成客户端私钥

openssl genrsa -out client.key 2048

 

#生成客户端证书签名请求文件

openssl req -new -key client.key -out client.csr

 

#根据签发请求和⽣成客户端证书

openssl x509 -req -sha256 -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650 -out client.crt

 

#生成客户端pfx或p12证书

openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12

 

4、开启https,并校验客户端(双向认证)
#配置nginx,开启https

开启https请求
进入nginx目录,编辑nginx.conf – vim nginx.conf
找到HTTPS server
ssl_certificate 服务端crt证书路径
ssl_certificatie_key 服务端私钥路径
 
配置完以后 启动或者容器一下nginx
启动:在nginx目录执行 ./sbin/nginx
重启:在nginx目录执行 ./sbin/nginx -s reload
在浏览器访问是成功的,因为我们是自签证书,因此显示不安全

 

 

 

 


#开启客户端认证

vim nginx.conf #继续编辑nginx.conf
ssl_client_certificate #指定客户端认证时使⽤的根证书路径,⽤来验证客户端证书的正确性,我们使用的自签ca证书签发的客户端证书,因此使用ca.crt
ssl_verify_client on #为开启客户端校验

 

 

配置完成后重启

nginx ./sbin/nginx -s reload

 

为了方便测试。我们直接使用curl 命令进行测试

curl https://ip -k -v

 

ip为访问的具体ip地址
-k编码忽略服务端证书的校验,因为我们这里服务端证书也是自签的,所以要加上-k
不加-k,会有异常提示

 

 

 

-v为显示具体的信息,也可以不加
使用上述命令访问后

 

 

提示需要携带客户端的证书,说明我们配置的客户端认证已经生效了

curl --cert client.crt --key client.key https://ip -k

 

 可以看到携带证书后访问是成功的,说明客户端已经认证成功了,因此https双向认证完成了

5.java代码
附一段java代码,代码来自 https://wenku.baidu.com/view/ee8e04315c0e7cd184254b35eefdc8d376ee1494.html

public class SSLService {
    // 客户端证书路径,⽤了本地绝对路径,需要修改
    private final static String CLIENT_CERT_FILE = "C:\\Users\\tzx\\Desktop\\client.p12";
    // 客户端证书密码
    private final static String CLIENT_PWD = "131112";
    // 信任库路径,即keytool⽣成的那个⾃定义名称的库⽂件
    private final static String TRUST_STRORE_FILE = "D:\\Java\\jdk1.8.0_131\\jre\\lib\\security\\test.truststore";
    // 信任库密码,即keytool时的密码
    private final static String TRUST_STORE_PWD = "131112";
    private static String readResponseBody(InputStream inputStream) throws IOException {
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
            StringBuffer sb = new StringBuffer();
            String buff = null;
            while ((buff = br.readLine()) != null) {
                sb.append(buff + "\n");
            }
            return sb.toString();
        } finally {
            inputStream.close();
        }
    }
    public static void httpsCall() throws Exception {
        // 初始化密钥库
        KeyManagerFactory keyManagerFactory = KeyManagerFactory
                .getInstance("SunX509");
        KeyStore keyStore = getKeyStore(CLIENT_CERT_FILE, CLIENT_PWD, "PKCS12");
        keyManagerFactory.init(keyStore, CLIENT_PWD.toCharArray());
        // 初始化信任库
        TrustManagerFactory trustManagerFactory = TrustManagerFactory
                .getInstance("SunX509");
        KeyStore trustkeyStore = getKeyStore(TRUST_STRORE_FILE, TRUST_STORE_PWD, "JKS");
        trustManagerFactory.init(trustkeyStore);
        // 初始化SSL上下⽂
        SSLContext ctx = SSLContext.getInstance("SSL");
        ctx.init(keyManagerFactory.getKeyManagers(), trustManagerFactory
                .getTrustManagers(), null);
        SSLSocketFactory sf = ctx.getSocketFactory();
        HttpsURLConnection.setDefaultSSLSocketFactory(sf);
        String url = "https://blog.tzx.com";
        URL urlObj = new URL(url);
        HttpsURLConnection con = (HttpsURLConnection) urlObj.openConnection();
        con.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 " +
                "(KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36");
        con.setRequestProperty("Accept-Language", "zh-CN;en-US,en;q=0.5");
        con.setRequestMethod("GET");
        String res = readResponseBody(con.getInputStream());
        System.out.println(res);
    }
    /**
     * 获得KeyStore
     */
    private static KeyStore getKeyStore(String keyStorePath, String password, String type)
            throws Exception {
        FileInputStream is = new FileInputStream(keyStorePath);
        KeyStore ks = KeyStore.getInstance(type);
        ks.load(is, password.toCharArray());
        is.close();
        return ks;
    }
   public static void main(String[] args) throws Exception {
    httpsCall(null);
  }
}

 

标签:crt,nginx,证书,单向,pem,SSL,详解,key,服务器
来源: https://www.cnblogs.com/simono/p/16629480.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有