导航菜单

  • 1.vector
  • 2.milvus
  • 3.pymilvus
  • 4.rag
  • 5.rag_measure
  • ragflow
  • heapq
  • HNSW
  • cosine_similarity
  • math
  • typing
  • etcd
  • minio
  • collections
  • jieba
  • random
  • beautifulsoup4
  • chromadb
  • sentence_transformers
  • numpy
  • lxml
  • openpyxl
  • PyMuPDF
  • python-docx
  • requests
  • python-pptx
  • text_splitter
  • all-MiniLM-L6-v2
  • openai
  • llm
  • BPETokenizer
  • Flask
  • RAGAS
  • BagofWords
  • langchain
  • Pydantic
  • abc
  • faiss
  • MMR
  • scikit-learn
  • Runnable
  • PromptEngineering
  • dataclasses
  • LaTeX
  • rank_bm25
  • TF-IDF
  • asyncio
  • sqlalchemy
  • fastapi
  • Starlette
  • uvicorn
  • argparse
  • Generic
  • ssl
  • urllib
  • python-dotenv
  • RRF
  • CrossEncoder
  • Lost-in-the-middle
  • Jinja2
  • logger
  • io
  • venv
  • concurrent
  • parameter
  • SSE
  • 1. ssl 模块是什么?
    • 1.1 为什么需要 ssl?
    • 1.2 基本导入
  • 2. 前置知识
    • 2.1 SSL/TLS 基础
    • 2.2 证书基础
    • 2.3 socket 基础
  • 3. SSL 上下文(Context)
    • 3.1 创建默认上下文
    • 3.2 创建特定用途的上下文
  • 4. 证书验证
    • 4.1 验证模式
    • 4.2 不验证证书(仅用于测试)
  • 5. 创建 HTTPS 客户端
    • 5.1 简单的 HTTPS 连接
    • 5.2 使用 with 语句(推荐)
    • 5.3 检查证书信息
  • 6. 错误处理
  • 7. 实际应用示例
    • 7.1 简单的 HTTPS 请求函数
    • 7.2 检查服务器证书
  • 8. 常见问题
    • 8.1 如何处理证书验证错误?
    • 8.2 如何跳过证书验证(仅用于测试)?
  • 9. 总结
    • 9.1 核心概念回顾
    • 9.2 基本使用流程
    • 9.3 使用 ssl 模块的好处

1. ssl 模块是什么? #

ssl 是 Python 的标准库,用于实现网络通信的安全加密。它提供了 SSL/TLS 协议的支持,让你可以创建安全的网络连接(如 HTTPS)。

1.1 为什么需要 ssl? #

在网络上传输数据时,如果不加密,数据可能被窃听或篡改。SSL/TLS 提供了加密和身份验证,确保数据安全传输。

简单理解:

  • HTTP:不加密的网页传输(不安全)
  • HTTPS:加密的网页传输(安全)
  • ssl 模块:Python 中实现 HTTPS 的工具

ssl 模块的用途:

  1. 创建 HTTPS 客户端:安全地访问 HTTPS 网站
  2. 创建 HTTPS 服务器:提供安全的 Web 服务
  3. 验证证书:确保连接的是正确的服务器
  4. 加密通信:保护数据传输不被窃听

1.2 基本导入 #

# 导入 ssl 模块
import ssl

说明:

  • ssl 是 Python 标准库,无需安装
  • 通常与 socket 模块一起使用

2. 前置知识 #

在学习 ssl 模块之前,你需要了解以下基础知识。

2.1 SSL/TLS 基础 #

SSL(Secure Sockets Layer) 和 TLS(Transport Layer Security) 是用于加密网络通信的协议。

简单理解:

  • SSL:旧版本的加密协议(已废弃)
  • TLS:新版本的加密协议(现在使用)
  • 通常统称为 SSL/TLS

