Bạn có biết rằng bất kỳ ai cũng có thể commit code với tên và email của bạn mà không cần password hay xác thực gì không? Không phải lỗ hổng mới được phát hiện — đây là cách Git hoạt động từ đầu, và phần lớn developer không nghĩ đến điều này cho đến khi nó xảy ra với chính họ.
Vấn đề thực tế: Git không kiểm tra danh tính người commit
Git mặc định không verify danh tính người commit. Chỉ cần hai lệnh đơn giản:
git config user.email "[email protected]"
git config user.name "Nguyen Van A"
Thế là xong — từ giờ mọi commit trên máy đó sẽ mang tên “Nguyen Van A”, kể cả khi người thực hiện không phải là anh ấy. GitHub, GitLab đều hiển thị avatar dựa trên email, nhưng bản thân commit không có cơ chế xác thực nào cả.
Tình huống này xảy ra nhiều hơn bạn nghĩ:
- Thành viên trong team vô tình dùng sai email trong git config trên máy mới
- Máy CI/CD được cấu hình sai danh tính
- Kẻ xấu muốn giả mạo commit history trong dự án open source
Tại sao Git lại dễ bị giả mạo đến vậy?
Git được thiết kế theo kiến trúc phân tán — không có server trung tâm để xác thực danh tính. Email và tên trong git config chỉ là metadata đơn thuần, không khác gì tự ghi tên vào một tờ giấy.
Git không hỏi bất kỳ server nào để kiểm tra email đó có thật không. Cũng không kiểm tra người dùng có quyền commit dưới danh nghĩa email đó không. Đây là trade-off có chủ ý: Git ưu tiên tốc độ và tính offline, còn bảo mật danh tính là trách nhiệm của layer bên trên — hosting platform, CI/CD, hoặc convention của team.
Ba cách xử lý — và chỉ một cái thực sự đúng
Cách 1: Tin tưởng vào platform (không nên)
GitHub và GitLab đối chiếu email commit với tài khoản đăng ký. Nhưng nếu ai đó biết email của bạn và dùng đúng email đó trong git config, platform vẫn hiển thị avatar của bạn — dù người commit không phải bạn.
Cách 2: Dùng SSH key cho push (bảo vệ sai chỗ)
SSH key xác thực ai có quyền push lên repo, nhưng không xác thực ai đã tạo từng commit. Hai thứ này hoàn toàn khác nhau.
Cách 3: GPG Signed Commits (cách đúng)
GPG (GNU Privacy Guard) cho phép ký số vào từng commit. Chữ ký mã hóa này chỉ có thể tạo ra bằng private key của bạn, và bất kỳ ai cũng có thể verify bằng public key. Đây là cách duy nhất đảm bảo cryptographically rằng commit được tạo bởi đúng người.
Cách làm đúng: Setup GPG Signed Commits từng bước
Bước 1: Cài đặt GPG
Ubuntu/Debian:
sudo apt install gnupg
macOS:
brew install gnupg
Kiểm tra đã cài thành công:
gpg --version
Bước 2: Tạo GPG key pair
gpg --full-generate-key
Khi được hỏi, chọn:
- Key type: RSA and RSA (option 1)
- Key size: 4096 bit (bảo mật cao hơn 2048)
- Expiry:
1y— nên đặt expiry, không để vĩnh viễn - Name và email: phải khớp chính xác với
git config user.namevàuser.email
Bước 3: Lấy Key ID
gpg --list-secret-keys --keyid-format=long
Output trông như này:
sec rsa4096/3AA5C34371567BD2 2024-01-15 [SC] [expires: 2025-01-15]
1234567890ABCDEF1234567890ABCDEF12345678
uid [ultimate] Nguyen Van A <[email protected]>
Key ID là phần sau dấu / — ở đây là 3AA5C34371567BD2. Copy nó lại để dùng ở bước sau.
Bước 4: Cấu hình Git dùng GPG key
git config --global user.signingkey 3AA5C34371567BD2
git config --global commit.gpgsign true
Option commit.gpgsign true bật auto-sign cho tất cả commit — không cần nhớ thêm flag -S mỗi lần commit nữa.
Bước 5: Thêm public key lên GitHub hoặc GitLab
Export public key ra dạng text:
gpg --armor --export 3AA5C34371567BD2
Copy toàn bộ output (từ -----BEGIN PGP PUBLIC KEY BLOCK----- đến -----END PGP PUBLIC KEY BLOCK-----).
Trên GitHub: vào Settings → SSH and GPG keys → New GPG key, paste vào và lưu.
Bước 6: Test thử và verify
Commit bình thường, không cần thêm gì:
git commit -m "feat: add user authentication"
Verify chữ ký commit vừa tạo:
git log --show-signature -1
Output khi ký thành công:
commit a1b2c3d4e5f6...
gpg: Signature made Mon 15 Jan 2024 10:30:00 JST
gpg: using RSA key 3AA5C34371567BD2
gpg: Good signature from "Nguyen Van A <[email protected]>" [ultimate]
Author: Nguyen Van A <[email protected]>
Date: Mon Jan 15 10:30:00 2024 +0900
feat: add user authentication
Commit được ký hợp lệ sẽ hiển thị badge Verified màu xanh trên GitHub, ngay cạnh commit message.
Xử lý lỗi thường gặp
Lỗi “gpg failed to sign the data”
GPG cần biết terminal để hiển thị prompt nhập passphrase. Thêm vào ~/.bashrc hoặc ~/.zshrc:
export GPG_TTY=$(tty)
Sau đó reload:
source ~/.bashrc
Cấu hình pinentry trên macOS
macOS nên dùng pinentry-mac để nhập passphrase qua popup thay vì terminal — tiện hơn nhiều:
brew install pinentry-mac
echo "pinentry-program /opt/homebrew/bin/pinentry-mac" >> ~/.gnupg/gpg-agent.conf
gpgconf --kill gpg-agent
Enforce GPG signing bắt buộc cho cả team
Muốn áp dụng cho toàn team? Vào GitHub → Repository Settings → Branches → Branch protection rules → bật “Require signed commits”. Từ đó mọi commit merge vào nhánh được bảo vệ đều phải có GPG signature hợp lệ — không ký thì không merge được.
Verify trong CI/CD pipeline:
git verify-commit HEAD
Exit code 0 = signature hợp lệ, khác 0 = không có hoặc signature sai.
Backup GPG key — bước quan trọng hay bị bỏ qua
Mình từng mất code quan trọng vì force push nhầm branch — từ đó luôn cẩn thận với mọi thao tác git không thể undo. GPG key cũng vậy. Mất private key là mất luôn khả năng ký commit mới bằng key đó. Tệ hơn nữa: nếu key hết hạn mà không có backup, bạn phải tạo key mới từ đầu — toàn bộ commit cũ sẽ hiện Unverified trên GitHub.
Backup ngay sau khi tạo key:
# Export cả private và public key
gpg --export-secret-keys 3AA5C34371567BD2 > my-gpg-private-key.asc
gpg --export 3AA5C34371567BD2 > my-gpg-public-key.asc
Lưu file .asc vào USB hoặc password manager (Bitwarden, 1Password đều hỗ trợ lưu file đính kèm). Đừng upload lên cloud storage thông thường.
Khi cần restore trên máy mới:
gpg --import my-gpg-private-key.asc
Tóm tắt các lệnh cần nhớ
# Tạo key pair mới
gpg --full-generate-key
# Xem danh sách key hiện có
gpg --list-secret-keys --keyid-format=long
# Export public key để thêm lên GitHub
gpg --armor --export KEY_ID
# Cấu hình git dùng key
git config --global user.signingkey KEY_ID
git config --global commit.gpgsign true
# Verify commit đã ký
git log --show-signature -1
# Backup private key
gpg --export-secret-keys KEY_ID > backup-private.asc
Setup mất khoảng 15 phút. Đổi lại, mọi commit của bạn đều mang chữ ký cryptographic — ai cũng verify được, không ai giả mạo được. Nếu bạn contribute vào các dự án open source lớn như curl hay Kubernetes, nhiều maintainer nhìn vào badge Verified trước khi review code. Đó là tín hiệu ngầm: người này biết mình đang làm gì.
