Bảo mật Git Repository: Xóa API Keys và Passwords đã push bằng git-filter-repo hoặc BFG
Hướng dẫn bảo mật Git repository khi lộ API key hoặc password trên GitHub: rotate credential, xóa lịch sử với git-filter-repo/BFG, force push, xác minh và phối hợp team.
ShanverseCập nhật 12 phút đọc— lượt xemĐang tải lượt xem
Git
Secret Management
Supply Chain Security
Một secret đã xuất hiện trên remote có thể tồn tại trong clone, fork, cache, Pull Request, CI log hoặc artifact. Vì vậy xử lý sự cố gồm hai mục tiêu độc lập:
Chặn khả năng bị lợi dụng: revoke/rotate credential và kiểm tra hoạt động bất thường.
Giảm dữ liệu nhạy cảm còn lưu: rewrite Git history, force push và phối hợp cleanup với mọi người liên quan.
Quy trình khẩn cấp trong 15 phút đầu
1. Thu hồi secret ngay lập tức
Vào hệ thống phát hành credential:
Revoke API key/token bị lộ.
Tạo credential mới nếu dịch vụ vẫn cần hoạt động.
Giảm quyền theo nguyên tắc least privilege.
Bình luận
Thay credential ở production, CI/CD và secret manager.
Kiểm tra audit log, IP, request, billing và hành vi bất thường.
Nếu là cloud credential hoặc token có quyền cao, kích hoạt quy trình incident response của tổ chức.
2. Không chia sẻ lại secret
Không dán secret vào:
Issue hoặc Pull Request.
Slack/chat công khai.
Lệnh terminal lưu trong shell history.
File replacement được commit vào repository.
Ticket không có kiểm soát truy cập.
Khi cần nhận diện, chỉ dùng vài ký tự cuối hoặc ID của credential, không dùng toàn bộ giá trị.
3. Khoanh vùng nơi secret xuất hiện
Kiểm tra:
File hiện tại.
Commit history của mọi branch và tag.
Pull Request diff/comment.
GitHub Actions log và artifact.
Release artifact/package.
Fork, mirror và clone của thành viên.
Có thể tìm file theo lịch sử:
Dùng secret scanner như Gitleaks hoặc TruffleHog trên một môi trường kiểm soát. Không in raw secret ra log CI.
4. Thông báo team trước khi rewrite
History rewrite thay đổi commit hash và có thể làm branch của mọi người diverge. Yêu cầu team:
Tạm dừng push/merge.
Không pull/rebase lịch sử cũ vào remote đã làm sạch.
Chuẩn bị re-clone sau khi hoàn tất.
Vì sao xóa file ở commit mới nhất là chưa đủ?
Giả sử:
Commit D xóa file chỉ làm file biến mất ở snapshot mới nhất. Commit C vẫn giữ blob chứa secret và bất kỳ ai có hash hoặc clone cũ vẫn có thể đọc:
Muốn xóa khỏi Git history, cần tạo lại các commit bị ảnh hưởng mà không có secret. Commit hash, tag và branch descendant đều có thể thay đổi.
Chọn git-filter-repo hay BFG?
git-filter-repo thường là lựa chọn mặc định tốt cho cleanup mới. BFG vẫn hữu ích với repository lớn và workflow quen thuộc.
Chuẩn bị an toàn trước khi rewrite
Tạm dừng thay đổi remote
Đóng băng merge/push trong thời gian cleanup.
Ghi lại branch/tag cần giữ.
Xem branch protection/ruleset có chặn force push không.
Chỉ nới protection trong thời gian ngắn, có phê duyệt và khôi phục ngay sau đó.
Tạo bản backup hạn chế truy cập
Bản backup vẫn chứa secret đã lộ. Lưu nó ở vị trí mã hóa, hạn chế quyền và có kế hoạch xóa. Không upload lên nơi chia sẻ chung.
Làm việc trên fresh mirror clone
Mirror clone chứa mọi branch, tag và ref cần cho rewrite. Không làm thử trực tiếp trên clone làm việc duy nhất của bạn.
Cách 1: Xóa file bí mật bằng git-filter-repo
Cài git-filter-repo theo package manager/hướng dẫn chính thức của môi trường, sau đó kiểm tra:
Xóa một file khỏi toàn bộ lịch sử:
Xóa nhiều path:
Ý nghĩa:
--path: chọn path trong lịch sử.
--path-glob: chọn theo pattern.
--invert-paths: giữ mọi thứ trừ path đã chọn.
--sensitive-data-removal: bật hành vi/báo cáo hỗ trợ cleanup dữ liệu nhạy cảm ở phiên bản có hỗ trợ.
Cách 2: Thay secret bằng placeholder với git-filter-repo
Tạo file replacement ngoài repository và giới hạn quyền:
Chạy:
File replacement có thể dùng literal, glob hoặc regex theo cú pháp công cụ. Ưu tiên literal để giảm thay nhầm nội dung.
Sau khi hoàn tất và xác minh, xóa an toàn file chứa giá trị cũ theo policy của tổ chức. Lưu ý shell command, terminal scrollback và backup cũng có thể giữ secret.
Tránh đưa secret vào command line
Không chạy kiểu:
Dùng file có quyền hạn chế hoặc workflow secret-handling được phê duyệt.
Kiểm tra kết quả sau git-filter-repo
Xem báo cáo và thay đổi refs mà công cụ tạo ra. Sau đó kiểm tra:
Quét lại repository:
Hoặc dùng scanner đã được tổ chức phê duyệt. Một scanner không tìm thấy secret không thay thế việc rotate credential.
Kiểm tra branch/tag:
Build/test một clone từ repository đã làm sạch trước khi cập nhật remote.
Force push lịch sử đã làm sạch
Với mirror clone:
Tùy ruleset và ref phía server, một số ref có thể bị từ chối. Không xóa hoặc force push ref không hiểu rõ chỉ để command “xanh”.
Một workflow kiểm soát hơn có thể push branches và tags theo policy:
Sau khi push:
Khôi phục branch protection/ruleset.
Kiểm tra default branch, tag và release.
Chạy CI/security scan.
Kiểm tra secret scanning alert.
Ghi lại old/new commit mapping cho điều tra nội bộ, nhưng không công khai dữ liệu nhạy cảm.
Dùng BFG Repo-Cleaner
BFG chạy trên mirror clone và tối ưu cho việc xử lý blob.
1. Tạo mirror clone
2. Xóa file theo tên
BFG --delete-files tập trung theo tên/blob, không phải full path. Kiểm tra kỹ nếu nhiều file trùng tên.
3. Xóa folder
Dùng pattern phù hợp với cấu trúc repository và test trên bản clone riêng.
4. Thay secret trong text
Tạo file ngoài repo, quyền hạn chế:
Chạy:
5. Dọn object local sau BFG
6. Xác minh và push
Lưu ý quan trọng của BFG: blob protection
BFG mặc định bảo vệ nội dung ở commit tip mới nhất để tránh phá phiên bản hiện tại. Vì vậy:
Xóa secret khỏi snapshot mới nhất trước.
Commit trạng thái sạch.
Sau đó dùng BFG để làm sạch lịch sử cũ.
Có tùy chọn thay đổi cơ chế bảo vệ, nhưng không nên tắt khi chưa hiểu tác động. Luôn kiểm tra current tree sau cleanup.
Sau history rewrite: mọi thành viên phải làm gì?
Khuyến nghị an toàn nhất: re-clone repository.
Nếu có công việc local chưa push:
Tạo patch hoặc branch backup ở vị trí cách ly.
Re-clone repository sạch.
Áp dụng lại thay đổi cần thiết bằng patch/cherry-pick sau khi review.
Không merge/rebase toàn bộ branch cũ vào lịch sử sạch.
Ví dụ tạo patch trước cleanup:
Sau khi clone sạch:
Kiểm tra patch không chứa secret trước khi áp dụng.
GitHub cache, Pull Request và fork
Rewrite repository không đảm bảo mọi bản sao biến mất ngay:
Commit cũ có thể còn trong fork hoặc clone cá nhân.
Pull Request refs có thể giữ object.
Cached view, artifact hoặc release có thể chứa dữ liệu.
Search engine hoặc dịch vụ bên thứ ba có thể đã index nội dung public.
Với dữ liệu nhạy cảm trên GitHub:
Xóa artifact/release chứa secret.
Kiểm tra Actions logs và rerun/cancel phù hợp.
Phối hợp với chủ fork nếu cần.
Liên hệ GitHub Support theo quy trình sensitive-data removal nếu object/cache/ref không thể tự xử lý.
Ngay cả khi Support purge dữ liệu, credential vẫn phải giữ trạng thái revoked.
Ảnh hưởng của history rewrite
Commit hash thay đổi từ điểm chứa secret trở đi.
Pull Request cũ có thể hiển thị diff lạ hoặc mất liên kết commit.
Tag annotated/signed commit có thể cần tạo lại.
Chữ ký commit/tag cũ không còn áp dụng cho commit mới.
CI cache và deployment mapping có thể cần cập nhật.
Open branch của thành viên bị diverge.
Audit link dùng SHA cũ cần mapping nội bộ.
Lên kế hoạch maintenance window và thông báo rõ trước/sau cleanup.
Xác minh secret đã biến mất
Quét mọi refs local
Dùng scanner:
Clone lại từ remote
Quét clone mới, không chỉ clone đã rewrite.
Kiểm tra credential cũ
Xác minh tại provider:
Credential đã revoked.
Request bằng credential cũ bị từ chối.
Không còn hệ thống production dùng credential cũ.
Audit log đã được review trong khoảng thời gian phơi nhiễm.
Không thử credential theo cách làm lộ thêm vào log.
Ngăn sự cố tái diễn
Không lưu secret trong repository
Dùng:
GitHub Actions Secrets/Variables theo đúng mức độ nhạy cảm.
Cloud secret manager.
Vault hoặc hệ thống quản lý secret của tổ chức.
.env local nằm trong .gitignore.
File .env.example chỉ chứa placeholder.
Ví dụ:
Đừng ignore quá rộng nếu repository hợp lệ cần một số public key/certificate; điều chỉnh theo dự án.
Hướng dẫn quản lý secrets với .env và Git: phân loại cấu hình, gitignore, env example, hooks, secret scanning, CI/CD, Next.js, Docker, rotation và incident response.
Hướng dẫn cấu hình .gitignore chuẩn cho dự án Git, Node.js và Next.js: cú pháp pattern, bảo vệ file .env, bỏ qua node_modules, xử lý file đã tracked và kiểm tra rule hiệu quả.
Hướng dẫn Git Aliases và .gitconfig thực chiến: alias an toàn, log đẹp, cấu hình pull/push/rebase, includeIf cho tài khoản work/personal, bảo mật và chia sẻ dotfiles.