第 10 章

安全实践

认证、分支保护、漏洞扫描——给你的代码和账号上保险

一次泄露,前功尽弃——安全是底线

真实的惨剧

这些事故每天在 GitHub 上发生

密钥推上去了

把云服务的 API key 写进代码,一 push 到公开仓库。10 分钟内就有爬虫扫到,刷你几千美元账单。

账号被盗

只用密码没开 2FA,密码泄露后被人改了你的仓库、删了你的代码。没有第二道防线,全军覆没。

依赖藏毒

装了个第三方库,它有已知漏洞。攻击者通过这个漏洞攻破你的应用。你都不知道自己装了什么。

本章把安全基本面铺好:认证三件套(SSH/PAT/2FA)、分支保护、secret scanning、Dependabot。
都是免费个人账号就能用的能力,花半小时配上,省掉未来无数麻烦。

开始之前

适合谁

  • 有 GitHub 账号,但没配过 2FA
  • 担心密钥泄露、账号被盗
  • 想让项目自动检测漏洞和敏感信息

你将学会

  • 配置 SSH key、PAT、2FA
  • 用分支保护防止误操作
  • 开启 secret scanning 和 push protection
  • 用 Dependabot 管依赖漏洞
  • 查看账号安全日志

本章暂不覆盖

  • 企业版安全功能(Audit Log 高级版等)
  • 代码签名(GPG signing)
  • 自托管 runner 安全

认证三件套

SSH key、PAT、2FA——三种保护,各管一摊

SSH keyPAT2FA
保护什么 Git 推送认证 API / 命令行认证 账号登录本身
形式 公私钥对 长字符串令牌 第二因素验证
建议 长期主力开发 限定 scope 和期限 必开
三者不冲突,应该都配。2FA 是账号级防线,SSH/PAT 是操作级认证。少了任何一层,都有对应的攻击路径。

开 2FA

双因素认证——账号安全的第一道也是最重要防线

怎么开

头像 → Settings → Password and authentication → Enable two-factor authentication。

两种方式

  • Authenticator app(推荐):用 Google Authenticator、Authy 扫码,每 30 秒生成验证码
  • SMS:短信收验证码(不如 app 安全)
务必保存恢复码!2FA 开启时会给你一组一次性恢复码。手机丢了时用它登录。没恢复码 + 手机丢失 = 账号永久无法登录,存到密码管理器或打印。

SSH key 详解

公钥放 GitHub,私钥留本地——非对称加密认证

# 1. 生成密钥对(推荐 ed25519 算法)
$ ssh-keygen -t ed25519 -C "你的邮箱"
# 一路回车,或设个私钥密码再加一层保护

# 2. 启动 ssh-agent 并加私钥
$ eval "$(ssh-agent -s)"
$ ssh-add ~/.ssh/id_ed25519

# 3. 复制公钥
$ cat ~/.ssh/id_ed25519.pub

# 4. 加到 GitHub: Settings → SSH and GPG keys → New SSH key

# 5. 测试
$ ssh -T git@github.com
# Hi 用户名! You've successfully authenticated.

SSH 安全要点

让密钥既方便又安全

私钥永不外泄

id_ed25519(无 .pub)是私钥,绝对不能:发给别人、推上仓库、截图发群。它等同于你的身份。

一机一钥

每台设备生成独立密钥对。这样丢一台设备只需吊销对应公钥,不影响其他设备。

定期轮换

怀疑泄露、换电脑时,在 GitHub 删除旧公钥、添加新的。GitHub 不会有「泄露通知」,要自己留意。

加私钥密码

生成时设 passphrase。即使私钥文件被盗,没有密码也用不了。配合 ssh-agent 免每次输入。

PAT 安全

令牌比密码强,但用错一样出事

最小权限原则

生成 PAT 时只勾必要的 scope:

  • 只读公开仓库:public_repo
  • 读写仓库:repo
  • 改设置:额外加 admin:repo_hook

不要勾「全选」——用不上就是风险。

设过期时间

别选 No expiration。90 天或更短。过期后强制重新生成,降低长期泄露风险。

PAT 泄露的应急:立刻到 Settings → Developer settings → Tokens,删除该令牌(不是改,是删)。它立即失效。然后排查有没有被滥用。

分支保护

第 05 章讲过工作流视角,这里看安全视角

防止误操作

  • 禁止 force push(防历史被覆盖)
  • 禁止删除分支
  • 必须 PR 才能合并

强制质量门槛

  • 必须 review approve
  • CI 必须通过
  • 分支必须最新
  • CODEOWNERS 审查
安全角度看分支保护:即使有人 PAT 泄露,攻击者也无法直接改 main——必须走 PR 流程被审查。这是「纵深防御」的一层。
免费版的限制:分支保护只在公共仓库免费可用。免费账号的私有仓库无法启用任何分支保护规则——需升级 GitHub Pro(约 $4/月)。敏感项目想用这层防护,要么公开仓库,要么付费。

secret scanning

GitHub 自动扫描仓库,找出已泄露的密钥

能识别什么

  • 云厂商的 access key(AWS、GCP、Azure)
  • 数据库连接串
  • 各种 SaaS 的 token(Slack、Stripe 等)
  • GitHub 自己的 PAT

怎么开

公开仓库默认开启、完全免费。

免费账号的私有仓库不支持 secret scanning(需付费计划)。所以密钥相关的敏感项目要么公开、要么升级。

扫到会在 Security 标签报警,并通知对应服务商(很多会自动吊销泄露的 key)。

这是救命的功能。很多开发者是在 GitHub 的 secret scanning 告警里,第一次知道自己的 key 泄露了——比刷爆账单才发现早得多。