SSL/TLS 的作用:

  1. 加密数据:防止数据被窃听
  2. 身份验证:验证服务器身份(通过证书)
  3. 数据完整性:确保数据不被篡改

2.2 证书基础 #

证书(Certificate) 用于验证服务器的身份,类似于身份证。

证书的组成部分:

  • 主题(Subject):证书的所有者(如域名)
  • 颁发者(Issuer):颁发证书的机构(CA)
  • 有效期:证书的有效时间
  • 公钥:用于加密的公钥

简单理解:

  • 访问 https://www.example.com 时,服务器会出示证书
  • 证书证明这个服务器确实是 www.example.com
  • 浏览器会验证证书是否有效

2.3 socket 基础 #

socket 是网络编程的基础,用于创建网络连接。

# 导入 socket 模块
import socket

# 创建 TCP 套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 连接到服务器
sock.connect(('www.example.com', 80))

# 发送数据
sock.send(b'GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n')

# 接收数据
data = sock.recv(4096)

# 关闭连接
sock.close()

说明:

  • socket 用于创建网络连接
  • ssl 模块将普通的 socket 包装为安全的 SSL socket

3. SSL 上下文(Context) #

SSL 上下文(Context) 是 ssl 模块的核心,用于配置 SSL/TLS 参数。

3.1 创建默认上下文 #

最简单的方式是创建默认上下文,它会自动配置安全的默认值。

# 导入 ssl 模块
import ssl

# 创建默认 SSL 上下文
# create_default_context() 会创建一个安全的默认配置
# 包括:验证证书、检查主机名、加载系统 CA 证书等
context = ssl.create_default_context()

# 打印上下文信息
print(f"上下文已创建:{context}")
print(f"验证模式:{context.verify_mode}")
print(f"检查主机名:{context.check_hostname}")

说明:

  • create_default_context() 创建默认的 SSL 上下文
  • 默认配置是安全的(会验证证书)
  • 适合大多数场景

3.2 创建特定用途的上下文 #

可以创建用于客户端或服务器端的上下文。

# 导入 ssl 模块
import ssl

# 创建客户端上下文(用于连接服务器)
# Purpose.SERVER_AUTH 表示用于验证服务器身份
client_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
print(f"客户端上下文:{client_context}")

# 创建服务器端上下文(用于接受客户端连接)
# Purpose.CLIENT_AUTH 表示用于验证客户端身份
server_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
print(f"服务器端上下文:{server_context}")

# 主程序入口
if __name__ == "__main__":
    print("上下文创建成功")

说明:

  • Purpose.SERVER_AUTH:客户端使用,验证服务器
  • Purpose.CLIENT_AUTH:服务器使用,验证客户端
  • 大多数情况下使用默认上下文即可

4. 证书验证 #

证书验证是确保连接安全的重要步骤。

4.1 验证模式 #

SSL 上下文有不同的验证模式。

# 导入 ssl 模块
import ssl

# 创建默认上下文
context = ssl.create_default_context()

# 设置验证模式
# CERT_REQUIRED:必须验证证书(推荐,最安全)
context.verify_mode = ssl.CERT_REQUIRED

# CERT_OPTIONAL:可选验证(不推荐)
# context.verify_mode = ssl.CERT_OPTIONAL

# CERT_NONE:不验证证书(不安全!仅用于测试)
# context.verify_mode = ssl.CERT_NONE

# 检查主机名
# check_hostname=True 会验证证书中的主机名是否匹配
context.check_hostname = True

# 打印配置
print(f"验证模式:{context.verify_mode}")
print(f"检查主机名:{context.check_hostname}")

# 主程序入口
if __name__ == "__main__":
    print("证书验证配置完成")

说明:

  • CERT_REQUIRED:必须验证证书(推荐)
  • CERT_NONE:不验证证书(不安全,仅用于测试)
  • check_hostname:验证证书中的主机名

4.2 不验证证书(仅用于测试) #

