Bootstrap

python实现HTTPS通信

python实现HTTPS通信


0x01 前言

之前有一个需要实现基于https通信的连接链路的工具,当时感觉很简单,以为https应该和实现http一样的简单,没想到最后想了好些时间,都没能实现出来,然后看了看网上的一些案例,五花八门,于是就在官方文档看到了ssl模块的使用,但是按照文档也没有实现,*_*! 最后根据https的一些资料和ssl 认证的方式,理清思路,实现了工具。
因此想记录一下,加深对https通信的理解,这里使用的是python。

0x02 HTTPS简述

HTTPS是一种通过计算机网络进行安全通信的传输协议,经由HTTP进行通信,利用SSL/TLS建立全信道,加密数据包。HTTPS使用的主要目的是提供对网站服务器的身份认证,同时保护交换数据的隐私与完整性。
SSL是安全套接层(secure sockets layer),而TLS是SSL的继任者,叫传输层安全(transport layer security)。是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层对网络连接进行加密。

PS:TLS是传输层加密协议,前身是SSL协议,由网景公司1995年发布,有时候两者不区分。

HTTPS协议比HTTP更安全的原因是多了SSL协议,SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持。https的s也就是指SSL协议。

SSL/TLS协议提供的服务主要有:

认证用户和服务器,确保数据发送到正确的客户机和服务器;
加密数据以防止数据中途被窃取;
维护数据的完整性,确保数据在传输过程中不被改变

SSL的两种认证方式
在这里插入图片描述
在这里插入图片描述

0x03 python 官方文档ssl 模块

上面介绍了SSL的情况,同时也了解到了两种认证模式,现在来看看python的官方文档对SSL的一些实现。
首先是生成CA证书,CA证书中包含私钥和公钥,而公钥则是附带在证书信息中,可以公开的。
这边可以使用的是python的CA证书
以下是python官方文档SSL介绍关于CA证书的介绍
17.3.4. Certificates
CA证书通常包含是公钥/私钥两个部分,公钥中含有证书的信息。在这个https通信中,每个主体(可能是一台主机,一个人,或者一个组织)都会被分配唯一的两个加密密钥,一个是可以公开的密钥,成为公钥,另一个是保密的密钥,成为私钥。这两个密钥是有关联的,在传输信息过程中,使用公钥加密数据,需要用自己的密钥进行解密数据。另外,私钥只有发布方,即HTTPS服务端知道私钥,但是,任何人都可以看到服务端发布的公钥,并用公钥解密证书的声明和其他信息进行比较,证书中还包含有其证书有效期限的信息,具体表现为"notBefore","notAfter"两个字段。
在使用python证书时,客户端或者服务器能使用证书来证明自身,同时获得网络连接中另一端的证书,并且验证获得的证书是否符合要求,如果验证失败在会触发异常。验证的过程是通过底层的OpenSSL框架自动完成的,应用程序不需要关心这种机制,但是需要提供CA证书。
Python使用文件来包含证书。它们应该被格式化为“PEM”(参见RFC 1422),这是一个base-64编码的表单,包含一个标题行和一个页脚行

如果您要创建一个提供ssl加密连接服务的服务器,您将需要获得该服务的证书。有许多方法可以获得适当的证书,比如从证书颁发机构购买证书。另一种常见做法是生成自签名证书。最简单的方法是使用OpenSSL包生成证书,
生成证书

使用openssl生成证书。

openssl req -new -x509 -days 365 -nodes -out cert.pem -keyout cert.pem

你会的到以下的内容

-----BEGIN RSA PRIVATE KEY-----  # 私钥内容
... (private key in base64 encoding) ...
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----  # 证书信息
... (certificate in base64 PEM encoding) ...
-----END CERTIFICATE-----

0x04 python实现https通信(单向认证)

HTTPS客户端 https_client.py

import socket, ssl, pprint, time
 
HOST = '127.0.0.1'
PORT = 10023
BUFSIZE = 1024
ADDR = (HOST, PORT)
 
# 创建socket套接字
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 从服务端获取一个CA证书
ssl_sock = ssl.wrap_socket(s, ca_certs="cert.pem", cert_reqs=ssl.CERT_REQUIRED)
# socket连接
ssl_sock.connect(ADDR)
 
# note that closing the SSLSocket will also close the underlying socket
pprint.pprint(ssl_sock.getpeercert())
 
while True:
    data = raw_input('> ')
    if not data:
        break
    ssl_sock.send(data)
    data = ssl_sock.recv(BUFSIZE)
    if not data:
        break
    print
    data
ssl_sock.close()

HTTPS服务端 https_server.py

import socket, ssl, time
 
HOST = ''
PORT = 10023
BUFSIZE = 1024
ADDR = (HOST, PORT)
# 创建 socket 套接字 
bindsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定socket
bindsocket.bind(ADDR)
# 监听socket 
bindsocket.listen(5)
 
print("listen on 127.0.0.1:10023") 
def do_something(connstream, data):
    return len(data)
 
 
def deal_with_client(connstream):
    data = connstream.recv(BUFSIZE)
    # empty data means the client is finished with us
    while data:
        backdata = do_something(connstream, data)
        if not backdata:
            # we'll assume do_something returns False
            # when we're finished with client
            break
        connstream.send(str(backdata))
        data = connstream.recv(BUFSIZE)
        print(data)
 
 
while True:
    newsocket, fromaddr = bindsocket.accept()
    print("socket accept one client from %s ", fromaddr)
    # 使用ssl.wrao_socket函数。这里使用TSLv1
    connstream = ssl.wrap_socket(newsocket, "key.pem", "cert.pem", server_side=True, ssl_version=ssl.PROTOCOL_TLSv1)
 
    try:
        deal_with_client(connstream)
    finally:
        connstream.shutdown(socket.SHUT_RDWR)
        connstream.close()

在这里插入图片描述

0x05 参考

官方文档ssl模块 https://docs.python.org/2/library/ssl.html
HTTPS 详述 https://blog.csdn.net/xiaoming100001/article/details/81109617


;