Chuyên gia chỉ trích mô hình bảo mật của Deno

Phần mềm08 tháng 11, 2026·5 phút đọc

Một bài viết phân tích cho rằng hệ thống quyền (permissions) của Deno tạo cảm giác an toàn giả tạo, bởi tiến trình Deno thực chất không được sandbox. Tác giả chỉ ra lỗ hổng qua terminal và qua các quyền như --allow-run, đồng thời khuyến nghị dùng sandbox thực sự thay vì tin vào cơ chế của runtime.

Chuyên gia chỉ trích mô hình bảo mật của Deno
Ảnh minh hoạ do AI tạo

Một bài viết đăng ngày 31/8/2024 đã phân tích kỹ hệ thống quyền (permissions) — vốn là một trong những tính năng được quảng bá hàng đầu của Deno dưới khẩu hiệu "Secure by default". Theo tác giả, cơ chế này không thực sự bảo vệ người dùng mà chỉ tạo ra cảm giác an toàn sai lệch. Vấn đề đáng chú ý vì nhiều lập trình viên có thể đang chạy mã không tin cậy với niềm tin rằng Deno đã cách ly họ an toàn.

Cách Deno tiếp cận bảo mật

Deno là một runtime cho JavaScript, bao gồm thư viện chuẩn, trình quản lý gói và trình biên dịch TypeScript. Nó không tự viết lại JavaScript mà tái sử dụng V8 để thực thi.

Ý tưởng cốt lõi của hệ thống quyền khá đơn giản: vì mã JS chạy trong Deno cần thư viện chuẩn để tương tác với thế giới bên ngoài, Deno có thể quyết định cho phép hay chặn từng loại truy cập. Ví dụ:

deno run --allow-read=/tmp/dir --allow-run=uname code.ts

Lệnh này chỉ cho phép code.ts đọc thư mục /tmp/dir và chạy lệnh uname. Ngoài ra, chương trình có thể yêu cầu quyền ngay lúc chạy, và Deno sẽ hiển thị một hộp thoại xác nhận ngay trên terminal để người dùng chấp thuận hoặc từ chối.

Vấn đề với hộp thoại xác nhận quyền

Theo tác giả, đây là lỗi ít nghiêm trọng hơn trong hai lỗi được nêu. Hộp thoại xác nhận chỉ là văn bản in ra stdout và chờ dữ liệu từ stdin. Trong khi đó, hầu hết lệnh gửi tới terminal đều đi in-band — nghĩa là in thẳng ra stdout — và terminal phản hồi qua stdin.

Vì Deno cho phép chương trình in dữ liệu tùy ý ra stdout và đọc stdin mà không cần bất kỳ quyền nào, mã độc có thể gửi lệnh tùy ý tới terminal. Tác giả chỉ ra các cách lợi dụng: che giấu hộp thoại bằng cách thay đổi màu terminal, dụ người dùng nhập sẵn phê duyệt vào stdin, hoặc lừa terminal tự gửi phản hồi chấp thuận.

Vấn đề thực sự là sử dụng một kênh do kẻ tấn công kiểm soát để truyền thông tin nhạy cảm về bảo mật. Giống như chạy mã JS độc hại trên trang web rồi hỏi mật khẩu ngay trên chính trang đó.

Tác giả thừa nhận lỗi cụ thể trong đoạn ghi hình minh họa đã được vá, nhưng lỗi liên quan tới màu terminal thì chưa. Lý do đơn giản là không thể biết hết các mã escape không chuẩn của từng loại terminal để vá triệt để.

Vấn đề với --allow-run

Ví dụ trên dùng --allow-run=uname, nhưng tên chương trình không phải định danh duy nhất. Nó chỉ là cách viết tắt của việc "lần lượt tìm trong các thư mục trong PATH". Vì có thể đặt biến môi trường cho tiến trình con mà không cần quyền bổ sung, kẻ tấn công có thể trỏ PATH tới một thư mục chứa file uname giả và thực thi mã tùy ý.

Ngay cả khi vá được lỗi này, tác giả cho rằng vẫn chưa an toàn. Hầu hết file thực thi đều liên kết động, cần dynamic loader để nạp. Loader này có thể bị điều khiển qua biến môi trường. Cụ thể, LD_PRELOAD yêu cầu loader nạp một thư viện động được chỉ định khi khởi chạy, và thư viện đó có thể thực thi mã tùy ý ngay lúc nạp.

Tác giả đã báo cáo lỗi này và Deno đã vá bằng cách chặn đặt các biến môi trường bắt đầu bằng LD_. Nhưng theo tác giả, đây lại là cách vá một lỗi cụ thể trong khi bỏ qua vấn đề lớn hơn: "quyền chạy một lệnh duy nhất" phần lớn không phải một khái niệm hữu ích.

Ví dụ điển hình là quyền gọi $EDITOR để người dùng sửa dữ liệu, chẳng hạn như khi viết commit message trong Git. Đây là yêu cầu rất tự nhiên, nhưng cũng là thảm họa vì hầu hết trình soạn thảo đều đủ khả năng tùy biến để thoát khỏi sandbox. Người dùng có thể dễ dàng đồng ý với --allow-run=vim, rồi script chỉ cần đặt VIMINIT='!rm -rf /*' là toàn bộ file biến mất.

Deno chỉ giả vờ có sandbox

Một nhà phát triển Deno từng viết trong phần thảo luận trên GitHub rằng cơ chế này "chủ yếu bảo vệ bạn khỏi mã độc không đủ thông minh". Tác giả cho rằng câu này nói lên bản chất của vấn đề.

Kết luận của bài viết: Deno đang cố làm việc mà lẽ ra hệ điều hành phải làm — giả lập lọc syscall (lời gọi hệ thống) bằng cách lọc các lời gọi trong thư viện chuẩn. Cách này sụp đổ ngay khi cần chạy mã không dùng thư viện chuẩn của Deno. Tác giả cũng nêu thêm một vấn đề kém hấp dẫn hơn: Deno không ngăn việc đi theo symlink dẫn ra ngoài sandbox.

Dù vậy, tác giả không kêu gọi gây áp lực lên nhóm phát triển Deno, mà chỉ đề xuất dùng sandbox thực sự như bwrap cho mã không tin cậy.

Góc nhìn

Với các lập trình viên và đội ngũ kỹ thuật tại Việt Nam đang cân nhắc dùng Deno để chạy mã từ bên thứ ba — chẳng hạn plugin, script do người dùng gửi lên, hay các tác vụ tự động hóa — bài viết này là lời cảnh báo đáng lưu tâm. Việc thấy Deno yêu cầu quyền trước khi truy cập file hay chạy lệnh có thể khiến ta chủ quan, trong khi bản chất tiến trình vẫn chạy với đầy đủ đặc quyền.

Về mặt thực hành, nếu cần chạy mã không tin cậy, nên dựa vào cách ly ở tầng hệ điều hành hoặc container thay vì chỉ tin vào cơ chế quyền của runtime. Với mã chỉ dùng thư viện chuẩn và không có quyền nào trong môi trường phi tương tác, rủi ro thấp hơn, nhưng vẫn nên kiểm soát tài nguyên tiêu thụ vì việc đốt CPU hay cấp phát bộ nhớ không cần quyền nào cả. Điều quan trọng là không xem hệ thống quyền của một runtime là tương đương với sandbox thật.

Nguồn: goldstein.lol · Quy trình biên tập

Chia sẻ:FacebookX