在某些测试场景中,可能需要跳过证书验证(不推荐用于生产环境)。

# 导入 ssl 模块
import ssl

# 创建默认上下文
context = ssl.create_default_context()

# 禁用证书验证(仅用于测试!)
# 生产环境不应该这样做,存在安全风险
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE

# 打印配置
print(f"验证模式:{context.verify_mode}(不验证)")
print(f"检查主机名:{context.check_hostname}(不检查)")
print("警告:此配置不安全,仅用于测试!")

# 主程序入口
if __name__ == "__main__":
    print("不验证证书的上下文已创建(仅用于测试)")

警告:不验证证书存在安全风险,仅用于测试环境。

5. 创建 HTTPS 客户端 #

使用 ssl 模块创建 HTTPS 客户端,安全地访问 HTTPS 网站。

5.1 简单的 HTTPS 连接 #

# 导入必要的模块
import socket
import ssl

# 定义要连接的服务器
hostname = 'www.example.com'
port = 443  # HTTPS 默认端口

# 创建 SSL 上下文
# create_default_context() 会创建安全的默认配置
context = ssl.create_default_context()

# 创建 TCP 套接字
# socket.create_connection() 创建并连接到服务器
sock = socket.create_connection((hostname, port))

try:
    # 将普通套接字包装为 SSL 套接字
    # wrap_socket() 将普通 socket 转换为 SSL socket
    # server_hostname 用于 SNI(服务器名称指示)
    ssl_sock = context.wrap_socket(
        sock,
        server_hostname=hostname
    )

    # 发送 HTTP 请求
    # 构建简单的 HTTP GET 请求
    request = f'GET / HTTP/1.1\r\nHost: {hostname}\r\n\r\n'
    ssl_sock.send(request.encode())

    # 接收响应
    # recv() 接收数据(最多 4096 字节)
    response = ssl_sock.recv(4096)

    # 打印响应(前 500 个字符)
    print("响应内容(前 500 字符):")
    print(response.decode()[:500])

    # 获取证书信息
    cert = ssl_sock.getpeercert()
    if cert:
        print(f"\n证书信息:")
        print(f"  主题:{cert.get('subject')}")
        print(f"  颁发者:{cert.get('issuer')}")

    # 获取加密信息
    cipher = ssl_sock.cipher()
    if cipher:
        print(f"\n加密套件:{cipher[0]}")
        print(f"协议版本:{ssl_sock.version()}")

finally:
    # 关闭连接
    ssl_sock.close()
    sock.close()

说明:

  • socket.create_connection() 创建 TCP 连接
  • context.wrap_socket() 将普通 socket 包装为 SSL socket
  • server_hostname 用于 SNI(告诉服务器要访问哪个域名)
  • ssl_sock.getpeercert() 获取服务器证书信息

5.2 使用 with 语句(推荐) #

使用 with 语句可以自动管理资源,更安全。

# 导入必要的模块
import socket
import ssl

# 定义要连接的服务器
hostname = 'www.example.com'
port = 443

# 创建 SSL 上下文
context = ssl.create_default_context()

# 使用 with 语句自动管理资源
# 连接关闭时会自动清理
with socket.create_connection((hostname, port)) as sock:
    with context.wrap_socket(sock, server_hostname=hostname) as ssl_sock:
        # 发送 HTTP 请求
        request = f'GET / HTTP/1.1\r\nHost: {hostname}\r\n\r\n'
        ssl_sock.send(request.encode())

        # 接收响应
        response = ssl_sock.recv(4096)

        # 打印响应(前 300 个字符)
        print("响应内容(前 300 字符):")
        print(response.decode()[:300])

        # 获取证书信息
        cert = ssl_sock.getpeercert()
        if cert:
            print(f"\n✓ 证书验证通过")
            print(f"  主题:{cert.get('subject')}")

说明:

  • with 语句自动管理资源
  • 退出 with 块时自动关闭连接
  • 更安全,不会忘记关闭连接

