SSL介绍:
SSL 是“Secure Sockets Layer”的缩写,中文叫做“安全套接层”。它是在上世纪90年代中期,由网景公司设计的。到了1999年,SSL 应用广泛,已经成为互联网上的事实标准。IETF 就把SSL 标准化。标准化之后SSL被改为 TLS(Transport Layer Security传输层安全协议)。
SSL协议分为两层:
SSL记录协议 (SSL Record Protocol):它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能。
SSL握手协议(SSL Handshake Protocol):它建立在SSL记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。
SSL协议提供的服务:
1)认证用户和服务器,确保数据发送到正确的客户机和服务器
2)加密数据以防止数据中途被窃取
3)维护数据的完整性,确保数据在传输过程中不被改变。
工作流程
ssl握手协议
SSL握手协议的协议字段:
Type: 10中消息类型之一
Length:消息字节长度
Content: 与消息相关参数
SSL握手协议总过程:
SSL建立过程总共有13个包,第一次建立至少需要9个包。
SSL握手第一阶段:
SSLclient通过Client Hello消息将它支持的SSL版本号、加密算法、密钥交换算法、MAC算法等信息发送给SSLserver
客户端发送的密码套件的格式:
密码套件格式:每个套件都以“SSL”开头,紧跟着的是密钥交换算法。用“With”这个词把密钥交换算法、加密算法、散列算法分开,
例如:SSL_DHE_RSA_WITH_DES_CBC_SHA,
DHE_RSA(带有RSA数字签名的暂时Diffie-HellMan)定义为密钥交换算法; DES_CBC定义为加密算法;
SHA定义为散列算法。
SSL握手第二阶段:
服务器启动SSL握手的第二阶段,是本阶段唯一的发送方,客户机是唯一的接收方。
证书:服务器将证书和根CA整个链发给客户端。使客户端能用服务器证书中的服务器公钥认证服务器。
服务器密钥交换: 由密钥交换算法决定的。
证书请求: 服务端可能会要求客户自身验证。
服务器握手完成:第二阶段结束,第三阶段开始。
Certificate消息(可选):第一次建立必须要有证书。
一般情况下,除了会话恢复时不需要发送该消息,在SSL握手的全流程中,都需要包含该消息。
消息包含一个X.509证书,证书中包含公钥,发给客户端用来验证签名或在密钥交换的时候给消息加密。
这一步是服务器端将自己的证书下发给客户端,让客户端验证自己的身份,客户端验证通过后取出证书中的公钥。
Server Key Exchange(可选):
根据之前在ClientHello消息中包含的CipherSuite消息,决定了密钥交换方式。
因此在Server Key Exchange消息中便会包含完成密钥交换所需的一系列参数。
这里使用的是Diffi-Hellman算法,所以需要发送服务器使用的DH参数,RSA算法不需要。
在Diffie-Hellman中,客户端无法自行计算预主密钥;双方都有助于计算它,因此客户端需要从服务器获取Diffie-Hellman公钥。
Certificate Request(可选): 可以是单向的身份验证,也可以是双向的身份验证
服务器用来验证客户端,服务器发送Certificate Request消息,要求客户端发它自己的证书过来进行验证。
该消息中包含服务器支持的证书类型(RSA,DSA,ECDSA)和服务器端所信任的所有证书发行机构的CA列表。
客户端会用这些信息来筛选证书。
Server Hello Done
该消息表示服务器已经将所有信息发送完毕,接下来等待客户端的消息。
SSL握手第三阶段:
客户端启动SSL握手的第三阶段,客户端使本阶段唯一的发送方,服务器端是唯一接收方
证书(可选):为了对服务器证明自身,客户端要发送一个证书消息,这是可选的。
客户机密钥交换(Pre-master-secret): 这里客户端要将预备主密钥发送给服务器,使用服务器端的公钥进行加密。
证书验证(可选):对预备主密钥和随机数进行签名,证明拥有证书的密钥
Certificate(可选):
如果在第二阶段服务器端要求发送客户端证书,客户端便会在该阶段将自己的证书发送过去。服务器端在之前发送的Certificate
Request消息中包含了服务器端所支持的证书类型和CA列表,因此客户端会在自己的证书中选择满足这两个条件的第一个证书发送过去。若客户端没有证书,则发送一个no_certificate警告。
Client Key Exchange:
> 根据之前从服务器端收到的随机数,按照不同的密钥交换算法(RSA,Diffie-Hellman)产生的一个48字节的key,算出一个pre-master(是整个握手阶段第三个随机数),发送给服务器,服务器端收到pre-master算出main
> master。而客户端当然也能自己通过pre-master算出main master。如此以来双方就算出了对称密钥。
> 如果是RSA算法,会生成一个48字节的随机数,然后用server的公钥加密后再放入报文中。
如果是DH算法,发送的就是客户端的DH参数,之后服务器和客户端根据DH算法,各自计算出相同的pre-master secret.`
![image-20210908114317139](https://img-blog.csdnimg.cn/img_convert/975743c3b22280866dde128ead70bf3b.png)
本消息在给服务器发送的过程中,使用了服务器的公钥加密。服务器用自己的私钥解密后才能得到pre-master key.(向服务器证明自己的确持有客户端证书私钥。)
Certificate Verify(可选):
```java
`只有在客户端发送了自己证书到服务器端,这个消息才需要发送。其中包含一个签名,对从第一条消息以来的所有握手消息的HMAC值(用master_secret)进行签名。`
SSL握手第四阶段:
客户端启动SSL握手的第四个阶段,使服务器结束。该阶段分为四步,前两个消息来自客户机,后2个消息来自服务器。
建立起一个安全的连接,客户端发送一个Change Cipher Spec消息,并且把协商得到的CipherSuite拷贝到当前连接的状态之中。
客户端用新的算法、密钥参数发送一个Finished消息, 这条消息可以检查密钥交换和认证过程是否已经成功。其中包括一个校验值,
对客户端整个握手过程的消息进行校验。服务器同样发送Change Cipher Spec消息和Finished消息。握手过程完成,客户端和服务器
可以交换应用层数据进行通信。
ChangeCipherSpec:
编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送(ChangeCipherSpec是一个独立的协议,体现在数据包中就是一个字节的数据,用于告知服务端,客户端已经切换到之前协商好的加密套件(Cipher
Suite)的状态,准备使用之前协商好的加密套件加密数据并传输了)。Clinet Finished:
客户端握手结束通知,
表示客户端的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供服务器校验(使用HMAC算法计算收到和发送的所有握手消息的摘要,然后通过RFC5246中定义的一个伪函数PRF计算出结果,加密后发送。此数据是为了在正式传输应用数据之前对刚刚握手建立起来的加解密通道进行验证。)
Server Finished:
`服务端握手结束通知。
1.使用私钥解密加密的Pre-master数据,基于之前(Client Hello 和 Server Hello)交换的两个明文随机数 random_C 和 random_S,计算得到协商密钥:enc_key=Fuc(random_C, random_S,
Pre-Master);
2.计算之前所有接收信息的 hash 值,然后解密客户端发送的 encrypted_handshake_message,验证数据和密钥正确性;
3.发送一个 ChangeCipherSpec(告知客户端已经切换到协商过的加密套件状态,准备使用加密套件和 Session Secret加密数据了)
4.服务端也会使用 Session Secret 加密一段 Finish 消息发送给客户端,以验证之前通过握手建立起来的加解密通道是否成功。根据之前的握手信息,如果客户端和服务端都能对Finish信息进行正常加解密且消息正确的被验证,则说明握手通道已经建立成功,接下来,双方可以使用上面产生的Session Secret对数据进行加密传输了。 `
消息验证代码(HMAC)和TLS数据完整性:
当服务器或客户端使用主密钥加密数据时,它还会计算明文数据的校验和(哈希值),这个校验和称为消息验证代码(MAC)。然后在发送之前将MAC包含在加密数据中。密钥用于从数据中生成MAC,以确保传输过程中攻击者无法从数据中生成相同的MAC,故而MAC被称为HMAC(哈希消息认证码)。另一方面,在接收到消息时,解密器将MAC与明文分开,然后用它的密钥计算明文的校验和,并将其与接收到的MAC进行比较,如果匹配,那我们就可以得出结论:数据在传输过程中没有被篡改。
重要的secret key
PreMaster secret
PreMaster Secret是在客户端使用RSA或者Diffie-Hellman等加密算法生成的。它将用来跟服务端和客户端在Hello阶段产生的随机数结合在一起生成 Master Secret。PreMaster secret前两个字节是TLS的版本号,这是一个比较重要的用来核对握手数据的版本号。服务端需要对密文中解密出来对的PreMaster版本号跟之前Client Hello阶段的版本号进行对比,如果版本号变低,则说明被串改,则立即停止发送任何消息。
Master secret
由于最后通过交换,客户端和服务端都会有Pre-master和随机数,这个随机数将作为后面产生Master secret的种子,结合PreMaster secret,客户端和服务端将计算出同样的Master secret。
配置不同端的虚拟主机访问apache服务器
1.创建一个目录,里面有两个不同端
mkdir -p /www/ip/{100,200}
2.增加内容
[root@localhost ~]# echo this is 100 > /www/ip/100/index.html
[root@localhost ~]# echo this is 200 > /www/ip/200/index.html
3.配置文件vim /etc/httpd/conf.d/myhosts.conf
<Directory "/www/ip">
AllowOverride none
Require all granted
</Directory>
Listen 100
<VirtualHost 192.168.155.100:100 >
DocumentRoot "/www/ip/100"
ServerName 192.168.233.100
</VirtualHost>
Listen 200
<VirtualHost 192.168.155.100:200>
DocumentRoot "/www/ip/200"
ServerName 192.168.155.200
</VirtualHost>
结果:
在这里插入图片描述
配置用户控制和虚拟目录访问apache服务器
1.先创建一个密码
htpasswd -c /usr/local/etc/passwd
(-c表示创建)
输入密码
2.创建浏览器首页
/www/baohu
echo this is my secret > /www/baohu/index.html
3.vim /etc/httpd/conf.d/myhosts.conf
Listen 8001
<Directory "/www/baohu">
AuthType Basic
AuthName "hello"
AuthBasicProvider file
AuthUserFile "/usr/local/etc/passwd"
require user lsj
</Directory>
<VirtualHost 192.168.155.200:8001>
alias /xuni /www/baohu
ServerName 192.168.155.200
</VirtualHost>
结果:
配置使用ssl完成https访问apache服务器
1.安装ssl# yum install mod_ssl -y
[root@localhost https]# yum install mod_ssl -y
2.在www目录下创建https目录
3.vim /etc/httpd/conf.d/myhosts.conf
<Directory "www/https">
AllowOverride none
Require all granted
</Directory>
#Listen 443
<VirtualHost 192.168.155.200:443>
DocumentRoot "/www/https"
ServerName 192.168.155.200
SSLEngine on
SSLProtocol all -SSLv2
SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5:!SEED:!IDEA
SSLCertificateFile /etc/pki/tls/certs/localhost.crt
SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
</VirtualHost>
最后启动服务
systemctl restart httpd
结果
配置访问apache的cgi程序
1.创建一个cgi的目录: /www/cgi
mkdir -p /www/cgi
2.在这个目录下创建一个cgi程序: 注意设置test.cgi程序的权限具备可执行权限
vim test.cgi
#!/bin/bash
printf "Context-type:text/html\n\n"
printf "Hello World for CGI"
3.配置目录权限(让这个目录具有可执行cgi权限的权限,设定cgi的后缀名)
设置虚拟主机(执行cgi程序的虚拟目录)
vim /etc/httpd/conf.d/myhosts.conf
Listen 8001
<Directory "/www/cgi/">
AllowOverride none
Options +ExecCGI
AddHandler cgi-script .cgi .py .pl
require all granted
</Directory>
<VirtualHost 192.168.155.200:8001>
ScriptAlias "/cgi/" "/www/cgi/"
ServerName 192.168.155.200
</VirtualHost>
记得更改权限:chamd +x test.cgi
结果: