• Python开启ssl证书校验


    Python- SSL文档:https://docs.python.org/dev/library/ssl.html

    有啥不懂,看文档呗

    一、介绍

    1、主要方法介绍

    SSLContext.load_cert_chain(certfile, keyfile=None, password=None):
        """
        加载私钥和相应的证书。证书文件字符串必须是PEM格式的单个文件的路径,其中包含证书以及建立证书真实性所需的任何数量的CA证书。
        如果存在keyfile字符串,则必须指向包含中私钥的文件。否则,私钥也将从证书文件中获取。
        password参数可以是一个要调用的函数,以获取用于解密私钥的密码。只有在私钥已加密并且需要密码时,才会调用它。
        它将在没有参数的情况下调用,并且它应该返回字符串、字节或字节数组。如果返回值是字符串,在使用它解密密钥之前,它将被编码为UTF-8。或者,字符串、字节或字节数组值可以直接作为密码参数提供。
        如果私钥未加密,且不需要密码,则将忽略此密钥。
        如果未指定password参数,并且需要密码,则将使用OpenSSL内置的密码提示机制以交互方式提示用户输入密码。
        如果私钥与证书不匹配,将引发SSLError。
        """
    
    
    SSLContext.load_verify_locations(cafile=None, capath=None, cadata=None):
        """
        加载一组“证书颁发机构”(CA)证书,用于在验证模式不是CERT_NONE时验证其他对等体的证书。cafile和capath必须至少指定一个。
        此方法还可以加载PEM或DER格式的证书撤销列表(CRL)。为了使用CRL,必须正确配置SSLContext.verify_flags。
        cafile字符串(如果存在)是PEM格式的级联CA证书文件的路径。有关如何在此文件中安排证书的更多信息,请参阅证书的讨论。
        capath字符串(如果存在)是指向包含多个PEM格式CA证书的目录的路径,遵循OpenSSL特定布局。
        cadata对象(如果存在)是一个或多个PEM编码证书的ASCII字符串,或DER编码证书的类似字节的对象。与capath一样,PEM编码证书周围的额外行将被忽略,但必须至少存在一个证书。
        """
    
    
    SSLContext.get_ca_certs(binary_form=False):
        """
        获取加载的“证书颁发机构”(CA)证书的列表。
        如果二进制形式参数为False,则每个列表条目都是一个dict,就像SSLSocket.getpeercert()的输出一样。
        否则,该方法返回DER编码的证书列表。返回的列表不包含来自capath的证书,除非证书是由SSL连接请求和加载的。
        """
        
       
    SSLContext.set_ciphers(ciphers):
        """
        为使用此上下文创建的套接字设置可用密码。它应该是OpenSSL密码列表格式的字符串。
        如果无法选择密码(因为编译时选项或其他配置禁止使用所有指定的密码),将引发SSLError。
        """

    2、主要模式介绍

    SSL上下文

    class ssl.SSLContext(protocol=None)

    创建新的SSL上下文。您可以传递协议,该协议必须是本模块中定义的协议常数之一。该参数指定要使用的SSL协议版本。通常,服务器选择特定的协议版本,客户端必须适应服务器的选择。大多数版本都无法与其他版本互操作。如果未指定,则默认为PROTOCOL_TLS;它与其他版本的兼容性最好。

    下面的表格显示了客户端(下方)中的哪些版本可以连接到服务器(顶部)中的哪些版本:

    client / server

    SSLv2

    SSLv3

    TLS 3

    TLSv1

    TLSv1.1

    TLSv1.2

    SSLv2

    yes

    no

    no 1

    no

    no

    no

    SSLv3

    no

    yes

    no 2

    no

    no

    no

    TLS (SSLv233

    no 1

    no 2

    yes

    yes

    yes

    yes

    TLSv1

    no

    no

    yes

    yes

    no

    no

    TLSv1.1

    no

    no

    yes

    no

    yes

    no

    TLSv1.2

    no

    no

    yes

    no

    no

    yes

    SSLContext.verify_mode:认证模式
    ssl.CERT_NONE
    SSLContext.verify_mode的可能值,或包装_socket()的cert_reqs参数。除PROTOCOL_TLS_CLENT外,它是默认模式。
    对于客户端套接字,几乎接受任何证书。验证错误,如不受信任或过期的证书,将被忽略,并且不会中止TLS/SSL握手。
    在服务器模式下,没有向客户端请求证书,因此客户端不会发送任何客户端证书身份验证。


    ssl.CERT_OPTIONAL
    SSLContext.verify_mode的可能值,或包装_socket()的cert_reqs参数。
    在客户端模式下,CERT_OPTIONAL与CERT_REQUIRED的含义相同。建议对客户端套接字使用CERT_REQUIRED。
    在服务器模式下,向客户端发送客户端证书请求。客户端可以忽略请求,也可以发送证书,以便执行TLS客户端证书身份验证。
    如果客户端选择发送证书,则会对其进行验证。任何验证错误都会立即中止TLS握手。
    使用此设置需要将一组有效的CA证书传递给SSLContext.load_verify_locations(),或作为ca_certs参数的值传递给包装_socket()。


    ssl.CERT_REQUIRED
    SSLContext.verify_mode的可能值,或包装_socket()的cert_reqs参数。
    在此模式下,需要从套接字连接的另一端获得证书;如果未提供证书或其验证失败,将引发SSL错误。
    此模式不足以在客户端模式下验证证书,因为它与主机名不匹配。还必须启用check_hostname才能验证证书的真实性。PROTOCOL_TLS_CLENT使用CERT_REQUIRED,默认情况下启用check_hostname。
    对于服务器套接字,此模式提供强制性的TLS客户端证书身份验证。服务端向客户端发起客户端证书请求发,客户端必须提供有效的可信证书。
    使用此设置需要将一组有效的CA证书传递给SSLContext.load_verify_locations(),或作为ca_certs参数的值传递给包装_socket()。

    SSLContext.verify_flags:吊销列表校验
    ssl.VERIFY_DEFAULT
    SSLContext.verify_flags的可能值。在此模式下,不检查证书吊销列表(CRL)。默认情况下,OpenSSL既不要求也不验证CRL。


    ssl.VERIFY_CRL_CHECK_LEAF
    SSLContext.verify_flags的可能值。在这种模式下,只检查对端证书,不检查中间CA证书。
    该模式需要由对等证书颁发者(其直接祖先CA)签名的有效CRL。如果没有正确的CRL加载SSLContext.load_verify_locations,则验证将失败。


    ssl.VERIFY_CRL_CHECK_CHAIN
    SSLContext.verify_flags的可能值,在这种模式下,会检查对端证书链中所有证书的CRL。

    二、示例

    1、服务端

    import ssl
    from flask import Flask
    
    app = Flask(__name__)
    
    
    @app.route("/", methods=["GET"])
    def hello_world():
        return "hello World!"
    
    
    def get_ssl_context():
        # ca根证书
        ca_crt_path = r"E:\MyData\TestProjects\TestPython36\ca\root.crt"
        # 吊销列表
        server_crl_path = r"E:\MyData\TestProjects\TestPython36\ca\server.crl"
        # 服务端证书和秘钥
        server_crt_path = r"E:\MyData\TestProjects\TestPython36\ca\server.crt"
        server_key_path = r"E:\MyData\TestProjects\TestPython36\ca\server.key"
        # 创建ssl上下文
        ssl_context = ssl.SSLContext(protocol=ssl.PROTOCOL_TLSv1_2)
        # 选择认证模式:作为服务端,此选项为服务端必须校验客户端的证书,双向认证
        ssl_context.verify_mode = ssl.CERT_REQUIRED
        # 不校验域名
        ssl_context.check_hostname = False
        # 吊销列表校验:只检查对端证书,不检查中间CA证书
        # ssl_context.verify_flags = ssl.VERIFY_CRL_CHECK_LEAF
        # ssl_context.load_verify_locations(server_crl_path)
        # 加密套件
        ssl_context.set_ciphers = ("HIGH:!SSLv3:!TLSv1:!aNULL:@STRENGTH")
        # 加载ca根证书
        ssl_context.load_verify_locations(ca_crt_path)
        # 加载服务端证书和秘钥,用于通信时携带
        ssl_context.load_cert_chain(certfile=server_crt_path,
                                    keyfile=server_key_path)
    
        return ssl_context
    
    
    if __name__ == '__main__':
        ssl_context = get_ssl_context()
        app.run(host="127.0.0.1", port=5000, ssl_context=ssl_context)

    2、客户端

    import ssl
    from urllib import request
    
    
    def get_ssl_context():
        # ca根证书
        ca_crt_path = r"E:\MyData\TestProjects\TestPython36\ca\root.crt"
        # 吊销列表
        client_crl_path = r"E:\MyData\TestProjects\TestPython36\ca\client.crl"
        # 客户端证书和秘钥
        client_crt_path = r"E:\MyData\TestProjects\TestPython36\ca\client.crt"
        client_key_path = r"E:\MyData\TestProjects\TestPython36\ca\client.key"
        # 创建ssl上下文
        ssl_context = ssl.SSLContext(protocol=ssl.PROTOCOL_TLSv1_2)
        # 选择认证模式:作为客户端,此选项为客户端必须校验服务端的证书
        ssl_context.verify_mode = ssl.CERT_REQUIRED
        # 不校验域名
        ssl_context.check_hostname = False
        # 吊销列表校验:只检查对端证书,不检查中间CA证书
        # ssl_context.verify_flags = ssl.VERIFY_CRL_CHECK_LEAF
        # ssl_context.load_verify_locations(client_crl_path)
        # 加载ca根证书
        ssl_context.load_verify_locations(ca_crt_path)
        # 加载客户端证书和秘钥,用于通信时携带
        ssl_context.load_cert_chain(certfile=client_crt_path,
                                    keyfile=client_key_path)
    
        return ssl_context
    
    
    if __name__ == '__main__':
        """当我们需要加载吊销列表,ca根证书等等的时候,需要使用urlopen的方式"""
        ssl_context = get_ssl_context()
        req = request.Request("https://127.0.0.1:5000/", method="GET")
    
        with request.urlopen(req, context=ssl_context) as response:
            print(response.msg)
            print(response.read().decode("utf-8"))
            print(response.getcode())
  • 相关阅读:
    iOS无限循环滚动scrollview
    SDWebImage实现原理(怎么实现图片缓存器)
    CocoaPods第三方库管理 iOS
    什么时候会报unrecognized selector的异常?
    iOS提交后申请加急审核
    iOS 个人账号 iOS APP Development 灰色不可选
    Xcode6 管理provisioning profile
    iOS苹果推送功能实现步骤
    蓝桥杯 幸运数
    hihocoder编程练习赛52-3 部门聚会
  • 原文地址:https://www.cnblogs.com/Zzbj/p/15868210.html
Copyright © 2020-2023  润新知