5.3 检查证书信息 #

可以检查服务器的证书信息,确保连接安全。

# 导入必要的模块
import socket
import ssl

# 定义要检查的服务器
hostname = 'www.example.com'
port = 443

# 创建 SSL 上下文
context = ssl.create_default_context()

# 连接到服务器并检查证书
try:
    with socket.create_connection((hostname, port), timeout=5) as sock:
        with context.wrap_socket(sock, server_hostname=hostname) as ssl_sock:
            # 获取证书
            cert = ssl_sock.getpeercert()

            if cert:
                print(f"主机名:{hostname}")
                print(f"\n证书信息:")

                # 解析主题(证书所有者)
                # subject 是一个元组列表,需要转换为字典
                subject = dict(x[0] for x in cert.get('subject', []))
                print(f"  主题:{subject}")

                # 解析颁发者(CA 机构)
                issuer = dict(x[0] for x in cert.get('issuer', []))
                print(f"  颁发者:{issuer}")

                # 有效期
                print(f"  生效时间:{cert.get('notBefore')}")
                print(f"  过期时间:{cert.get('notAfter')}")

                # 替代名称(SAN)
                if 'subjectAltName' in cert:
                    print(f"  替代名称:{cert['subjectAltName']}")

                # 加密信息
                cipher = ssl_sock.cipher()
                if cipher:
                    print(f"\n加密信息:")
                    print(f"  加密套件:{cipher[0]}")
                    print(f"  协议版本:{ssl_sock.version()}")

                print(f"\n✓ 证书验证通过,连接安全")
            else:
                print("未收到证书")

except ssl.SSLError as e:
    print(f"SSL 错误:{e}")
except Exception as e:
    print(f"错误:{e}")

说明:

  • getpeercert() 获取服务器证书
  • 证书信息包括主题、颁发者、有效期等
  • 可以检查证书是否有效

6. 错误处理 #

网络连接可能失败,需要正确处理各种异常。

# 导入必要的模块
import socket
import ssl

# 定义安全的 SSL 连接函数
def safe_ssl_connect(hostname, port=443):
    """安全的 SSL 连接,包含错误处理"""
    try:
        # 创建 SSL 上下文
        context = ssl.create_default_context()

        # 创建连接
        with socket.create_connection((hostname, port), timeout=10) as sock:
            with context.wrap_socket(sock, server_hostname=hostname) as ssl_sock:
                # 返回 SSL 套接字
                return ssl_sock

    except ssl.SSLCertVerificationError as e:
        # 证书验证失败
        print(f"证书验证失败:{e}")
        print("可能的原因:")
        print("  - 证书已过期")
        print("  - 证书不匹配")
        print("  - 证书链不完整")
        raise
    except ssl.SSLError as e:
        # SSL 错误
        print(f"SSL 错误:{e}")
        if 'CERTIFICATE_VERIFY_FAILED' in str(e):
            print("可能是自签名证书或证书链不完整")
        raise
    except socket.timeout:
        # 连接超时
        print("连接超时:服务器没有响应")
        raise
    except ConnectionRefusedError:
        # 连接被拒绝
        print("连接被拒绝:服务器可能未运行或端口错误")
        raise
    except Exception as e:
        # 其他错误
        print(f"未知错误:{e}")
        raise

# 主程序入口
if __name__ == "__main__":
    # 测试连接
    try:
        ssl_sock = safe_ssl_connect('www.example.com')
        print("✓ 连接成功")

        # 获取证书信息
        cert = ssl_sock.getpeercert()
        if cert:
            print(f"✓ 证书验证通过")

        ssl_sock.close()
    except Exception as e:
        print(f"✗ 连接失败:{e}")

说明:

  • SSLCertVerificationError:证书验证失败
  • SSLError:SSL 协议错误
  • socket.timeout:连接超时
  • ConnectionRefusedError:连接被拒绝

