0
0
Lập trình
Admin Team
Admin Teamtechmely

Sức mạnh nguy hiểm của chuỗi không trích dẫn trong Python

Đăng vào 4 tháng trước

• 6 phút đọc

Giới thiệu

Trong lập trình Python, việc chạy các lệnh trong shell là một yêu cầu thường gặp. Tuy nhiên, việc sử dụng chuỗi không được trích dẫn trong các lệnh này có thể dẫn đến những lỗ hổng bảo mật nghiêm trọng. Bài viết này sẽ khám phá sức mạnh nguy hiểm của các chuỗi không trích dẫn trong Python và cách chúng đã góp phần gây ra CVE-2024-9287.

Mối nguy hiểm từ các đối số không trích dẫn

Khi chúng ta chạy các lệnh trong shell, các lệnh này thường được phân tách bằng các ký tự phân cách lệnh như ';', '&&', '||', và ' '. Trong khi đó, các ký tự phân tách đối số xác định cách mà các đối số của một lệnh được tách rời. Trên các hệ thống tuân theo tiêu chuẩn POSIX, biến môi trường IFS xác định các ký tự được sử dụng để tách các đối số. Mặc định, IFS được thiết lập để tách bằng khoảng trắng, dòng mới và tab.

Khi một đường dẫn hoặc đối số của lệnh chứa khoảng trắng, shell không xem đó là một thực thể liên tục mà xem nó như hai thứ khác nhau. Một đường dẫn đơn đã trở thành hai đối số.

Phần 1: Khoảng trắng như một ký tự phân tách

Xem xét việc tạo một thư mục với một khoảng trắng trong tên.

Khi chúng ta sử dụng mô-đun os, nó hiểu đường dẫn như một chuỗi duy nhất vì nó không liên quan đến việc giải thích của shell. Thư mục được tạo ra như mong muốn với một khoảng trắng trong tên.

Tuy nhiên, khi sử dụng mô-đun subprocess với cờ shell=True, Python sẽ truyền lệnh của chúng ta đến shell để thực thi như một chuỗi duy nhất.

Khi đoạn mã này chạy, shell sẽ thấy lệnh là mkdir my new path. Shell sẽ hiểu điều này như là một lệnh để tạo ra một thư mục tên là my, một thư mục thứ hai tên là new, và một thư mục thứ ba tên là path. Đường dẫn đơn đã trở thành ba đường dẫn khác nhau.

Phần 2: Tấn công lệnh

Mối nguy hiểm không chỉ nằm ở sự hiểu lầm mà còn ở tấn công độc hại.

Hãy tưởng tượng nếu đường dẫn đến từ một nguồn bên ngoài như một tham số do người dùng định nghĩa.

Shell sẽ thấy mkdir my; rm -rf /. Dấu chấm phẩy là một ký tự phân tách lệnh trong shell. Shell sẽ thực hiện mkdir my trước và sau đó thực hiện rm -rf /, điều này sẽ xóa thư mục gốc.

Đường dẫn không được trích dẫn đã cho phép người dùng chèn một lệnh mới. Đây là một thất bại sâu sắc và nguy hiểm trong việc bảo vệ ranh giới. Chỉ một khoảng trắng hay dấu chấm phẩy có thể làm tổn hại đến tính toàn vẹn của hệ thống.

Phần 3: Nguyên tắc trích dẫn

Để ngăn chặn điều này, chúng ta phải sử dụng trích dẫn. Trích dẫn tạo ra một rào cản bảo vệ xung quanh chuỗi, thông báo cho shell coi đó là một đơn vị duy nhất bất kể nội dung của nó.

Bây giờ shell sẽ thấy mkdir "my; rm -rf /". Toàn bộ chuỗi được coi là một đối số duy nhất cho mkdir. Không có thư mục mới nào được tạo ra. Không có lệnh nào được thực thi. Dấu chấm phẩy trở thành một ký tự vô hại trong chuỗi.

Phần 4: Con đường của sự khôn ngoan

Con đường khôn ngoan là con đường tránh xa shell hoàn toàn khi không cần thiết. Hầu hết các công cụ kiểm tra mã (như ruff) sẽ phát hiện điều này cho bạn.

Tại đây, chúng ta truyền một danh sách các đối số cho subprocess.run. Python không truyền một chuỗi duy nhất cho shell. Thay vào đó, nó thực thi mkdir trực tiếp như một tiến trình riêng biệt và truyền user_input làm đối số đầu tiên. Shell không bao giờ được tham gia và rủi ro được loại bỏ.

