22、Git安全与权限:HTTPS与SSH安全、GPG签名、权限管理、安全最佳实践

聊到Git安全,很多人第一反应是「我一个小项目,谁没事来攻击我?」

嗯,我以前也这么想。直到有一次,我在一个开源项目里发现有人偷偷往代码里塞了后门——那家伙通过盗用的SSH密钥提交的。从那以后,我对Git安全的看法彻底变了。

说白了,Git安全不是防黑客,而是防「自己人犯错」和「坏人钻空子」。

本章核心脉络:传输安全(HTTPS vs SSH)→ 身份验证(GPG签名)→ 权限控制(仓库级/组织级)→ 日常安全习惯

Git 安全与权限知识体系 Git 安全 传输安全 HTTPS vs SSH 身份验证 GPG 签名 权限管理 仓库/组织级控制 安全最佳实践 密钥管理 · 审计 · 备份 四个维度层层递进,构建完整的 Git 安全防线

一、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