7. 实际应用示例 #

7.1 简单的 HTTPS 请求函数 #

创建一个简单的函数来发送 HTTPS 请求。

# 导入必要的模块
import socket
import ssl
import urllib.parse

# 定义 HTTPS 请求函数
def https_request(url, method='GET', data=None, headers=None):
    """发送 HTTPS 请求"""
    # 解析 URL
    # urlparse() 解析 URL 的各个组成部分
    parsed = urllib.parse.urlparse(url)
    hostname = parsed.hostname
    port = parsed.port or 443  # 如果没有指定端口,使用 443(HTTPS 默认端口)
    path = parsed.path or '/'  # 如果没有指定路径,使用根路径

    # 创建 SSL 上下文
    context = ssl.create_default_context()

    # 创建 TCP 连接
    sock = socket.create_connection((hostname, port))

    try:
        # 包装为 SSL 套接字
        ssl_sock = context.wrap_socket(
            sock,
            server_hostname=hostname
        )

        # 构建 HTTP 请求
        # HTTP 请求格式:方法 路径 协议版本
        request = f'{method} {path} HTTP/1.1\r\n'
        request += f'Host: {hostname}\r\n'
        request += 'Connection: close\r\n'

        # 添加自定义请求头
        if headers:
            for key, value in headers.items():
                request += f'{key}: {value}\r\n'

        # 添加请求体(如果有)
        if data:
            request += f'Content-Length: {len(data)}\r\n'
            request += '\r\n'
            request += data
        else:
            request += '\r\n'

        # 发送请求
        ssl_sock.send(request.encode())

        # 接收响应
        response = b''
        while True:
            chunk = ssl_sock.recv(4096)
            if not chunk:
                break
            response += chunk

        # 返回响应(解码为字符串)
        return response.decode()

    finally:
        # 关闭连接
        ssl_sock.close()
        sock.close()

# 主程序入口
if __name__ == "__main__":
    # 发送 GET 请求
    # httpbin.org 是一个用于测试 HTTP 请求的网站
    response = https_request('https://httpbin.org/get')
    print("GET 请求响应:")
    print(response[:500])  # 打印前 500 个字符

说明:

  • urlparse() 解析 URL
  • 构建 HTTP 请求字符串
  • 发送请求并接收响应

7.2 检查服务器证书 #

创建一个函数来检查服务器的证书信息。

# 导入必要的模块
import socket
import ssl

# 定义检查证书的函数
def check_certificate(hostname, port=443):
    """检查服务器证书"""
    # 创建 SSL 上下文
    context = ssl.create_default_context()

    try:
        # 连接到服务器
        with socket.create_connection((hostname, port), timeout=5) as sock:
            with context.wrap_socket(sock, server_hostname=hostname) as ssl_sock:
                # 获取证书
                cert = ssl_sock.getpeercert()

                if cert:
                    print(f"主机名:{hostname}")
                    print(f"\n证书信息:")

                    # 解析主题
                    subject = dict(x[0] for x in cert.get('subject', []))
                    print(f"  主题:{subject}")

                    # 解析颁发者
                    issuer = dict(x[0] for x in cert.get('issuer', []))
                    print(f"  颁发者:{issuer}")

                    # 有效期
                    print(f"  生效时间:{cert.get('notBefore')}")
                    print(f"  过期时间:{cert.get('notAfter')}")

                    # 替代名称
                    if 'subjectAltName' in cert:
                        print(f"  替代名称:{cert['subjectAltName']}")

                    # 加密信息
                    cipher = ssl_sock.cipher()
                    if cipher:
                        print(f"\n加密信息:")
                        print(f"  加密套件:{cipher[0]}")
                        print(f"  协议版本:{ssl_sock.version()}")

                    print(f"\n✓ 证书验证通过")
                    return True
                else:
                    print("未收到证书")
                    return False

    except ssl.SSLCertVerificationError as e:
        # 证书验证失败
        print(f"✗ 证书验证失败:{e}")
        return False
    except Exception as e:
        # 其他错误
        print(f"✗ 错误:{e}")
        return False

