- Một cuộc tấn công chuỗi cung ứng vào npm registry đã làm lộ hàng triệu ứng dụng doanh nghiệp và hàng tỷ hồ sơ người dùng, nhưng hệ sinh thái này lại xem đó như chuyện không thể tránh khỏi
- Senior Frontend Engineer Mark Vance châm biếm thực tế rằng ngay cả việc chuyển một chuỗi thành chữ hoa cũng phải dựa vào 40 tầng phụ thuộc lồng nhau của các gói chưa được kiểm chứng
- Việc một gói tiện ích bị bỏ mặc từ lâu bị chiếm quyền và bị chèn crypto-miner vào các bản build production trên toàn cầu được đối xử như một thảm họa tự nhiên
- Hệ sinh thái Node.js tiếp nhận thực thi mã từ xa độc hại như một bi kịch không thể đoán trước, còn các đội DevOps thì mải miết xoay vòng khóa AWS
- Các hệ sinh thái Go, Rust và Web API native trở thành đối trọng khi giảm phụ thuộc bên thứ ba nhờ thư viện chuẩn mạnh và khả năng xác minh mật mã
Châm biếm về tấn công chuỗi cung ứng npm
- Một cuộc tấn công chuỗi cung ứng vào npm registry đã xâm phạm hàng triệu ứng dụng doanh nghiệp và làm lộ hàng tỷ hồ sơ người dùng, nhưng các nhà phát triển trong hệ sinh thái JavaScript lại tiếp nhận điều đó theo kiểu “hoàn toàn không thể tránh được”
- Senior Frontend Engineer Mark Vance xem việc phải dựa vào một cây phụ thuộc lồng nhau 40 tầng của các gói chưa được kiểm chứng chỉ để biến một chuỗi đơn thành chữ hoa là cái giá của phát triển ứng dụng web hiện đại
- Tình huống một gói tiện ích bị bỏ mặc từ lâu bị chiếm quyền rồi chèn crypto-miner vào các bản build production trên toàn thế giới được đối xử như một hiện tượng thiên tai
- Hệ sinh thái Node.js tiếp nhận thực thi mã từ xa độc hại như một bi kịch không thể dự báo, đồng thời gửi “suy nghĩ và lời cầu nguyện” đến các đội DevOps đang bận xoay vòng khóa AWS
Sự đối lập giữa các hệ sinh thái khác và npm
- Các hệ sinh thái Go, Rust và Web API native dùng thư viện chuẩn mạnh để giảm mạnh phụ thuộc vào mã bên thứ ba, đồng thời tích hợp xác minh mật mã nghiêm ngặt vào chuỗi công cụ cốt lõi
- Ở các hệ sinh thái đó, người ta có thể đối chiếu theo kiểu “hôm nay có 0 trường hợp một dự án cuối tuần của sinh viên bỏ học đại học phá hỏng hạ tầng logistics toàn cầu”
- Người phát ngôn của npm khẳng định rằng trong một thế giới có các tác nhân độc hại thì mọi người phải chấp nhận điều này, và không hề có chính sách registry hay hàng rào sandbox build nào có thể ngăn chặn
- npm registry được khắc họa là một registry mã nguồn mở mặc định thực thi các install script tùy ý trên máy cục bộ, khiến lời người phát ngôn ăn khớp với rủi ro mang tính cấu trúc
- Phần cuối khép lại bằng lời an ủi dành cho nạn nhân, đồng thời nhấn mạnh rằng họ phải giữ được khả năng chống chịu cho đến “vụ xâm phạm tất yếu tiếp theo vào sáng mai”
1 bình luận
Ý kiến trên Hacker News
Mỗi người có thể có quan điểm riêng về cooldown, nhưng phần lớn các vụ tấn công chuỗi cung ứng npm gần đây, bao gồm axios, tanstack, đều có thể đã tránh được bằng cooldown
Nếu dùng Artifactory / Nexus thì rất có thể đã có cooldown sẵn, và nếu chưa có thì cũng rất dễ cấu hình
Phần lớn các vụ xâm nhập npm hoặc PyPI đều bị gỡ xuống trong vòng vài giờ, nên cooldown ở đây có nghĩa là “bỏ qua các gói mới phát hành chưa quá N ngày”. 1 ngày cũng có tác dụng, 3 ngày là ổn, còn 7 ngày thì hơi quá nhưng vẫn hiệu quả
Cách cấu hình là dùng pnpm bản mới nhất có cooldown mặc định 1 ngày hoặc https://pnpm.io/supply-chain-security, còn nếu muốn sửa một lần cho xong thì có thể dùng https://depsguard.com để thêm cooldown và cấu hình khuyến nghị cho npm, pnpm, yarn, bun, uv, dependabot. Tôi là maintainer của nó
Hoặc cũng có https://cooldowns.dev tập trung hơn vào cooldown, kèm script hỗ trợ cấu hình cục bộ. Tất cả đều là mã nguồn mở hoặc miễn phí
Nếu bạn biết tự chỉnh trực tiếp
~/.npmrcvà các file tương tự thì không nhất thiết cần mấy thứ này, nhưng với những người xung quanh cần giải pháp một cú nhấp thì nó có thể giúp họ tránh đợt tấn công tiếp theoTuy nhiên, khi cần vá một CVE nghiêm trọng mới xuất hiện thì phải bỏ qua cooldown, và mỗi công cụ đều có cách bỏ qua riêng. Không có số liệu chính xác, nhưng vài tuần gần đây có vẻ rủi ro lớn hơn đến từ tấn công chuỗi cung ứng phần mềm so với CVE zero-day mới
Với việc nâng cấp dependency định kỳ cũng vậy. Chỉ là đôi khi có trường hợp phải nâng ngay, như xử lý lỗ hổng bảo mật, và lúc đó để lập trình viên chỉ định rõ phiên bản mới mà họ muốn cũng là hợp lý
Nếu ai cũng bật cooldown 7 ngày thì chẳng phải chỉ là phát nổ muộn hơn thôi sao?
Nghĩ thêm khi đang viết, tôi vẫn đồng ý với cooldown 10 ngày là không cài bất cứ thứ gì được phát hành trong 10 ngày gần nhất. Chỉ là không nên kỳ vọng đây là biện pháp giảm thiểu duy nhất
Tôi tò mò Go hay Rust thực sự đảm bảo được điều gì so với Python/npm. Cũng có thể chỉ là Python/npm là mục tiêu béo bở hơn thôi
Tôi ngày càng cố tránh mọi gói bên thứ ba
Maven Central đã tồn tại hàng chục năm nhưng rất hiếm sự cố bị chiếm namespace
Bạn không thể tải package với groupId
com.ycombinatorlên mà không xác minh được mình sở hữu domain ycombinator.com. Và một khi package đã được tải lên thì nó bất biến 100%, kể cả có chứa mã độc. Tất nhiên những thư viện như vậy sẽ bị gắn cờ là dễ bị tấn công ở khắp nơiTôi không hiểu vì sao NPM đã mất ngần ấy năm mà vẫn không sao sao chép được các cơ chế an toàn như Maven Central
Thay vì có sẵn một bộ thư viện đã được kiểm chứng đi kèm ngôn ngữ, ứng dụng phải tự làm hoặc lấy từ kho package bên thứ ba. Vì người ta luôn được dạy là nên tránh NIH, nên họ có xu hướng nhặt package về dùng
Bản thân điều đó không hẳn là xấu, nhưng thường kéo vào nhiều code hơn mức cần thiết. Hệ sinh thái JS cũng chuộng các module nhỏ, nên cần rất nhiều module, rồi mọi người lại xây chồng tiếp lên trên, khiến đồ thị dependency trở nên khổng lồ. Dù cố ý hay không thì bề mặt phát sinh vấn đề cũng quá lớn
Các ngôn ngữ khác có nhiều thứ được cung cấp sẵn hơn. Không phải là chưa từng có bug hay vấn đề bảo mật, nhưng so với những gì thấy trong hệ sinh thái JS thì chỉ như muối bỏ bể. Đồ thị dependency bên ngoài nhỏ hơn nhiều và các chức năng cốt lõi đến từ các bên thứ ba đáng tin cậy
Điều này không bào chữa cho NPM, mà đúng hơn là lại thêm một điểm bất lợi cho NPM
Cũng có thể nói các cuộc tấn công kiểu này cho thấy sâu hơn sự khác biệt giữa lập trình viên frontend và backend, nhưng tôi không đi xa đến mức đó
Ở nhiều nơi làm việc, tôi đã rất khổ sở khi phải cài cấu hình npm toàn cục an toàn lên máy của toàn bộ lập trình viên, rồi còn phải nhờ họ đừng tắt đi, và dùng công cụ MDM để kiểm tra
Thiết lập mặc định an toàn hơn đáng ra phải có từ lâu rồi
Không có lý do chính đáng nào để postinstall script phải tồn tại. Đội npm giờ đủ trưởng thành để tuyên bố rằng “kể từ phiên bản npm nào đó, chỉ chạy postinstall script với các phiên bản package đã được publish trước ${today}”
Điều này là vì các chuỗi công cụ dev như esbuild được viết bằng ngôn ngữ biên dịch và được phân phối dưới dạng binary qua kho npm. Nếu bạn dùng Node/npm mới cùng OS/nền tảng phổ biến hiện đại, thì đáng ra phải có thể vô hiệu hóa toàn bộ postinstall script mà không gặp vấn đề chính đáng nào
Code npm đã cài gần như luôn sẽ được thực thi
Nhưng code bình thường bên trong package đó cũng vậy. Dù nó không chạy ngay lúc cài thì cuối cùng vẫn sẽ có thứ gì đó trong đó được chạy. Nếu không thì ngay từ đầu nó đã chẳng được đưa vào dependency
Nghĩ rằng loại bỏ postinstall script sẽ có tác động hơn là nhất thời đến tỷ lệ bị lạm dụng là dấu hiệu của việc chưa nghĩ vấn đề đến nơi đến chốn. Đáng tiếc là chuyện này tinh vi hơn nhiều so với điều bài gốc ngụ ý
Đây không phải kiểu vấn đề “đừng đặt nút làm rụng cánh cạnh công tắc đèn”, mà cốt lõi là: điều ta muốn ngăn là “code xấu của người khác chạy trên máy mình”, còn điều ta muốn có lại là “code tốt của người khác chạy trên máy mình”, và không có cách nào phân biệt hai thứ đó nếu không làm thủ công cực kỳ vất vả. Mà lý do ta chạy code của người khác ngay từ đầu là để tránh làm cái phần thủ công cực kỳ vất vả đó
Mọi dự án Node.js đều bắt đầu bằng
npm install, và đột nhiên có 500 package mà bạn cũng chẳng hề muốn. Một nửa trong số đó là những thứ đã không ai đụng vào suốt nhiều nămCó một vấn đề văn hóa là người ta luôn muốn nâng mọi thứ lên package mới nhất, kể cả những gì đang chạy tốt. Nhiều khi họ còn chẳng đọc changelog để xem thay đổi đó có áp dụng được hay không
Cooldown chỉ là cách buộc maintainer phải kiên nhẫn thêm một chút, và nó thực sự có tác dụng
Package Lisp có thể dùng tốt suốt 15 năm mà không cần thay đổi gì, nhưng package JS thì lại bị xem như thảm họa nếu không được bảo trì. Dù 15 năm trước nó đã hoàn thiện rồi, người ta vẫn phải làm cho nó trông như đang được quản lý trên npm và GitHub, bằng cách không thêm gì cả hoặc đôi khi còn nhét cả thay đổi gây vỡ rồi tăng version. Thế là mọi thứ lại phải cập nhật
Cooldown 7 ngày có cảm giác như một miếng vá tạm thời, ít công sức. Giải pháp thực sự có lẽ là build tái lập được và chứng thực có chữ ký, nhưng phần lớn đội ngũ sẽ không chịu trả cái giá đó cho đến khi chính họ bị dính đòn
Bài này đọc như một bài của Onion
Liên kết này là một phiên bản rõ ràng được tẩy rửa bằng AI của trò đùa mà Xe Iaso đã làm từ lâu. Thật đáng tiếc
https://xeiaso.net/shitposts/no-way-to-prevent-this/CVE-2024...
https://news.ycombinator.com/item?id=40438408
[0]: https://en.wikipedia.org/wiki/%27No_Way_to_Prevent_This,%27_...
https://en.wikipedia.org/wiki/%27No_Way_to_Prevent_This,%27_...