python使用https

post请求举例:
    httpsConn = None    
    try:    
        httpsConn = httplib.HTTPSConnection(host)
        sock = socket.create_connection((httpsConn.host, httpsConn.port))
        try:
            httpsConn.sock = ssl.wrap_socket(sock, ca_certs=CERT_FILE, cert_reqs=ssl.CERT_REQUIRED, ssl_version=ssl.PROTOCOL_SSLv3)
            #self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, ssl_version=ssl.PROTOCOL_SSLv3)
        except ssl.SSLError, e:
            print("Trying SSLv3.")
            try:
                httpsConn.sock = ssl.wrap_socket(sock, ca_certs=CERT_FILE, cert_reqs=ssl.CERT_REQUIRED, ssl_version=ssl.PROTOCOL_SSLv23)
                #self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, ssl_version=ssl.PROTOCOL_SSLv23)
            except ssl.SSLError, e:
                print("Trying SSLv23.")
                try:
                    httpsConn.sock = ssl.wrap_socket(sock, ca_certs=CERT_FILE, cert_reqs=ssl.CERT_REQUIRED, ssl_version=ssl.PROTOCOL_TLSv1)
                except ssl.SSLError, e:
                    print("Trying TLSv1.")
                    try:
                        httpsConn.sock = ssl.wrap_socket(sock, ca_certs=CERT_FILE, cert_reqs=ssl.CERT_REQUIRED, ssl_version=ssl.PROTOCOL_SSLv2)
                    except ssl.SSLError, e:
                        print("Trying SSLv2.")        
        
        httpsConn.request("POST", path, body, headers)
        res = httpsConn.getresponse()
        headers = {}
        for k, v in res.getheaders():
            headers[k] = v
        return res.status, headers, res.read()
    except Exception, e:
        import traceback
        print traceback.format_exc()
        return e
    finally:
        if httpsConn:
            httpsConn.close
备注:
如果只有服务器端有私钥,客户端有公钥,则客户端的程序需要指定公钥文件,见代码:httpsConn.sock = ssl.wrap_socket(sock, ca_certs=CERT_FILE, cert_reqs=ssl.CERT_REQUIRED, ssl_version=ssl.PROTOCOL_SSLv3),是通过ca_certs参数指定的,CERT_FILE是文件的路径,保证能够找到即可;如果是是一个文件夹下有多个文件,然后这多个文件都是需要用到的,比如A域名的证书和B域名的证书,A服务器在对接口处理请求的时候,会向B端发请求,如此客户端需要将A域名证书和B域名证书都添加进来,所以只要把文件夹路径设置成ca_certs参数的值即可。
另外,如果不确定SSL的版本,则需要尝试多个不同的SSL版本:ssl.PROTOCOL_TLSv1、ssl_version=ssl.PROTOCOL_SSLv2、ssl_version=ssl.PROTOCOL_SSLv23、ssl_version=ssl.PROTOCOL_SSLv3。
get请求的话,就将httpsConn.request("POST", path, body, headers)中的"POST"换成"GET"就好了,然后body设置为None即可。
 
以下是服务器端代码:
from socket import socket, AF_INET, SOCK_STREAM
import ssl

KEYFILE = 'server_key.pem'   # Private key of the server
CERTFILE = 'server_cert.pem' # Server certificate (given to client)

def echo_client(s):
    while True:
        data = s.recv(8192)
        if data == b'':
            break
        s.send(data)
    s.close()
    print('Connection closed')

def echo_server(address):
    s = socket(AF_INET, SOCK_STREAM)
    s.bind(address)
    s.listen(1)

    # Wrap with an SSL layer requiring client certs
    s_ssl = ssl.wrap_socket(s,
                            keyfile=KEYFILE,
                            certfile=CERTFILE,
                            server_side=True
                            )
    # Wait for connections
    while True:
        try:
            c,a = s_ssl.accept()
            print('Got connection', c, a)
            echo_client(c)
        except Exception as e:
            print('{}: {}'.format(e.__class__.__name__, e))

echo_server(('', 20000))
之后是客户端连接服务器端的例子:
>>> from socket import socket, AF_INET, SOCK_STREAM
>>> import ssl
>>> s = socket(AF_INET, SOCK_STREAM)
>>> s_ssl = ssl.wrap_socket(s, cert_reqs=ssl.CERT_REQUIRED, ca_certs = 'server_cert.pem')
>>> s_ssl.connect(('localhost', 20000))
>>> s_ssl.send(b'Hello World?')
12
>>>s_ssl.recv(8192)
b'Hello World?'
>>>
 
备注:其中 ssl.wrap_socket(s,cert_reqs=ssl.CERT_REQUIRED,ca_certs = 'server_cert.pem') 的ca_certs就是需要在客户端指定的证书,这个是服务器给的公钥证书。
证书的格式:一般有der格式、pem格式,且格式不能单纯通过后缀名去进行判定,比如一个后缀名是crt,就认为其不是pem的格式是错误的。

原文地址:https://www.cnblogs.com/absoluteli/p/13959760.html