# 主程序入口
if __name__ == "__main__":
    # 检查证书
    check_certificate('www.example.com')

说明:

  • 连接到服务器并获取证书
  • 解析并显示证书信息
  • 检查证书是否有效

8. 常见问题 #

8.1 如何处理证书验证错误? #

如果遇到证书验证错误,可以:

  1. 检查证书是否有效:证书可能已过期
  2. 检查主机名是否匹配:证书中的域名必须匹配
  3. 检查证书链:可能需要完整的证书链
# 导入必要的模块
import socket
import ssl

# 处理证书验证错误
def connect_with_error_handling(hostname, port=443):
    """连接并处理证书错误"""
    # 创建 SSL 上下文
    context = ssl.create_default_context()

    try:
        with socket.create_connection((hostname, port), timeout=5) as sock:
            with context.wrap_socket(sock, server_hostname=hostname) as ssl_sock:
                print(f"✓ 成功连接到 {hostname}")
                return ssl_sock
    except ssl.SSLCertVerificationError as e:
        print(f"证书验证失败:{e}")
        print("\n可能的解决方案:")
        print("1. 检查证书是否过期")
        print("2. 检查主机名是否匹配")
        print("3. 检查证书链是否完整")
        print("4. 如果是自签名证书,需要添加 CA 证书")
        raise
    except Exception as e:
        print(f"连接失败:{e}")
        raise

# 主程序入口
if __name__ == "__main__":
    try:
        ssl_sock = connect_with_error_handling('www.example.com')
        ssl_sock.close()
    except:
        pass

8.2 如何跳过证书验证(仅用于测试)? #

在某些测试场景中,可能需要跳过证书验证(不推荐用于生产环境)。

# 导入必要的模块
import socket
import ssl

# 创建不验证证书的上下文(仅用于测试!)
def create_unverified_context():
    """创建不验证证书的上下文(仅用于测试)"""
    # 创建默认上下文
    context = ssl.create_default_context()

    # 禁用证书验证(不安全!)
    context.check_hostname = False
    context.verify_mode = ssl.CERT_NONE

    print("警告:此配置不安全,仅用于测试!")
    return context

# 主程序入口
if __name__ == "__main__":
    # 创建不验证证书的上下文
    context = create_unverified_context()

    # 连接到服务器(不会验证证书)
    try:
        with socket.create_connection(('www.example.com', 443)) as sock:
            with context.wrap_socket(sock, server_hostname='www.example.com') as ssl_sock:
                print("连接成功(未验证证书)")
    except Exception as e:
        print(f"连接失败:{e}")

警告:不验证证书存在安全风险,仅用于测试环境。

9. 总结 #

9.1 核心概念回顾 #

  • ssl 模块:Python 标准库,用于实现 SSL/TLS 加密
  • SSL 上下文:配置 SSL/TLS 参数的对象
  • 证书验证:确保连接的是正确的服务器
  • wrap_socket:将普通 socket 包装为 SSL socket

9.2 基本使用流程 #

  1. 创建 SSL 上下文:ssl.create_default_context()
  2. 创建 TCP 连接:socket.create_connection()
  3. 包装为 SSL 套接字:context.wrap_socket()
  4. 发送和接收数据:使用 SSL 套接字
  5. 关闭连接:自动或手动关闭

9.3 使用 ssl 模块的好处 #

  1. 无需安装:Python 内置,开箱即用
  2. 安全可靠:提供标准的 SSL/TLS 支持
  3. 灵活控制:可以精细控制 SSL/TLS 参数
  4. 学习价值:帮助理解 SSL/TLS 工作原理
← 上一节 SSE 下一节 Starlette →

访问验证

请输入访问令牌

Token不正确,请重新输入