push protection

更前一步——在你 push 含密钥的提交时直接拦截

和 scanning 的区别

scanning:事后扫描,密钥已经进了仓库历史,再报警让你处理。

push protection:事前拦截,含密钥的 push直接被拒绝,密钥根本进不了仓库。

怎么开

对公开仓库,push protection 对每个用户默认开启,无需手动配置。

私有仓库需要仓库级设置(Settings → Code security → Push protection),免费账号可能不可用。

开启后,push 被拦时本地会收到提示,告诉你哪个文件哪行疑似密钥。

两者配合最佳:push protection 拦新泄露,secret scanning 兜底历史泄露。公开仓库两者都建议开。

已经泄露怎么办

密钥进了仓库历史,光删文件不够

第一步:立即吊销

去对应服务商(AWS/云厂商/SaaS)立即吊销那个 key,生成新的。
这是第一优先级,别先去清理 git 历史。

第二步:清理历史(可选)

用 git filter-repo 或 BFG 清理历史中的密钥。但吊销才是根本——历史可能已被 clone,删了也不保险。

关键认知:git 历史几乎无法真正「删除」。有人 clone 了、fork 了,密钥就还在。
所以正确的做法永远是先吊销让密钥失效,而不是试图抹除痕迹。

Dependabot

自动监控依赖,发现已知漏洞就告诉你

它做什么

  • 扫描 package.json / requirements.txt 等依赖文件
  • 对照漏洞数据库(GitHub Advisory)
  • 发现有漏洞版本的依赖就发告警
  • 能自动开 PR 升级到安全版本

怎么开

Settings → Code security → Dependabot alerts → Enable。
再开 Dependabot security updates 让它自动提升级 PR。

Dependabot 实战

你会在仓库里看到这些

告警

Security 标签出现告警:「lodash 4.17.4 有原型污染漏洞(CVE-xxx)」。点进去看影响范围和修复版本。

自动 PR

Dependabot 自动开 PR:「Bump lodash from 4.17.4 to 4.17.21」。review 合并即修复。连 changelog 都给你附上。

Dependabot 是免费的「安全管家」。装一次,持续监控。学生项目尤其推荐——你通常不知道自己装的库有没有漏洞,Dependabot 替你知道。

版本更新

除了安全漏洞,还能定期升级到最新版

# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"      # 每周检查更新
    open-pull-requests-limit: 5  # 最多同时 5 个升级 PR

安全更新 vs 版本更新

安全更新:有漏洞才开 PR(自动)。

版本更新:定期开 PR 升到最新版(需配 yml)。后者让依赖保持新鲜,避免攒一堆旧债。

Security Advisory

仓库级安全公告——报告和管理漏洞

两种角色

  • 报告者:发现别人仓库漏洞,私下报告给维护者(不公开)
  • 维护者:在修补前不公开,修好后发公告

入口

仓库 → Security → Advisories。可配 CVSS 评分、影响版本、修复版本。

开源项目用这个流程负责任地披露漏洞,避免攻击者抢在修复前利用。

账号安全日志

查看你账号的所有活动记录

在哪看

头像 → Settings → Password and authentication → 底部 Security log。

能看到什么

  • 登录记录(IP、时间、设备)
  • 密码、2FA 的修改
  • PAT、SSH key 的增删
  • 仓库权限变更
定期瞄一眼。看到不认识的 IP 登录、没做过的操作,立即改密码、检查 2FA、吊销可疑令牌。这是发现账号被盗的最快途径。

安全清单

对照这份清单,给你的账号和项目体检

账号级

  • 开了 2FA,恢复码已保存
  • 密码独特(不在别处复用)
  • 定期看 Security log
  • 无用的 PAT 已清理

仓库级

  • main 分支有保护规则
  • secret scanning 已开
  • push protection 已开
  • Dependabot 已开
  • secrets 不在代码里
学生项目至少做到:开 2FA + main 分支保护 + Dependabot。这三样免费、配一次就行,挡住 90% 的常见风险。

CI 里的密钥

workflow 用 secrets 安全,但有几点要注意

不要打印到日志

虽然 GitHub 会自动打码 ${{ secrets.X }},但 echo $TOKEN 这种可能漏出来。日志是公开的(公开仓库)。

PR 慎用

fork 来的 PR 默认访问不到你的 secrets。这是好事——防恶意 PR 偷密钥。需要时手动给特定 PR 加权限。

最小权限

workflow 用 permissions: 显式声明所需权限,别用默认的宽权限。

动手试一试

给自己的账号和仓库上保险

你的任务

任务:按安全清单配置一遍。

要求:

  1. 开启账号 2FA,保存恢复码
  2. 生成 SSH key,加到 GitHub,测试连接
  3. 给自己的仓库开 secret scanning + push protection
  4. 开启 Dependabot alerts 和 security updates
  5. 检查 PAT 列表,删掉不用的、给在用的设短过期
  6. 看一眼 Security log

提示

  1. 2FA 恢复码用密码管理器存,别存笔记软件明文
  2. 已开的功能开关在 Settings → Code security 一页集中看
第 10 章

小结

你已经给自己的代码和账号上了多重保险

本章要点

  • 认证三件套:SSH key(推送)、PAT(API)、2FA(账号)
  • PAT 遵循最小权限 + 短过期
  • secret scanning 事后扫,push protection 事前拦
  • 密钥泄露第一优先级是吊销,不是删历史
  • Dependabot 自动监控依赖漏洞并提升级 PR
  • 定期看 Security log 发现异常
下一步:第 11 章 GitHub API 与集成 —— 最后一章,学习用 REST/GraphQL API 和 webhook 把 GitHub 与外部系统打通。