6 phút đọc

Lỡ commit file .env lên GitHub, xóa đi vẫn chưa xong

Xóa file .env, xóa commit hay viết lại lịch sử đều không thu hồi được key đã lộ. Việc đầu tiên là đổi khóa, sau đó mới dọn lịch sử, quét bằng gitleaks và chặn trong CI để không lặp lại.

Xem nhanh trong 1 phút

Bạn đẩy code lên GitHub, năm phút sau mới thấy file .env nằm trong commit. Phản xạ đầu tiên của hầu hết mọi người là git rm .env, commit tiếp, rồi thở phào. Có người cẩn thận hơn thì git reset, push --force cho commit đó biến mất.

Cả hai cách đều để key còn sống. Bot quét GitHub công khai liên tục, và một key nằm trên repo public vài phút là đủ để bị chép đi. Theo báo cáo năm 2025 của GitGuardian, năm 2024 có 23,8 triệu bí mật mới lộ trên GitHub công khai, và 70% bí mật lộ từ năm 2022 tới lúc khảo sát vẫn dùng được. Nghĩa là phần lớn người làm lộ đã không đổi key.

Linh vật robot cầm cục tẩy xóa một tờ giấy, nhưng phía sau là hàng loạt bản sao của tờ giấy đó bay ra, mỗi bản kẹp một chiếc chìa khóa

Vì sao xóa không đủ

Git giữ lại mọi thứ. Commit mới xóa .env chỉ làm file biến mất khỏi phiên bản hiện tại, còn ai mở lịch sử ra vẫn thấy. Viết lại lịch sử rồi force push thì sạch hơn, nhưng tài liệu của GitHub nói rõ những chỗ vẫn còn bản sao:

  • Máy của đồng nghiệp đã clone, các fork của repo. Bạn không xóa hộ được.
  • Commit cũ vẫn có thể mở được qua mã SHA trong bộ nhớ đệm của GitHub.
  • Pull request giữ tham chiếu tới commit cũ, phải nhờ GitHub Support gỡ.
  • Và quan trọng nhất: bản đã bị bot chép đi thì không ai thu hồi được.

Vì vậy GitHub khuyên làm theo thứ tự ngược với phản xạ: thu hồi hoặc đổi khóa trước. Key đã vô hiệu thì lộ cũng không dùng được, nhiều khi không cần viết lại lịch sử nữa.

Làm gì trong 30 phút đầu

  1. Liệt kê mọi thứ trong file đó. Mở .env bản đã commit, ghi ra từng dòng: key OpenAI, Anthropic, Stripe, chuỗi kết nối database, JWT_SECRET, mật khẩu SMTP, token bot Telegram.
  2. Đổi từng cái, bắt đầu từ thứ tốn tiền hoặc mở được dữ liệu. Key AI và key thanh toán trước, mật khẩu database ngay sau. Với JWT_SECRET hay SESSION_SECRET, đổi xong mọi người bị đăng xuất, chấp nhận điều đó.
  3. Xem nhật ký sử dụng của từng dịch vụ quanh thời điểm commit: trang usage của nhà cung cấp AI, request log của Stripe, danh sách kết nối vào database. Thấy dòng lạ thì xử lý như sự cố lộ dữ liệu.
  4. Sau đó mới dọn lịch sử nếu repo public hoặc file có dữ liệu không đổi được (ví dụ thông tin khách hàng).

Đổi khóa mà app không chết

Lý do nhiều người ngại đổi key là sợ app sập giữa chừng. Cách làm chung là cho key cũ và key mới cùng chạy một lúc:

  • Tạo key mới, đừng xóa key cũ ngay.
  • Cập nhật biến môi trường trên nền tảng deploy (Vercel, Railway, Render, VPS), deploy lại.
  • Kiểm tra app chạy được với key mới, xem log lỗi.
  • Thu hồi key cũ.

Một số dịch vụ làm sẵn việc này. Stripe cho chọn thời gian hết hạn khi xoay key, key cũ và mới cùng dùng được tối đa 7 ngày. Nhưng với key đã lộ, đừng để khoảng chồng chéo dài: vài phút tới vài giờ là đủ, đúng bằng thời gian deploy.

