1 điểm bởi GN⁺ 1 giờ trước | 1 bình luận | Chia sẻ qua WhatsApp
  • 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 ~/.npmrc và 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 theo
    Tuy 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

    • Tôi lại thấy lạ khi cho rằng 7 ngày là quá mức. Nếu không thực sự cần một tính năng mới cụ thể nào đó, thì ngay cả khi bắt đầu dự án mới, dùng phiên bản dependency phát hành từ vài tháng trước thường cũng đã đủ
      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ý
    • Vậy chẳng phải vấn đề chỉ bị trì hoãn thêm 7 ngày thôi sao. Tôi cứ nghĩ mấy sự cố này kết thúc là vì có người bị dính rồi nhận ra, chứ không phải vì có cả một đội quân audit thay đổi để phát hiện ra nó
      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?
    • Có vẻ đang thiếu một câu này:

      Disclaimer: I maintain depsguard

    • Tôi không chắc cooldown có hiệu quả thật không. Sẽ phải có ai đó vượt cooldown để cài một bản phát hành có vấn đề rồi phát hiện ra nó. Nếu không ai làm vậy thì chỉ là dời vấn đề đi 3/7/10/14 ngày mà thôi
      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
    • Không thể tạo các bản phân phối hoặc kênh riêng kiểu latest/stable/LTS như các distro Linux sao?
  • 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

    • Việc cấp quyền sở hữu cho package và namespace được làm thế nào phụ thuộc 100% vào đơn vị vận hành package manager
      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.ycombinator lê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ơi
      Tô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
    • Một trong những ý chính của bài là hầu hết các ngôn ngữ phổ biến khác đều có thư viện chuẩn khá đầy đủ. Thư viện chuẩn của JS thì nhỏ đến mức đáng ngạc nhiên
      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
    • Kẻ tấn công tìm đến nơi có nạn nhân. Frontend gần như là một nền văn hóa đơn nhất nơi phần lớn mọi người đều dùng NPM, còn backend thì ít như vậy hơn
      Đ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 đó
    • Nói thật thì Rust cũng có chính xác cùng một mẫu tấn công chuỗi cung ứng. Chỉ là nó mới hơn và hiện tại đang được quản lý tốt hơn thôi. Cứ chờ thêm 10 năm xem
    • Lần gần nhất tôi kiểm tra thì npm có 2FA khi publish còn cargo thì không. Tôi không nghĩ cargo tốt hơn npm ở điểm nào, chỉ là nó chưa hấp dẫn bằng với tư cách mục tiêu mà thôi
  • Ở 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

    • Chỉ cần đừng dùng npm. Dùng package manager không chạy postinstall theo mặc định là được, và chuyển đổi thì dễ đến khó tin
    • Tôi tò mò “cấu hình an toàn” nghĩa là gì. Nếu là muốn ép cooldown hoặc danh sách cho phép/chặn package, thì cách đúng là thiết lập một kho do công ty kiểm soát, lấy từ kho npm upstream nhưng áp chính sách mà công ty muốn
  • 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}”

    • Gần đây tôi đã audit khá nhiều postinstall script của các package phổ biến. Phần lớn là để dùng hoặc tải xuống binary native, phát hiện khả năng tương thích nền tảng, tự nối dây thay vì để Node bootstrap, và lách các vấn đề của phiên bản npm cũ
      Đ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
    • Script cài đặt, cũng như ký package, là yếu tố gây xao nhãng. Thêm hay bớt tính năng nào trong số đó cũng không ảnh hưởng nhiều đến khả năng hệ sinh thái package này biến thành sâu máy tính
      Code npm đã cài gần như luôn sẽ được thực thi
    • Việc package Rust có thể chạy mà không có sandbox khi build cũng chẳng có gì là chính đáng cho lắm
    • Cách này không thực sự sửa được vấn đề. Vì code của package vẫn được chạy ở thời điểm build và trong lúc test. Có thể thu hẹp phạm vi đôi chút, nhưng cũng chỉ đến vậy
    • Nói một cách thận trọng thì postinstall script gần như là một tranh cãi giả. Người ta ngạc nhiên vì code do người khác kiểm soát lại chạy trên máy mình và có thể làm chuyện xấu, đúng vậy, điều đó có thể xảy ra
      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ăm

  • Có 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

    • Nếu có yêu cầu tuân thủ thì bạn phải cập nhật vì các CVE nhắm vào phiên bản cũ. Phần lớn gần như là giả tạo kiểu “ReDoS trong regex”, nhưng vì phải đáp ứng quy trình nên vẫn buộc phải cập nhật
    • Và còn chuyện chủ package cập nhật những thứ không cần cập nhật chỉ để khỏi trông như đồ cũ kỹ bị bỏ hoang
      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

    residents of the Node.js ecosystem stood unified in their belief that the malicious remote-code execution was a completely unpredictable tragedy
    Có ai thực sự tin điều đó sao? Đã có quá nhiều phản ví dụ rồi
    Đây là một màn châm biếm khá trúng vào thất bại của hệ sinh thái, nhưng rốt cuộc vẫn chỉ là nội dung giải trí. Có lẽ nó còn tạo dịp cho dân marketing đem hàng ra bán. Ví dụ như maintainer của depsguard đã xóa rồi lại thêm, rồi lại xóa chuyện đó trong bài viết của chính mình. Tại thời điểm tôi viết bình luận này thì bài đó đang đứng đầu

  • 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