Ký Commit bằng GPG Key: Bảo vệ Code Khỏi Giả Mạo Danh Tính trong Git

Git tutorial - IT technology blog
Git tutorial - IT technology blog

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.nameuser.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ì.

Share: