Theo dõi taint
Dữ liệu đến từ bên ngoài chương trình — tham số dòng lệnh, nội dung tệp, stdin — là dữ liệu mà kẻ tấn công kiểm soát. Trong Halis, nó mang nhãn taint ngay trong kiểu.
tainted[str] không phải là một wrapper runtime. Ở backend native, đây là
thuộc tính lúc biên dịch: chương trình không thể “quên” nhãn rồi vẫn biên
dịch được. Nếu bạn gỡ nhãn mà không đi qua một bước làm sạch tường minh, bản
build sẽ thất bại.
Ba nguồn taint
Phần tiêu đề “Ba nguồn taint”| Nguồn | Cho ra |
|---|---|
tainted_args() |
Toàn bộ tham số dòng lệnh, dưới dạng list[tainted[str]] |
read_file_tainted(path) |
Nội dung của một tệp không được tin cậy |
read_line() |
Một dòng từ stdin |
Các sink
Phần tiêu đề “Các sink”Sink là nơi dữ liệu rời khỏi chương trình và có thể gây hại: print,
println, eprint, eprintln, read_file, write_file, file_exists,
exit, net_lookup, proc_exec, cùng nhóm net_tcp_* /
net_udp_send_to / net_tls_get.
Giá trị tainted không thể tới một sink.
Điều trình biên dịch nói
Phần tiêu đề “Điều trình biên dịch nói”error: taint-sink violation: println argument 1 is tainted[str](tainted values must be sanitised before reaching a sink — usesanitize_html / sanitize_path / sanitize_sql_identifier /sanitize_sql_string / sanitize_command / sanitize_filename fromstd.sanitize, or taint_unwrap() if you accept the risk)Với sink mạng, thông điệp nêu đúng mối đe doạ:
error: taint-sink violation: net_tcp_connect argument 1 (host) is tainted[str](a tainted host enables SSRF + DNS rebinding — use sanitize_command,or taint_unwrap() if you accept the risk)Làm sạch
Phần tiêu đề “Làm sạch”std.sanitize cung cấp bảy bộ làm sạch, mỗi bộ trả về một str sạch:
sanitize_html, sanitize_html_attr, sanitize_path,
sanitize_sql_identifier, sanitize_sql_string, sanitize_command và
sanitize_filename. Tất cả đều là hàm thuần khiết — chúng không khai báo
effect — nên có thể dùng ở bất kỳ đâu.
import "std.sanitize"
fn main() -> int uses Args, IO { let argv: list[tainted[str]] = tainted_args() if argv.len() > 1 { println("hello, " + sanitize_filename(argv.get(1))) } return 0}Định tuyến trên dữ liệu tainted mà không cần bỏ nhãn
Phần tiêu đề “Định tuyến trên dữ liệu tainted mà không cần bỏ nhãn”std.taint cung cấp các truy vấn thuần: taint_check_equals,
taint_check_starts_with, taint_check_contains, taint_check_len và các
hàm cùng loại. Chúng trả về bool và giữ nguyên nhãn taint ở phía bên
kia.
if taint_check_equals(argv.get(1), "admin") { println("admin route")}Bạn có thể định tuyến trên dữ liệu không tin cậy mà không gỡ nhãn. Nhãn chỉ bị gỡ khi dữ liệu thực sự rời khỏi chương trình. Đó là khác biệt giữa một hệ taint có kiểm soát và một cái máy chỉ biết bóc nhãn.
Giới hạn thành thật
Phần tiêu đề “Giới hạn thành thật”- Taint là một nhãn đơn.
tainted[str, Html]vàtainted[str, Sql]chưa được triển khai. Hôm nay, một lần sanitize xoá nhãn cho mọi sink. taint_unwrap()là đường thoát có chủ đích. Dùng nó tức là tắt hệ taint cho giá trị đó ngay lập tức. Đó là quyết định của người dùng, không phải lỗi của toolchain.
Xem trang tra cứu nhanh để có bảng đầy đủ các nguồn và sink.