Cách Ngăn Chặn Tấn Công Chuỗi Cung Ứng với GitHub Actions
Trong một lần làm việc với dự án API REST Node.js của mình, tôi đã gặp phải một tình huống bất ngờ khi kiểm tra tệp package-lock.json từ một PR (pull request) của một contributor ngẫu nhiên. Một contributor khác đã phê duyệt PR này ngay sau đó. Điều này đã dẫn tôi vào một cuộc tấn công chuỗi cung ứng đang diễn ra nhắm vào các nhà phát triển như chúng tôi.
Hãy cùng đào sâu vào câu chuyện này để hiểu rõ hơn về cách mà phát triển phần mềm hiện đại có thể nhanh chóng trở nên nguy hiểm, và lý do tại sao một PR "hữu ích" có thể không hữu ích chút nào.
Tấn Công Chuỗi Cung Ứng Là Gì?
Tấn công chuỗi cung ứng xảy ra khi các hacker đưa mã độc hoặc các công cụ đánh cắp thông tin vào trong các phụ thuộc, kịch bản xây dựng hoặc pipelines CI/CD. Họ thường tấn công vào bất kỳ liên kết nào mà mã nguồn, bí mật và môi trường có thể tiếp xúc với nhau. Hãy nghĩ đến việc: "Nếu tôi có thể làm hỏng upstream, tại sao phải tấn công hàng ngàn repos một cách riêng lẻ?"
Điều này rất tinh vi bởi vì những công cụ này là những gì chúng ta tin tưởng một cách tuyệt đối. Khi lodash phát hành bản cập nhật, chúng ta thường không kiểm tra từng dòng mã, đúng không? Chúng ta chỉ cần npm update và tiếp tục với cuộc sống.
Bằng Chứng Hết Sức Rõ Ràng: Tệp Lock Đã Bị Can Thiệp
Mọi chuyện bắt đầu khi tôi xem xét tệp package-lock.json từ pull request. Tôi nhận thấy một điều gì đó làm tôi cảm thấy không ổn - cùng với các tin tức về hack NPM gần đây vào tháng 9 năm 2025:
json
// TRƯỚC (Bình thường, an toàn)
"@types/body-parser": {
"version": "1.17.0",
"requires": {
"@types/connect": "3.4.32",
"@types/node": "10.12.18"
}
}
// SAU (Đáng ngờ)
"@types/body-parser": {
"version": "1.17.0",
"dependencies": {
"@types/connect": "*",
"@types/node": "*"
}
}
Những ký tự hoa thị nhỏ? Chúng là wildcards cho biết npm "hãy cho tôi bất kỳ phiên bản nào mà bạn cảm thấy thích hợp." Nó giống như đặt món ăn và nói với người phục vụ "bất ngờ tôi đi" - ngoại trừ bất ngờ có thể là mã độc.
Thay đổi này hoàn toàn bỏ qua việc khóa phiên bản, một trong những hàng rào chính của chúng ta chống lại các tấn công chuỗi cung ứng. Với wildcards, nếu bất kỳ gói nào bị xâm phạm sau này, bạn sẽ tự động kéo phiên bản độc hại trong lần cài đặt tiếp theo.
Đóng Góp "Hữu Ích"
Tôi tìm thấy bằng chứng quan trọng: một pull request từ ngày 5 tháng 9 năm 2025, được gửi bởi một người dùng có tên harshitcodez19. PR này trông có vẻ vô hại - chỉ thêm một số CI/CD với GitHub Actions. Thật chu đáo!
yaml
name: Build on PR
# Heello đây là một tệp ymk được tạo ra cho cICD
on:
push:
branches:
- main # ← Chờ đã, repo của tôi sử dụng 'master'
pull_request:
branches:
- main # ← Điều này cũng sai...
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Sử dụng Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
- name: Cài đặt phụ thuộc
run: npm install # ← Nên là 'npm ci' để đảm bảo an toàn
- name: Chạy Build
run: npm run build
Nhìn thoáng qua, điều này dường như là một người mới đang cố gắng giúp đỡ. Các lỗi chính tả trong bình luận ("Heello", "ymk", "cICD") khiến nó có vẻ như là người đang học hỏi. Cấu hình nhánh cũng sai, vì vậy nó thậm chí sẽ không chạy.
Nhưng điều này - chính xác là cách mà chiến dịch GhostAction hoạt động.
Chiến Dịch GhostAction: Khi GitHub Actions Trở Nên Ác Độc
Thời gian của PR này không phải là tình cờ. Ngày 5 tháng 9 năm 2025 là khi các nhà nghiên cứu bảo mật lần đầu tiên phát hiện ra chiến dịch GhostAction - một cuộc tấn công chuỗi cung ứng tinh vi nhắm vào các kho GitHub.
Dưới đây là cách mà GhostAction hoạt động:
- Do Thám: Kẻ tấn công xác định các kho có phụ thuộc lỗi thời
- Kỹ Thuật Xã Hội: Gửi PR "hữu ích" thêm vào các quy trình CI/CD
- Phá Hoại Có Chủ Đích: Bao gồm những sai lầm rõ ràng để tránh thực thi ngay lập tức
- Kiên Nhẫn: Chờ đợi các nhà duy trì "sửa" các vấn đề rõ ràng
- Khai Thác: Khi quy trình hoạt động, nó thu thập bí mật và thông tin xác thực
Điều thông minh là sự phủ nhận hợp lý. PR trông như một contributor vô hại nhưng thiếu kinh nghiệm. Những "sai lầm" khiến nó có vẻ vô hại. Nhưng một khi những quy trình này chạy với quyền truy cập đúng, thì hết game.
Phân Tích Vector Tấn Công
Hãy phân tích điều gì sẽ xảy ra nếu tôi đã hợp nhất PR này:
yaml
# Cấu hình nhánh sai ngăn chặn thực thi ngay lập tức
on:
push:
branches:
- main # Repo của tôi sử dụng 'master', vì vậy điều này sẽ không kích hoạt
Điều này cho phép kẻ tấn công có thời gian. Nếu tôi đã "sửa" vấn đề nhánh rõ ràng và hợp nhất nó, quy trình sẽ:
yaml
- name: Cài đặt Phụ Thuộc
run: npm install # Kéo các phụ thuộc wildcard
Với những wildcards trong tệp lock của tôi, npm install sẽ lấy các phiên bản mới nhất của @types/node và @types/connect. Nếu những gói đó đã bị xâm phạm (điều mà cuộc tấn công npm lớn đã thực hiện), môi trường CI của tôi sẽ cài đặt mã độc với quyền truy cập đầy đủ tới:
- Bí mật GitHub
- Thông tin xác thực AWS
- Chuỗi kết nối cơ sở dữ liệu
- Khóa API
- Mã thông báo triển khai
Về cơ bản, mọi thứ bạn cần để hoàn toàn sở hữu cơ sở hạ tầng của tôi.
Bối Cảnh Rộng Hơn: Cuộc Tấn Công NPM Lớn Năm 2025
Cuộc tấn công này là một phần của một chiến dịch lớn hơn theo nghiên cứu của OX Security.
Các kẻ tấn công đã:
- Xâm phạm tài khoản của các nhà duy trì gói hợp pháp
- Tiêm mã độc vào các gói đáng tin cậy
- Cụ thể nhắm vào môi trường CI/CD
- Sử dụng GitHub Actions để lấy thông tin xác thực
Tệp lock cũ của tôi, với các gói từ 2018-2019, là mục tiêu hoàn hảo. Các phụ thuộc lỗi thời giống như những ổ khóa cũ - chúng hoạt động cho đến khi một người có công cụ phù hợp xuất hiện.
Những Dấu Hiệu Đỏ Tôi Nên Nhận Ra Sớm Hơn
Nhìn lại, có một vài dấu hiệu cảnh báo:
1. Hồ Sơ Contributor
harshitcodez19có lịch sử đóng góp tối thiểu- Mẫu tên ngẫu nhiên điển hình của các tài khoản tạm
- Không có mối quan hệ thiết lập với dự án của tôi
2. Những "Sai Lầm" Quá Tiện Lợi
- Tên nhánh sai ngăn chặn thực thi ngay lập tức
- Các lỗi chính tả tạo ra sự phủ nhận hợp lý
- Sử dụng
npm installthay vìnpm cian toàn hơn
3. Thời Gian
- Được gửi vào ngày 5 tháng 9 năm 2025 (ngày phát hiện chính xác của GhostAction)
- Các wildcards trong tệp lock của tôi xuất hiện xung quanh cùng thời điểm đó
- Trùng hợp với các vụ xâm phạm chuỗi cung ứng npm lớn hơn
Điều Gì Có Thể Đã Xảy Ra Nếu Cuộc Tấn Công Thành Công
Nếu cuộc tấn công này thành công, đây là những gì kẻ tấn công có thể làm:
bash
# Trong môi trường CI của tôi đã bị xâm phạm:
echo $AWS_SECRET_ACCESS_KEY # Lấy thông tin xác thực đám mây
echo $DATABASE_URL # Đánh cắp quyền truy cập cơ sở dữ liệu
echo $DEPLOY_TOKEN # Xâm phạm pipeline triển khai
# Sau đó chuyển sang:
# - Triển khai backdoor lên production
# - Truy cập dữ liệu khách hàng
# - Khai thác tiền ảo trên cơ sở hạ tầng của tôi
# - Di chuyển sang các hệ thống khác
Bán kính thiệt hại từ một cuộc tấn công CI thành công là rất lớn vì các môi trường CI thường có quyền truy cập cao để triển khai, kiểm tra và tích hợp với các dịch vụ khác.
Thực Hành Tốt Nhất: Cách Để Không Bị Tấn Công
Dưới đây là những gì tôi đã học được và những gì bạn nên làm để bảo vệ bản thân:
1. Vệ Sinh Tệp Lock
bash
# Luôn sử dụng npm ci trong môi trường sản xuất/CI
npm ci # Sử dụng các phiên bản chính xác trong lockfile
# Không bao giờ sử dụng npm install trong CI
npm install # Có thể cập nhật các phiên bản một cách bất ngờ
json
// Giữ tệp lock của bạn ở trạng thái khóa
"dependencies": {
"@types/node": "10.12.18", // ✅ Phiên bản chính xác
"@types/connect": "*" // ❌ Wildcard = nguy hiểm
}
2. Bảo Mật CI/CD
yaml
# Quy trình làm việc GitHub Actions an toàn
name: Bảo mật Xây dựng
on:
pull_request:
branches: [master] # Tên nhánh chính xác
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 # Phiên bản mới nhất
- name: Thiết lập Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm' # Lưu trữ cho hiệu suất
# Sử dụng npm ci cho việc xây dựng tái tạo
- name: Cài đặt phụ thuộc
run: npm ci
# Kiểm tra bảo mật trước khi xây dựng
- name: Kiểm tra bảo mật
run: npm audit --audit-level=critical
- name: Xây dựng
run: npm run build
3. Quản Lý Phụ Thuộc
bash
# Bảo trì định kỳ
npm outdated # Kiểm tra cập nhật
npm audit # Lỗ hổng bảo mật
npm audit fix # Tự động sửa lỗi khi có thể
# Giữ các phụ thuộc hiện tại
npm update # Cập nhật trong các khoảng semver
4. Hướng Dẫn Xem Xét PR
Khi xem xét các PR liên quan đến CI/CD hoặc phụ thuộc:
- Ai là contributor? Họ có lịch sử với dự án của bạn không?
- Tại sao họ thực hiện thay đổi này? PR CI/CD không được yêu cầu là đáng ngờ
- Quyền truy cập nào sẽ được cấp? Kiểm tra bí mật và quyền truy cập môi trường
- Có những "sai lầm" rõ ràng không? Đôi khi lỗi là tính năng cho kẻ tấn công
5. Bảo Vệ Kho
yaml
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: 'npm'
directory: '/'
schedule:
interval: 'weekly'
reviewers:
- 'tên-người-dùng-của-bạn'
Kích hoạt các quy tắc bảo vệ nhánh:
- Yêu cầu xem xét PR cho các thay đổi CI/CD
- Yêu cầu kiểm tra trạng thái phải vượt qua
- Hạn chế ai có thể sửa đổi các quy trình làm việc
Yếu Tố Con Người
Điều đáng sợ nhất của các cuộc tấn công chuỗi cung ứng không phải là sự tinh vi về kỹ thuật – mà là cách chúng khai thác bản chất con người của chúng ta. Chúng ta muốn giúp đỡ các contributor. Chúng ta muốn tin tưởng vào những công cụ mà chúng ta sử dụng hàng ngày. Chúng ta muốn hợp nhất PR mà "sửa" một lỗi rõ ràng.
Nhưng trong thời đại các cuộc tấn công tự động và các gói bị xâm phạm, một chút nghi ngờ có thể đi một chặng đường dài. Contributor thân thiện có thể là một bot. PR hữu ích có thể là một cuộc do thám. Việc sửa lỗi chính tả đơn giản có thể đang thiết lập một backdoor.
Bài Học Rút Ra
- Tin nhưng cần kiểm tra: Ngay cả những PR hữu ích cũng cần phải được xem xét kỹ lưỡng
- Giữ phụ thuộc được cập nhật: Các gói cũ là mục tiêu hấp dẫn
- Sử dụng tệp lock một cách chính xác: Khóa các phiên bản và dùng
npm ci - Bảo mật CI/CD của bạn: Đây là viên ngọc quý mà kẻ tấn công muốn
- Luôn cập nhật thông tin: Theo dõi các nhà nghiên cứu bảo mật và cơ sở dữ liệu lỗ hổng
Ánh Sáng Cuối Đường Hầm
Mặc dù bị nhắm đến bởi một cuộc tấn công chuỗi cung ứng là điều không thoải mái, nhưng nó cũng rất giáo dục. Nó nhắc nhở tôi rằng bảo mật không chỉ là viết mã an toàn – mà còn là bảo vệ toàn bộ quy trình phát triển.
Hệ sinh thái npm cực kỳ mạnh mẽ, nhưng sức mạnh đó đi kèm với trách nhiệm. Mỗi lần npm install là một phiếu bầu tin tưởng vào hàng trăm người duy trì gói. Mỗi quy trình làm việc GitHub Action là một vector tấn công tiềm năng.
Nhưng đừng để điều này khiến bạn sợ hãi khỏi mã nguồn mở. Cộng đồng chính là điều làm cho phát triển JavaScript trở nên tuyệt vời. Chỉ cần thông minh về điều đó. Kiểm tra các phụ thuộc của bạn. Xem xét các quy trình làm việc của bạn. Tin nhưng cần kiểm tra.
Và có thể, chỉ có thể, hãy nghi ngờ một chút khi harshitcodez19 đề nghị giúp đỡ với pipeline CI/CD của bạn.
Chúc các bạn an toàn, các nhà phát triển. Các kẻ tấn công chuỗi cung ứng đang trở nên sáng tạo, nhưng chúng ta cũng vậy.
Tài Liệu Tham Khảo
- OX Security: Các gói NPM bị xâm phạm
- Cơ sở dữ liệu tư vấn bảo mật GitHub
- Tài liệu kiểm tra bảo mật npm
- Bảo mật GitHub Actions