22、Git安全与权限:HTTPS与SSH安全、GPG签名、权限管理、安全最佳实践
聊到Git安全,很多人第一反应是「我一个小项目,谁没事来攻击我?」
嗯,我以前也这么想。直到有一次,我在一个开源项目里发现有人偷偷往代码里塞了后门——那家伙通过盗用的SSH密钥提交的。从那以后,我对Git安全的看法彻底变了。
说白了,Git安全不是防黑客,而是防「自己人犯错」和「坏人钻空子」。
本章核心脉络:传输安全(HTTPS vs SSH)→ 身份验证(GPG签名)→ 权限控制(仓库级/组织级)→ 日常安全习惯
一、HTTPS与SSH:两种传输协议怎么选?
每次配置Git远程仓库,你都得面对这个选择。我个人习惯是:个人项目用SSH,团队协作用HTTPS。为什么?
1. HTTPS方式
HTTPS走的是443端口,公司防火墙基本不会拦。你想想看,在公司里用SSH连GitHub,有时候会被网络策略卡住,但HTTPS几乎畅通无阻。
不过有个坑——每次push都要输密码。我以前在客户现场演示代码提交,连续输了三次密码都报错,场面一度非常尴尬。
解决办法:配置credential helper缓存密码。
# 缓存15分钟
git config --global credential.helper cache
# 缓存1小时
git config --global credential.helper 'cache --timeout=3600'
# macOS用钥匙串
git config --global credential.helper osxkeychain
# Windows用Git Credential Manager
git config --global credential.helper manager-core
小技巧:如果你用HTTPS clone了仓库,后来想切SSH,直接改remote url就行:git remote set-url origin git@github.com:user/repo.git
2. SSH方式
SSH用的是公钥/私钥对。你生成一对密钥,把公钥扔到GitHub/GitLab上,私钥留在本地。每次push时,Git用私钥签名,服务器用公钥验证。
这样做的好处是:不用输密码,而且更安全。私钥本身还可以加密码保护。
# 生成SSH密钥(推荐ed25519算法)
ssh-keygen -t ed25519 -C "your_email@example.com"
# 或者用RSA 4096位(兼容性更好)
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
# 查看公钥
cat ~/.ssh/id_ed25519.pub
把公钥内容复制到GitHub的 Settings → SSH and GPG keys 里就行。
⚠️ 重要:私钥文件(id_ed25519)权限必须设为600,否则SSH会直接拒绝使用。我曾经遇到过同事把私钥权限设成777,结果SSH死活连不上,排查了半天。
chmod 600 ~/.ssh/id_ed25519
chmod 700 ~/.ssh
3. 多SSH密钥管理
如果你有多个Git账号(比如公司GitLab + 个人GitHub),需要配置~/.ssh/config文件。
# 公司GitLab
Host gitlab.company.com
HostName gitlab.company.com
User git
IdentityFile ~/.ssh/id_ed25519_company
# 个人GitHub
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_personal
这样Git会自动匹配对应的密钥,不会串号。
二、GPG签名:让你的提交「验明正身」
你有没有想过一个问题:Git提交记录里的作者名是可以随便改的。
git config user.name "Linus Torvalds" —— 你看,我瞬间就「变成」了Linux之父。这就是为什么需要GPG签名。
GPG签名相当于给你的每个commit打上一个「防伪标签」。别人看到你的提交旁边有个绿色的「Verified」徽章,就知道这确实是你本人提交的。
1. 生成GPG密钥
# 安装GPG(macOS)
brew install gpg
# 生成密钥
gpg --full-generate-key
# 按照提示选择:
# - 密钥类型:RSA and RSA(默认)
# - 密钥长度:4096
# - 有效期:2年(我个人习惯设2年,到期续)
# - 填写姓名和邮箱(必须和Git配置一致!)
关键点:GPG密钥里的邮箱必须和git config user.email完全一致,否则签名会失败。我踩过这个坑,折腾了半小时才发现是邮箱大小写不匹配。
2. 配置Git使用GPG签名
# 查看GPG密钥ID
gpg --list-secret-keys --keyid-format LONG
# 输出示例:
# sec rsa4096/3AA5C34371567BD2 2024-01-01
# 这里的 3AA5C34371567BD2 就是密钥ID
# 配置Git使用该密钥
git config --global user.signingkey 3AA5C34371567BD2
# 开启全局签名(所有commit自动签名)
git config --global commit.gpgsign true
# 或者只对当前仓库开启
git config commit.gpgsign true
3. 提交时手动签名
如果你不想全局开启,也可以每次提交时加 -S 参数:
git commit -S -m "这是一个经过签名的提交"
4. 把公钥上传到GitHub
导出公钥并添加到GitHub:
gpg --armor --export 3AA5C34371567BD2
复制输出的内容,粘贴到 GitHub Settings → SSH and GPG keys → New GPG key。
之后你的每个commit都会显示绿色的「Verified」标识。嗯,看着就放心。
三、权限管理:谁可以做什么?
权限管理说白了就是回答三个问题:谁能读?谁能写?谁能删?
1. 仓库级别权限
在GitHub/GitLab上,每个仓库可以设置:
- Read:只能clone和pull,不能push
- Triage:可以管理Issue和PR,但不能写代码
- Write:可以push代码
- Maintain:可以管理仓库设置,但不能删除
- Admin:完全控制,包括删除仓库
我个人建议:给开发人员Write权限就够了。Maintain和Admin留给技术负责人。
2. 分支保护规则
这是最实用的功能。你可以设置:
- 禁止直接push到main/master分支:必须通过PR合并
- 要求PR必须经过至少1人review
- 要求状态检查通过(比如CI测试必须全绿)
- 要求提交有GPG签名
# 在GitHub仓库 Settings → Branches → Add rule
# 分支名模式:main
# 勾选:
# ☑ Require a pull request before merging
# ☑ Require approvals (1)
# ☑ Dismiss stale pull request approvals when new commits are pushed
# ☑ Require status checks to pass before merging
# ☑ Require signed commits
避坑指南:我曾经在一个项目里没开「Dismiss stale approvals」,结果有人review通过后,又偷偷加了一行危险代码再合并。从那以后,我所有项目都强制开启「新提交自动撤销旧审批」。
3. 组织级别权限
如果你管理一个团队,建议用组织(Organization)来统一管理:
- 创建团队(如「前端组」「后端组」「QA组」)
- 给团队分配仓库权限
- 新人入职直接加团队,自动获得对应权限
- 离职时从组织移除,所有仓库权限一并收回
四、安全最佳实践:我踩过的坑和总结的经验
1. 密钥管理
- SSH私钥必须加密:生成时设置passphrase,用ssh-agent缓存
- 不要共享密钥:每个人用自己的密钥,不要用「公共账号」
- 定期轮换:我每半年换一次SSH密钥,GPG密钥每2年续期
# 使用ssh-agent缓存密码(只需输入一次)
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
2. 审计与日志
Git本身就有完整的提交历史,但权限操作日志需要平台支持:
- GitHub Audit Log:记录谁改了权限、谁删了仓库
- GitLab Audit Events:类似功能
- 建议每周检查一次审计日志
3. 敏感信息防护
千万不要把密码、API密钥、Token提交到Git仓库!
- 使用.gitignore排除配置文件
- 如果不小心提交了,用
git filter-branch或BFG Repo-Cleaner清理 - 配合pre-commit钩子自动检测敏感信息
# 安装pre-commit钩子
pip install pre-commit
# 在项目根目录创建 .pre-commit-config.yaml
# 配置 detect-private-key 等检查规则
4. 备份策略
Git仓库本身是分布式的,但远程仓库还是可能出问题:
- 定期
git clone --mirror做裸仓库备份 - 重要仓库开启GitHub的仓库备份功能
- 不要只依赖一个远程仓库
⚠️ 血的教训:我曾经有个客户,整个团队只用一台GitLab服务器,没有异地备份。有一天硬盘坏了,所有仓库全丢。幸好我每周五会拉一份裸仓库到本地,才救回了大部分代码。从那以后,我坚持「3-2-1备份原则」——3份数据,2种介质,1份异地。
五、总结
Git安全不是什么高深的技术,说白了就是几个习惯:
- 传输用SSH,省心又安全
- 提交加GPG签名,防冒充
- 权限给最小,分支加保护
- 密钥管好,定期备份
这些习惯花不了多少时间,但能帮你避免很多麻烦。嗯,安全这件事,永远是「防患于未然」比「亡羊补牢」划算得多。
公众号:蓝海资料掘金营,微信deep3321