str.lower() của Python là lỗ hổng bảo mật trong IDNA 2003
Một lỗi tinh vi trong triển khai IDNA 2003 của CPython đã sử dụng phiên bản Unicode của trình thông dịch để chuyển đổi chữ hoa/thường, khác với đặc tả RFC 3454. CVE-2026-17084 khắc phục bằng cách thêm các ngoại lệ để khớp với hành vi Unicode 3.2.0.

str.lower() của Python là một công cụ đắc lực — nhưng khi được dùng bên trong codec IDNA 2003, nó có thể mở ra lỗ hổng bảo mật. Vấn đề: IDNA 2003, được định nghĩa bởi RFC 3491, dựa trên StringPrep (RFC 3454), vốn chỉ định việc chuyển đổi chữ hoa/thường dựa trên Unicode 3.2.0. Tuy nhiên, str.lower() của Python lại dùng phiên bản Unicode mà trình thông dịch đi kèm — hiện tại là 17.0.0. Sự không khớp này có nghĩa codec có thể tạo ra các tên miền khác với đặc tả, có khả năng dẫn đến nhầm lẫn hoặc giả mạo.
Đoạn mã dễ bị tấn công trong mô-đun stringprep của CPython trông như thế này:
def map_table_b3(code):
r = b3_exceptions.get(ord(code))
if r is not None: return r
return code.lower()
Lệnh gọi str.lower() sử dụng dữ liệu Unicode của trình thông dịch, không phải dữ liệu Unicode 3.2.0 mà StringPrep yêu cầu. Python thực sự đi kèm mô-đun unicodedata.ucd_3_2_0 dành riêng cho mục đích này, nhưng mã đã không dùng nó để chuyển đổi chữ hoa/thường.
Tác động thực tế: một số ký tự Unicode, như chữ Cherokee 'Ꭰ' (U+13A0), chuyển đổi khác nhau dưới Unicode 17.0.0 so với 3.2.0. Điều này thay đổi đầu ra mã hóa tương thích ASCII (ACE):
# Giá trị tuân thủ RFC 3454
>>> "ᎠᎠ".encode("idna")
'xn--58da'
# Giá trị nếu dùng chuyển đổi chữ hoa/thường Unicode 17.0.0
>>> "ᎠᎠ".encode("idna")
'xn--kz9aa'
Sự khác biệt đó có nghĩa hai chuỗi Unicode khác nhau có thể ánh xạ đến cùng một nhãn IDNA, hoặc cùng một chuỗi có thể ánh xạ đến các nhãn khác nhau tùy thuộc vào phiên bản Python — một công thức kinh điển cho các cuộc tấn công nhầm lẫn tên miền.
Bản sửa lỗi, được hợp nhất trong CPython PR #155293, thêm các ngoại lệ rõ ràng cho mọi điểm mã nơi str.lower() khác với hành vi Unicode 3.2.0. Giờ đây IDNA 2003 nhất quán với đặc tả, bất kể phiên bản Unicode của trình thông dịch.
Điều này được báo cáo bởi Bitshift, với sự đồng phát triển của Stan Ulbrych, và được đánh giá bởi Marc-Andre Lemburg và Petr Viktorin. Được theo dõi là CVE-2026-17084.
Đối với hầu hết nhà phát triển, bài học rút ra là: hãy dùng gói idna (IDNA 2008) thay vì str.encode('idna') (IDNA 2003). Nhưng nếu bạn phải hỗ trợ IDNA cũ, bản sửa lỗi này rất quan trọng.
Lệnh gọi str.lower() trong hàm này là một lỗ hổng!
| Khía cạnh | IDNA 2003 | IDNA 2008 |
|---|---|---|
| Đặc tả | RFC 3491 (StringPrep) | RFC 5890-5893 |
| Phiên bản Unicode | 3.2.0 | Mới nhất (ví dụ: 15.1) |
| Hỗ trợ Python | str.encode('idna') | gói idna |
| Chuyển đổi chữ hoa/thường | StringPrep B.2/B.3 | UTS #46 |
| Trạng thái bảo mật | Lỗi thời, có CVE-2026-17084 | Được bảo trì tích cực |
Thảo luận
0 bình luận
Hãy là người đầu tiên thảo luận.