ssl --- Mô-đun SSL/TLS¶
Mô-đun này cung cấp khả năng mã hóa Transport Layer Security (trước đây và thường được gọi là "Secure Sockets Layer") cùng tính năng xác thực đối tác cho các socket mạng, cả phía máy khách lẫn phía máy chủ.
Mẹo
Bạn mới làm quen với TLS trên camera? Hãy bắt đầu với hướng dẫn Làm việc với chứng chỉ TLS. Hướng dẫn đó trình bày cách chọn loại khóa, tạo và chuyển đổi chứng chỉ sang định dạng DER mà camera yêu cầu, đưa chúng lên thiết bị và xác minh máy chủ cũng như máy khách -- kèm theo các ví dụ hoàn chỉnh có thể chạy được.
Ghi chú
MicroPython không triển khai ssl.SSLError. Các lỗi SSL/TLS được phát sinh dưới dạng OSError.
Ví dụ¶
Máy khách TLS, xác minh chứng chỉ máy chủ dựa trên chứng chỉ CA (định dạng DER) được lưu trên hệ thống tệp:
import socket
import ssl
import ntptime
# CERT_REQUIRED checks the certificate's validity dates, so the clock
# must be set (see the certificates tutorial linked above).
ntptime.settime()
# Open a plain TCP connection.
addr = socket.getaddrinfo("example.com", 443)[0][-1]
sock = socket.socket()
sock.connect(addr)
# Wrap it for TLS and require a valid certificate.
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ctx.verify_mode = ssl.CERT_REQUIRED
ctx.load_verify_locations(cafile="ca.der")
ssock = ctx.wrap_socket(sock, server_hostname="example.com")
ssock.write(b"GET / HTTP/1.0\r\nHost: example.com\r\n\r\n")
print(ssock.read())
ssock.close()
Để kết nối nhanh, không an toàn (không xác thực chứng chỉ), có thể sử dụng hàm tiện ích ssl.wrap_socket() thay thế:
ssock = ssl.wrap_socket(sock, server_hostname="example.com")
Máy chủ TLS, trình bày chứng chỉ và khóa riêng tư của nó (định dạng DER):
import socket
import ssl
sock = socket.socket()
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(socket.getaddrinfo("0.0.0.0", 8443)[0][-1])
sock.listen(1)
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ctx.load_cert_chain("server.der", "server.key")
while True:
client, addr = sock.accept()
sclient = ctx.wrap_socket(client, server_side=True)
sclient.write(b"hello\n")
sclient.close()
Hàm¶
- ssl.wrap_socket(sock: Any, server_side: bool = False, key: bytes | None = None, cert: bytes | None = None, cert_reqs: int = CERT_NONE, cadata: bytes | None = None, server_hostname: str | None = None, do_handshake: bool = True) Any¶
Bao bọc sock đã cho và trả về một đối tượng socket đã được bao bọc. Việc triển khai hàm này là trước tiên tạo một
SSLContextrồi gọi phương thứcSSLContext.wrap_socket()trên đối tượng ngữ cảnh đó. Các đối số sock, server_side và server_hostname được truyền trực tiếp không thay đổi. Đối số do_handshake được truyền dưới dạng do_handshake_on_connect. Các đối số còn lại có hành vi như sau:cert_reqs xác định xem đối tác (máy chủ hoặc máy khách) có phải trình bày chứng chỉ hợp lệ hay không. Lưu ý rằng
ssl.CERT_NONEvàssl.CERT_OPTIONALkhông xác thực bất kỳ chứng chỉ nào; chỉssl.CERT_REQUIREDmới làm điều đó.cadata là một đối tượng bytes chứa chuỗi chứng chỉ CA (định dạng DER) sẽ được dùng để xác thực chứng chỉ của đối tác. Hiện tại chỉ hỗ trợ một chứng chỉ được mã hóa DER.
Lớp¶
- class ssl.SSLContext(protocol: int, /)¶
Tạo một phiên bản SSLContext mới. Đối số protocol phải là một trong các hằng số
PROTOCOL_*.- load_cert_chain(certfile: str | bytes, keyfile: str | bytes) None¶
Nạp khóa riêng tư và chứng chỉ tương ứng. certfile là chuỗi chứa đường dẫn tệp chứng chỉ. keyfile là chuỗi chứa đường dẫn tệp khóa riêng tư.
Khác biệt so với CPython
Mở rộng MicroPython: certfile và keyfile có thể là đối tượng bytes thay vì chuỗi, trong trường hợp đó chúng được hiểu là dữ liệu chứng chỉ/khóa thực tế.
- load_verify_locations(cafile: str | None = None, cadata: bytes | None = None) None¶
Nạp chuỗi chứng chỉ CA dùng để xác thực chứng chỉ của đối tác. cafile là đường dẫn tệp chứng chỉ CA. cadata là đối tượng bytes chứa các chứng chỉ CA. Chỉ nên cung cấp một trong hai đối số này.
- set_ciphers(ciphers: List[str]) None¶
Đặt các cipher có sẵn cho các socket được tạo với ngữ cảnh này. ciphers phải là danh sách chuỗi theo định dạng bộ cipher IANA.
- wrap_socket(sock: Any, *, server_side: bool = False, do_handshake_on_connect: bool = True, server_hostname: str | None = None, client_id: bytes | None = None) Any¶
Nhận một stream sock (thường là phiên bản socket.socket kiểu
SOCK_STREAM), và trả về một phiên bản ssl.SSLSocket, bao bọc luồng bên dưới. Đối tượng được trả về có các phương thức giao diện stream thông thường nhưread(),write(), v.v.server_side chọn xem socket được bao bọc ở phía máy chủ hay máy khách. Socket SSL phía máy chủ nên được tạo từ socket thông thường được trả về từ
accept()trên socket máy chủ lắng nghe không SSL.do_handshake_on_connect xác định xem quá trình bắt tay có được thực hiện như một phần của
wrap_sockethay bị trì hoãn để thực hiện như một phần của các lần đọc hoặc ghi đầu tiên. Với các socket chặn, việc thực hiện bắt tay ngay lập tức là tiêu chuẩn. Với các socket không chặn (tức là khi sock được truyền vàowrap_socketđang ở chế độ không chặn), quá trình bắt tay thường nên được trì hoãn vì nếu khôngwrap_socketsẽ bị chặn cho đến khi hoàn tất.server_hostname dùng cho phía máy khách, đặt tên máy chủ để kiểm tra với chứng chỉ máy chủ nhận được. Nó cũng đặt tên cho Server Name Indication (SNI), cho phép máy chủ trình bày chứng chỉ phù hợp.
client_id là đối số mở rộng đặc thù MicroPython chỉ được dùng khi triển khai máy chủ DTLS. Xem Hỗ trợ DTLS để biết chi tiết.
Cảnh báo
Theo mặc định, không có xác thực chứng chỉ nào được thực hiện (
ssl.CERT_NONE). Để có kết nối an toàn, bạn phải xác minh chứng chỉ của đối tác bằng cách đặt cert_reqs /SSLContext.verify_modethànhssl.CERT_REQUIRED; nếu không, kết nối dễ bị tấn công man-in-the-middle.wrap_socketcủa CPython trả về đối tượngSSLSocketcó các phương thức điển hình cho socket nhưsend,recv, v.v.wrap_socketcủa MicroPython trả về đối tượng giốngSSLObjectcủa CPython hơn, vốn không có các phương thức socket này.
- verify_mode¶
Đặt hoặc lấy hành vi xác minh chứng chỉ đối tác. Phải là một trong các hằng số
CERT_*.Ghi chú
ssl.CERT_REQUIREDyêu cầu ngày/giờ của thiết bị được đặt đúng, ví dụ: dùng mpremote rtc --set hoặcntptime, vàserver_hostnamephải được chỉ định khi ở phía máy khách.
Hỗ trợ DTLS¶
Khác biệt so với CPython
Đây là phần mở rộng của MicroPython.
Mô-đun này hỗ trợ DTLS ở chế độ máy khách và máy chủ thông qua các hằng số PROTOCOL_DTLS_CLIENT và PROTOCOL_DTLS_SERVER có thể được dùng làm đối số protocol của SSLContext.
Trong trường hợp này, socket bên dưới được kỳ vọng hoạt động như một socket datagram (tức là giống socket được mở bằng socket.socket với socket.AF_INET là af và socket.SOCK_DGRAM là type).
Hỗ trợ máy chủ DTLS¶
Hỗ trợ máy chủ DTLS của MicroPython được cấu hình với "Hello Verify" theo yêu cầu của DTLS 1.2. Điều này minh bạch với các máy khách DTLS, nhưng có những điểm cần lưu ý khi triển khai máy chủ DTLS trong MicroPython:
Máy chủ nên truyền thêm đối số client_id khi gọi
SSLContext.wrap_socket(). ID này phải là đối tượngbytes(hoặc tương tự) chứa mã định danh đặc thù cho giao thức vận chuyển đại diện cho máy khách.Cách đơn giản nhất là chuyển đổi bộ tuple
(client_ip, client_port)được trả về từsocket.recv_from()thành chuỗi byte, tức là:_, client_addr = sock.recvfrom(1, socket.MSG_PEEK) sock.connect(client_addr) # Connect back to the client sock = ssl_ctx.wrap_socket(sock, server_side=True, client_id=repr(client_addr).encode())
Lần đầu tiên máy khách kết nối, lệnh gọi
wrap_socketcủa máy chủ sẽ thất bại với lỗiOSError"Hello Verify Required". Điều này là vì cookie DTLS "Hello Verify" chưa được máy khách biết đến. Nếu cùng một máy khách kết nối lần thứ hai,wrap_socketsẽ thành công.Cookie DTLS cho "Hello Verify" được liên kết với đối tượng
SSLContext, vì vậy cùng một đối tượngSSLContextnên được dùng để bao bọc kết nối tiếp theo từ cùng một máy khách. Việc triển khai cookie bao gồm thời gian chờ và sử dụng bộ nhớ cố định bất kể có bao nhiêu máy khách kết nối, vì vậy việc tái sử dụng cùng một đối tượngSSLContextcho vòng đời của máy chủ là ổn.
Hằng số¶
- ssl.PROTOCOL_DTLS_CLIENT: int¶
Giá trị được hỗ trợ cho tham số protocol, chọn chế độ máy khách DTLS.
- ssl.CERT_NONE: int¶
Giá trị được hỗ trợ cho tham số cert_reqs và thuộc tính
SSLContext.verify_mode. Không thực hiện xác minh chứng chỉ nào với đối tác.
- ssl.CERT_OPTIONAL: int¶
Giá trị được hỗ trợ cho tham số cert_reqs và thuộc tính
SSLContext.verify_mode. Xác minh chứng chỉ là tùy chọn. Lưu ý rằng trên OpenMV Cam, tính năng này hoạt động giống nhưssl.CERT_NONE.
- ssl.CERT_REQUIRED: int¶
Giá trị được hỗ trợ cho tham số cert_reqs và thuộc tính
SSLContext.verify_mode. Yêu cầu chứng chỉ hợp lệ từ đối tác.