Git:Git安全加固
发布时间:2026-04-22 20:01
一、前言
搞过的人都知道,最烦的是代码库裸奔在外网,密码密钥当白菜扔在commit历史里,权限管理跟菜市场似的谁都能进谁都能推。有团队的GitLab账户跟离职员工账号一起飞,有commit直接把生产数据库密码给push上去的。我见过太多这种惨案。今天不废话,直接上Git安全加固的真实操作步骤。
二、操作步骤
第1步:检查Git版本并堵住已知漏洞
git --version
预期输出:
git version 2.39.2
如果版本低于2.39.3(当前LTS稳定版),立刻升级。Git历史漏洞列表自己去查CVE,重点关注remote code execution和credential exposure类的高危漏洞。
CentOS/RHEL:
sudo yum remove git -y
sudo rpm -i https://packages.example.com/git-2.39.3-1.el7.x86_64.rpm
Ubuntu/Debian:
sudo apt update
sudo apt install git -y
sudo add-apt-repository ppa:git-core/ppa
sudo apt update && sudo apt install git -y
第2步:全局锁定危险协议和URL重写
彻底禁用git://协议,这玩意儿走明文TCP,credential直接裸奔在网络上。
git config --global url."https://".insteadOf git://
git config --global url."https://github.com/".insteadOf git@github.com:
预期输出:
git://
git@github.com:
验证配置生效:
git config --global --get-regexp url
预期输出:
url.https://.insteadOf git://
url.https://github.com/.insteadOf git@github.com:
第3步:强制GPG签名提交
没签名验证的commit就是裸奔的身份证,谁都能冒名顶替。
gpg --list-keys
如果没GPG密钥,先生成:
gpg --full-generate-key
# 选择RSA 4096-bit,密码用强密码,切勿用空密码
预期输出:
gpg: key 7A9C3D2E1F0B4A5C marked as ultimate trust.
gpg: revocation certificate stored as '/root/.gnupg/openpgp-revocs.d/XXXXXXX.rev'
pub rsa4096 2024-01-15 [SC]
7A9C3D2E1F0B4A5C6D7E8F9A0B1C2D3E4F5A6B7C
uid ultimate admin@example.com
sub rsa4096 2024-01-15 [E]
导出公钥并配置Git使用:
gpg --armor --export admin@example.com | head -10
预期输出:
-----BEGIN PGP PUBLIC KEY BLOCK-----
Comment: GPGTag marker
mQINBGXXXXX
...
git config --global user.signingkey 7A9C3D2E1F0B4A5C6D7E8F9A0B1C2D3E4F5A6B7C
git config --global commit.gpgsign true
从此每次commit都会弹出GPG签名提示,commit message会带一个verified标签。
第4步:清理Git历史中的敏感信息
⚠️ 警告:以下操作会重写仓库历史,团队协作情况下务必通知所有协作者!务必先备份仓库!
先安装BFG Repo-Cleaner(比git filter-branch快10倍不止):
wget https://repo1.maven.org/maven2/com/madgag/bfg/1.14.0/bfg-1.14.0.jar
mv bfg-1.14.0.jar bfg.jar
清理所有包含密码/密钥/secret的历史记录:
java -jar bfg.jar --replace-text passwords.txt --replace-text secrets.txt --replace-text credentials.txt your-repo.git
预期输出:
Using repo : your-repo.git
Found 23 commits
Cleaning commits
...
Deleted 47 files
...
In total, 23 object ids were changed
...
passwords.txt内容示例(每行一个敏感词匹配模式):
YOUR_PASSWORD=
DB_PASSWORD=
api_secret=
PRIVATE_KEY=
清理完后强制推送:
git reflog expire --expire=now --all && git gc --prune=now --aggressive
第5步:配置Git忽略敏感文件
新建仓库时就把敏感配置挡在门外,别等出事了再想起来加.gitignore。
cat >> .gitignore << 'EOF'
# 配置文件和密钥
*.pem
*.key
*.p12
*.jks
config/secrets.yml
config/credentials.yml
.env
.env.*
*.local
# 数据库连接配置
config/database.yml
config/initializers/database.yml
# 日志和临时文件
*.log
tmp/
vendor/bundle/
# IDE配置
.vscode/
.idea/
*.swp
EOF
如果已经有commit历史的文件需要移除但不删除本地副本:
git rm --cached .env
git rm --cached config/secrets.yml
git commit -m "Remove sensitive files from tracking"
第6步:GitLab/Gitea仓库权限加固
以GitLab为例,企业版的功能比社区版多,但基础权限模型是一样的。
创建受保护分支,只允许特定角色合并:
# 通过GitLab API创建Protected Branch
curl --header "PRIVATE-TOKEN: YOUR_GITLAB_TOKEN"
--request POST
--data "name=main&push_access_level=0&merge_access_level=30"
https://gitlab.example.com/api/v4/projects/123/protected_branches/main
预期输出:
{
"name": "main",
"push_access_levels": [{"access_level": 0}],
"merge_access_levels": [{"access_level": 30}],
"unprotect_access_levels": [{"access_level": 40}]
}
说明:access_level 0 = No one, 30 = Maintainers, 40 = Owners
强制所有分支必须通过Merge Request:
# 设置MR必须成功才能合并
curl --header "PRIVATE-TOKEN: YOUR_GITLAB_TOKEN"
--request POST
--data "id=123&name=main&merge_requests_require_success_to_merge=true"
https://gitlab.example.com/api/v4/projects/123/protected_branches/main
禁止直接push到受保护分支,所有代码必须经过MR+Code Review流程。
第7步:设置Git操作审计日志
GitLab EE版本有内置审计日志,社区版自己搭审计脚本。
# 查看最近的push事件
grep -E "POST|push|refs/heads" /var/log/gitlab/gitlab-rails/production.log | tail -50
预期输出:
POST /api/v4/projects/123/repository/commits
User: admin@example.com
Branch: main
Message: "Update config"
IP: 192.168.1.100
Timestamp: 2024-01-15T10:23:45Z
启用Git事件webhook通知到安全告警系统:
# 在GitLab Admin Area配置webhook
# URL: https://your-siem.example.com/webhook/gitlab
# Events: Push events, Merge request events, Member events
独立Git服务器用auditd记录所有git命令调用:
# CentOS/RHEL
sudo auditctl -w /usr/bin/git -p x -k git_command
# Ubuntu
sudo auditctl -w /usr/bin/git -p x -k git_command
sudo aureport -k | grep git
预期输出:
2. 2024-01-15 10:23:45 git_command /usr/bin/git /home/repos/project
3. 2024-01-15 10:24:12 git_command /usr/bin/git /home/repos/project
...
第8步:配置SSH Key最小权限
# 生成ED25519密钥(比RSA更安全且更短)
ssh-keygen -t ed25519 -C "your_email@example.com" -f ~/.ssh/gitlab_ed25519
预期输出:
Generating public/private ed25519 key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /usr/home/user/.ssh/gitlab_ed25519
Your public key has been saved in /usr/home/user/.ssh/gitlab_ed25519.pub
配置SSH客户端强制使用指定密钥和禁用密码登录:
cat >> ~/.ssh/config << 'EOF'
Host gitlab.example.com
HostName gitlab.example.com
User git
IdentityFile ~/.ssh/gitlab_ed25519
IdentitiesOnly yes
PasswordAuthentication no
PubkeyAuthentication yes
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/github_ed25519
IdentitiesOnly yes
PasswordAuthentication no
EOF
chmod 600 ~/.ssh/config
三、常见问题FAQ
Q:之前已经push上去的密码怎么办?密码已经泄露了怎么救?
A:别想着靠Git加固能解决问题,这种情况下就一个字:改。立刻去改掉所有用过的密码,撤销所有可能相关的API Key,通知安全团队这是个P0事件。Git历史删不掉,就算你重写了历史,github/gitlab的缓存和 forks 都可能还存着老版本。去haveibeenpwned.com查你的邮箱有没有泄露记录。另外,如果密码对应的是数据库或生产环境密码,立刻启动应急预案,那套密码直接报废,别抱侥幸心理。
Q:团队成员觉得GPG签名太麻烦,都想禁用,怎么说服他们?
A:现实点讲,你要是团队负责人,直接在GitLab/Gitea那边强推protected branch + require signed commits,不签名的commit根本push不上去,谁都别想绕过。要是普通开发者的角色,那就拿具体案例说话——2019年GitLab被黑客利用弱凭证删除数据的事故自己百度去,告诉他们不签名就是在裸奔。你要是跟我吐槽说团队里的人都是老油条根本不管这套,那只能说明你们公司安全建设本来就没做好,先去找领导要授权。
Q:公司内网GitLab服务器,想省事不做HTTPS行不行?
A:行个屁,内网不等于安全。内网横向渗透了解一下?你们的DHCP服务器、DNS服务器、交换机management口被拿下过吗?代码仓库是核心资产,别拿"内网"当借口省掉TLS。省事的结果就是有一天某台员工笔记本中马,内网DNS被劫持,git pull的时候凭证直接被明文拿走。内网GitLab装自签名证书的成本是零,就一个命令的事情,别找借口。
Q:离职员工的账户和SSH Key怎么处理?
A:离职当天就要revoke GitLab账户和所有SSH Key,这是IT Ops的活,别拖。GitLab Admin Panel直接disable账号,同时检查这个人创建的所有Deploy Key和Personal Access Token,全部删除。另外review一遍这个人参与过的仓库,看有没有被加进不相关的项目。如果用的是自建的Gitea,同样的流程在Admin面板操作一遍。GitHub的话去enterprise settings批量处理。别跟我说你们没有统一管理,权限管理烂到这种程度出事只是时间问题。
四、总结
核心要点记住三条:
- 堵住传输层漏洞:禁用git://协议,强制HTTPS/SSH,GPG签名commit是基操。这些做不好,后面都是白搭。
- 清理历史敏感数据:BFG Repo-Cleaner定期跑,password、secret、credential全部从历史里清干净。清理完重写历史后记得通知所有协作者rebase。密码一旦泄露就当废掉,别侥幸。
- 权限管控和审计:受保护分支强推MR+Code Review流程,离职人员账户即时revoke,auditd记录所有git操作日志。权限管理不是一次性的,是持续运营的事。
延伸阅读: