Bỏ qua để đến nội dung

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.

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

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.

error: taint-sink violation: println argument 1 is tainted[str]
(tainted values must be sanitised before reaching a sink — use
sanitize_html / sanitize_path / sanitize_sql_identifier /
sanitize_sql_string / sanitize_command / sanitize_filename from
std.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)

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.

  • 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.