Đây là cách được ưa chuộng. Nó sạch sẽ và an toàn.

Phần 5: Một ví dụ thực tế về tấn công lệnh (CVE-2024-9287)

Tấn công lệnh không chỉ là một vấn đề lý thuyết. Năm ngoái, một lỗ hổng nghiêm trọng đã được phát hiện ảnh hưởng đến tất cả các phiên bản Python <= 3.13:

Một lỗ hổng đã được tìm thấy trong mô-đun venv của CPython và CLI, nơi tên đường dẫn được cung cấp khi tạo môi trường ảo không được trích dẫn đúng cách, cho phép người tạo chèn lệnh vào các script "kích hoạt" môi trường ảo (ví dụ "source venv/bin/activate"). Điều này có nghĩa là các môi trường ảo do kẻ tấn công kiểm soát có thể thực thi các lệnh khi môi trường ảo được kích hoạt. Các môi trường ảo không được tạo bởi kẻ tấn công hoặc không được kích hoạt trước khi sử dụng (ví dụ "./venv/bin/python") sẽ không bị ảnh hưởng.

Trước đây, khi một môi trường ảo được tạo ra, các script kích hoạt (activate, activate.bat, v.v.) sẽ sử dụng tên môi trường do người dùng cung cấp để xây dựng đường dẫn venv mà không có dấu ngoặc kép.

Ví dụ, một tên như my test venv sẽ được viết vào script dưới dạng /home/user/my test venv. Một kẻ tấn công có thể tạo ra một tên môi trường ảo như my-venv-with-space-and-command; malicious_command, điều này sẽ được shell hiểu là một đường dẫn theo sau là một lệnh bổ sung để thực thi.

Giải pháp (xem mã tóm tắt bên dưới) là đảm bảo rằng tất cả các đường dẫn được viết vào các script kích hoạt venv được trích dẫn đúng cách bằng cách sử dụng mô-đun shlex. Giải pháp này sử dụng shlex.quote để đảm bảo rằng bất kỳ ký tự đặc biệt hoặc khoảng trắng nào trong đường dẫn đều được thoát hoặc bao trong dấu nháy đơn. Điều này ngăn shell hiểu nhầm đường dẫn như các đối số hoặc lệnh riêng biệt.

Rèn luyện kỹ năng

Bài học của thợ rèn bậc thầy thật đơn giản. Cũng như một mảnh kim loại có thể trông như một miếng thép duy nhất, nhưng lại phân tách thành những mảnh vụn khi bị đập bằng búa; các chuỗi lệnh không được trích dẫn bị shell phân tách thành các đối số hoặc lệnh khác nhau.

Khi xây dựng các lệnh trong Python:

  • Tránh sử dụng shell=True và sử dụng subprocess.run([…]) thay vào đó

  • Nếu bạn phải sử dụng subprocess với shell=True, hãy trích dẫn chuỗi lệnh

  • Khi xây dựng các lệnh shell bên ngoài subprocess, hãy sử dụng shlex để tránh tấn công lệnh từ đầu vào không đáng tin cậy.

Thợ rèn không đánh một mảnh thép mà không suy nghĩ. Các nhà phát triển cũng vậy, không nên truyền một đường dẫn cho shell mà không cẩn thận.

Cảm ơn bạn đã đọc bài viết này! Nếu bạn thấy bài viết hữu ích, hãy chia sẻ với bạn bè của mình :)

Tài nguyên và Đọc thêm

Câu hỏi thường gặp (FAQ)

1. Tại sao chúng ta nên tránh sử dụng shell=True?
Trả lời: Sử dụng shell=True có thể tạo ra lỗ hổng bảo mật, cho phép tấn công lệnh. Thay vào đó, bạn nên sử dụng danh sách đối số để bảo mật hơn.

2. Làm thế nào để bảo vệ ứng dụng Python khỏi tấn công lệnh?
Trả lời: Bạn nên luôn trích dẫn các đối số và tránh sử dụng shell khi không cần thiết. Sử dụng mô-đun shlex có thể giúp ích trong việc này.

3. CVE-2024-9287 ảnh hưởng đến những phiên bản Python nào?
Trả lời: CVE-2024-9287 ảnh hưởng đến tất cả các phiên bản Python <= 3.13.

Kết luận

Sử dụng chuỗi không được trích dẫn trong Python có thể dẫn đến những hậu quả nghiêm trọng nếu không được xử lý cẩn thận. Hy vọng bài viết này đã giúp bạn nhận thức rõ hơn về những rủi ro và cách phòng tránh chúng trong lập trình Python.

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào