|
2.1 TLS/SSL 基本知识
SSL(Secure Sockets Layer 安全套接层)协议,及其继任者TLS(Transport Layer Security传输层安全)协议,是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层对网络连接进行加密,用于保障网络数据传输安全,利用数据加密技术,确保数据在网络传输过程中不会被截取及窃听。
要建立TSL/SSL连接则需要证书文件及其密钥文件,这些证书就是起到了加密的作用,每一次连接都需要通过验证这些证书来进一步确定是否可以继续传输。证书文件可以是由受信任的证书颁发机构(CA机构),验证服务器身份后颁发,或者通过openssl工具生成自签名的证书。在这里笔者选择了使用openssl生成自签名的证书,并掌握了openssl工具的相关使用。
2.2 实现思路
1.写出TLS加密传输代码:基于无加密传输的服务器和客户端代码结构,导入了ssl包,并对代码进行了修改。
2.生成自签名证书文件:实现加密传输需要已认证的证书文件,这里笔者使用了openssl工具生成自签名证书文件。
3.导入证书文件,实现加密传输:加载后证书文件后,在两台电脑或者本机上实现加密传输数据。
2.3 具体操作及遇到的问题
2.3.1 TLS连接的代码:
服务端:
import socket
import ssl
class server_ssl:
def build_listen(self):
# 生成SSL上下文
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
# 加载服务器所用证书和私钥
context.load_cert_chain('server.crt', 'key.pem')
# 监听端口
with socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) as sock:
sock.bind(('10.63.120.14',7777))
sock.listen(5)
# 将socket打包成SSL socket
with context.wrap_socket(sock, server_side=True) as ssock:
while True:
# 接收客户端连接
client_socket, addr = ssock.accept()
msg = client_socket.recv(1024).decode("utf-8")
print(f"receive msg from client {addr}:{msg}")
# 向客户端发送信息
msg = f"yes , you have client_socketect with server.\r\n".encode("utf-8" )
client_socket.send(msg)
client_socket.close()
if __name__ == "__main__":
server = server_ssl()
server.build_listen()
客户端:
import socket
import ssl
class client_ssl:
def send_hello(self,):
# 生成SSL上下文
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
# 加载信任根证书
context.load_verify_locations('ca.crt')
#与服务端建立socket连接
with socket.create_connection(('10.63.120.14',7777)) as sock:
# 将socket打包成SSL socket
# 一定要注意的是这里的server_hostname不是指服务端IP,而是指服务端证书中设置的CN
with context.wrap_socket(sock, server_hostname='127.0.0.1') as ssock:
msg = "do i connect with server ?".encode("utf-8")
ssock.send(msg)
# 接收服务端返回的信息
msg = ssock.recv(1024).decode("utf-8")
print(f"receive msg from server : {msg}")
ssock.close()
if __name__ == "__main__":
client = client_ssl()
client.send_hello()
2.3.2证书的生成
证书的生成这一个问题卡住了笔者很长时间,刚开始笔者不太理解各个证书之间的关系,因为通过查找相关资料笔者发现证书的类型有很多,CA文件,CA密钥,服务器证书文件,服务器证书密钥,客户端证书文件,客户端证书密钥。所以一开始生成这些文件时没有一个很清晰的思路,都是根据网上其他人的生成方式,按照给出的步骤生成,但把这些证书放到程序中时就报错。但问题的关键在于生成的证书文件有问题。于是,笔者把程序中报出的各种错在网上进行搜索,最终在下面这个博客中找到了笔者想要的信息,并解决了证书生成问题:https://blog.csdn.net/gx_1983/article/details/47866537
实现步骤及遇到的问题:
笔者在Ubuntu下安装OpenSSL工具来生成证书文件
(1) 产生CA的key和证书文件
OpenSSL> req -new -x509 -days 365 -extensions v3_ca -keyout ca.key -out ca.crt
该命令将为CA产生一个名字为“ca.key”的key文件和一个名字为“ca.crt”的证书文件。命令执行过程中将需要输入国别、省份(或州)、市、Common Name等参数。开始笔者在填Common Name时随意填写,没注意到这一项需要填写ip地址或者需要访问的网站名。如果不这样设置,那么运行程序连接时将会报错。
(2) 产生一个私钥文件server.key 和证书请求文件server.crs
OpenSSL> genrsa -out server.key 2048
该命令将产生一个不加密的RSA私钥,其中参数“2048”表示私钥的长度
OpenSSL> req -out server.csr -key server.key -new
该命令将使用上一步产生的“server.key”文件为server产生一个签发证书所需要的请求文件:server.csr,使用该文件向CA发送请求才会得到CA签发的证书。
(3) 为server产生一个证书文件
OpenSSL> x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365
该命令将使用CA的密钥文件ca.key,CA的证书文件ca.crt和上一步为server产生证书请求文件server.csr文件这三个文件向CA请求产生一个证书文件,证书文件的名字为:server.crt
生成证书后,笔者在Ubuntu中找到笔者生成的证书文件,并把ca.crt, server.crt,server.key(这是笔者程序中需要的)加载到程序中,但报出下列错误:
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:833)
通过网上的资料,笔者发现这是因为笔者生成的证书没有得到验证,所以通过上述方法生成的证书文件无效。
下面笔者又尝试了另一种方法生成自签名证书:
(1)建立CA文件
1.进入Ubuntu root下建立文件夹,文件夹名称任意
/home/zhong# mkdir key
2.进入到新建立的文件夹key
/home/zhong# cd key
/home/zhong/key#
3.生成CA私钥/
home/zhong/key# openssl genrsa -out ca.key 2048
4.用CA私钥生成CA的证书
openssl req -new -x509 -days 365 -key ca.key -out ca.crt
5.建立CA相应目录进入到key文件夹执行如下命令:
/home/zhong/key# mkdir demoCA
/home/zhong/key# cd demoCA
/home/zhong/key# mkdir newcerts
/home/zhong/key# touch index.txt
/home/zhong/key# echo ‘01’ > serial
(2)生成server端证书
1.进入key文件夹,生成server私钥
/home/zhong/key# openssl genrsa -out server.key 2048
2.使用server私钥生成server端证书请求文件
/home/zhong/key# openssl req -new -key server.key -out server.csr
3.使用server证书请求文件通过CA生成自签名证书
/home/zhong/key# openssl ca -in server.csr -out server.crt -cert ca.crt -keyfile ca.key
4.验证server证书
/home/zhong# openssl verify -CAfile ca.crt server.crt
server.crt: OK
此时生成的证书就是验证成功的证书,查看证书内容,笔者发现上面两种方法生成的server.crt 格式不一样。
用第一种方法得到的server.crt文件没有被验证,其格式为:
-----BEGIN CERTIFICATE-----
MIIDZTCCAk0CCQDKDJZk3KHnmzAN…
…
-----END CERTIFICATE-----
而第二种方法生成已验证的server.crt的格式在原来基础上还增加了Cerificate的内容,包括public_key, Data, subject等参数信息:
Certificate:
…
2.3.3 TLS加密传输的实现
生成了正确的证书文件后,笔者把文件加载到程序中,设置ip地址为当前的ipv4的地址,设置端口,一台电脑先运行服务器,一台电脑再运行客户端,运行成功,结果如下:
服务器:
receive msg from client ('10.63.120.14', 60299):do i connect with server ?
客户端:
receive msg from server : yes , you have client_socketect with server.
参考资料:
https://blog.csdn.net/gx_1983/article/details/47866537
https://blog.csdn.net/houjixin/article/details/24305613 |