Mật khẩu database thì làm tương tự: tạo user mới hoặc đặt mật khẩu mới, đổi DATABASE_URL, deploy, rồi xóa user cũ hoặc đổi tiếp mật khẩu cũ.

Dọn lịch sử bằng git-filter-repo

GitHub khuyên dùng git-filter-repo (bản 2.47 trở lên). Làm trên một bản clone mới:

git clone https://github.com/ban/app.git app-sach
cd app-sach
git filter-repo --sensitive-data-removal --invert-paths --path .env
git push --force --mirror origin

Lệnh push sẽ báo lỗi ở các refs/pull/*, đó là bình thường vì GitHub không cho sửa. Sau đó báo mọi người đang có bản clone xóa đi clone lại, và gửi yêu cầu cho GitHub Support nếu có pull request chứa commit cũ. Một lần nữa: bước này chỉ để dọn, không thay được việc đổi khóa.

Quét repo bằng gitleaks

Gitleaks là công cụ mã nguồn mở tìm key, token, mật khẩu trong code và lịch sử Git. Chạy một lần để biết repo đang có gì:

# cài: brew install gitleaks
gitleaks git -v .          # quét toàn bộ lịch sử commit
gitleaks dir -v .          # quét thư mục hiện tại, kể cả file chưa commit

Repo cũ chạy lần đầu thường ra vài kết quả. Mỗi kết quả trỏ tới đúng file, dòng, commit. Cái nào là key thật thì đổi, cái nào là key mẫu trong test thì thêm vào file .gitleaksignore.

Chặn trước khi lọt

Ngay trên máy, cài hook chạy trước mỗi commit. Thêm file .pre-commit-config.yaml:

repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.24.2
    hooks:
      - id: gitleaks

Rồi chạy pre-commit install. Từ đó commit có key sẽ bị chặn.

Trong CI, thêm workflow GitHub Actions để bắt cả những người chưa cài hook:

# .github/workflows/gitleaks.yml
name: gitleaks
on: [push, pull_request]
jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 0
      - uses: gitleaks/gitleaks-action@v3
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Repo của tổ chức (organization) cần thêm GITLEAKS_LICENSE, lấy miễn phí ở gitleaks.io. Tài khoản cá nhân thì không cần.

GitHub cũng có push protection bật sẵn cho tài khoản cá nhân, chặn việc đẩy một số loại key đã biết lên repo public. Nó hữu ích nhưng chỉ nhận ra các mẫu key phổ biến, không thay được gitleaks.

Cất .env ở đâu

  • .env luôn nằm trong .gitignore từ commit đầu tiên. Nhờ AI tạo project thì kiểm lại dòng này, đừng tin nó đã làm.
  • Commit một file .env.example chỉ có tên biến, không có giá trị.
  • Giá trị thật để trong phần Environment Variables của nền tảng deploy, hoặc trình quản lý bí mật như Doppler, Infisical, 1Password. Bản sao lưu .env cũng cất ở đó, không để trong thư mục project rồi zip gửi qua chat.
  • Mỗi môi trường một bộ key: key dùng lúc dev trên máy khác key production. Lộ key dev thì thiệt hại nhỏ hơn nhiều.

Kiểm tra app của bạn trong vài phút

  1. Trong thư mục project, chạy git log --all --oneline -- .env .env.local .env.production. Có dòng nào hiện ra là file đó từng được commit.
  2. Chạy gitleaks git -v . và đọc từng kết quả.
  3. Mở .gitignore, chắc chắn có .env* và có ngoại lệ !.env.example nếu bạn commit file mẫu.
  4. Mở trang usage của nhà cung cấp AI, xem biểu đồ 30 ngày có ngày nào tăng vọt bất thường không.
  5. Nếu bước 1 hoặc 2 ra key thật: đổi key đó hôm nay, trước khi làm bất cứ việc gì khác.

Bạn đã từng lỡ đẩy key lên GitHub chưa, và phát hiện ra bằng cách nào? Vào cộng đồng Vibe Code & Bảo Mật kể lại cho mọi người cùng rút kinh nghiệm.

Nguồn

Chia sẻ lên Facebook

Bình luận

Đang tải bình luận…