| name | securing-github-actions-workflows |
| description | 本技能涵盖加固 GitHub Actions 工作流以防范供应链攻击、凭据盗窃和权限提升。 内容包括将 action 固定到 SHA 摘要、最小化 GITHUB_TOKEN 权限、防止机密泄露、 防止工作流表达式中的脚本注入,以及为工作流变更实施必要的审阅者机制。
|
| domain | cybersecurity |
| subdomain | devsecops |
| tags | ["devsecops","cicd","github-actions","supply-chain","workflow-security","secure-sdlc"] |
| version | 1.0.0 |
| author | mahipal |
| license | Apache-2.0 |
加固 GitHub Actions 工作流
使用场景
- 当 GitHub Actions 是 CI/CD 平台且工作流需要针对供应链攻击进行加固时
- 当工作流处理机密、部署到生产环境或具有提升的权限时
- 当需要防止通过不受信任的 PR 标题、分支名称或提交信息进行脚本注入时
- 当需要工作流修改的审计跟踪和审批门禁时
- 当第三方 action 通过可变版本标签带来供应链风险时
不适用于加固其他 CI/CD 平台(参见特定平台加固指南)、应用程序漏洞扫描(使用 SAST/DAST)或代码中的机密检测(使用 Gitleaks)。
前置条件
- 已启用 GitHub Actions 的 GitHub 仓库
- GitHub 组织管理员访问权限(用于组织级设置)
- 了解 GitHub Actions 工作流语法和事件
操作流程
步骤 1:将 Action 固定到 SHA 摘要
- uses: actions/checkout@v4
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
commit-message:
prefix: "ci"
步骤 2:最小化 GITHUB_TOKEN 权限
name: CI Pipeline
permissions: {}
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
deploy:
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/main'
permissions:
contents: read
deployments: write
id-token: write
steps:
- name: Deploy
run: echo "deploying"
步骤 3:防止脚本注入
- run: echo "PR title is ${{ github.event.pull_request.title }}"
- name: Process PR
env:
PR_TITLE: ${{ github.event.pull_request.title }}
PR_BODY: ${{ github.event.pull_request.body }}
run: |
echo "PR title is ${PR_TITLE}"
echo "PR body is ${PR_BODY}"
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea
with:
script: |
const title = context.payload.pull_request.title;
console.log(`PR title: ${title}`);
步骤 4:安全处理 Fork Pull Request
on:
pull_request:
branches: [main]
on:
pull_request_target:
types: [labeled]
jobs:
safe-job:
if: contains(github.event.pull_request.labels.*.name, 'safe-to-test')
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
步骤 5:保护机密和环境变量
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- name: 使用机密进行部署
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
run: |
# 切勿打印机密
# echo "$DEPLOY_KEY" # 错误做法
deploy-tool --key-file <(echo "$DEPLOY_KEY")
- name: 审计机密访问
run: |
# 记录机密使用情况而不暴露内容
echo "::notice::已为生产部署访问部署密钥"
步骤 6:实施工作流变更控制
.github/workflows/ @security-team @platform-team
.github/actions/ @security-team @platform-team
关键概念
| 术语 | 定义 |
|---|
| SHA 固定 | 通过不可变的提交 SHA 而非可变版本标签引用 GitHub Action |
| 脚本注入 | 不受信任的输入(PR 标题、分支名称)被插入到 shell 命令中的攻击 |
| GITHUB_TOKEN | 自动生成的令牌,权限范围限于当前仓库,可配置 |
| pull_request_target | 危险的事件触发器,在 fork PR 上以基础仓库的完整权限运行 |
| 环境保护 | GitHub 功能,要求在访问环境的作业运行前进行人工审批 |
| CODEOWNERS | 定义特定路径(包括工作流文件)所需审阅者的文件 |
| OIDC 联合 | 使用 GitHub 的 OIDC 令牌向云提供商认证,无需存储长期凭据 |
工具与系统
- Dependabot:自动化依赖更新器,保持固定的 action SHA 处于最新状态
- StepSecurity Harden Runner:监控并限制工作流出站网络调用的 GitHub Action
- actionlint:检测安全问题的 GitHub Actions 工作流文件代码检查器
- allstar:OpenSSF 的 GitHub App,对仓库强制执行安全策略
- scorecard:评估供应链安全实践(包括 CI/CD)的 OpenSSF 工具
常见场景
场景:防范受攻陷的第三方 Action 供应链攻击
背景:一个广泛使用的 GitHub Action 被攻陷,其 v3 标签被更新为包含凭据盗窃代码。使用 @v3 的仓库自动拉取恶意版本。
方法:
- 立即在所有仓库中将所有 action 固定到 SHA 摘要
- 为 github-actions 生态系统配置 Dependabot 以管理 SHA 更新
- 限制 GITHUB_TOKEN 权限,使即便受攻陷的 action 也只有最小访问权限
- 添加 StepSecurity harden-runner 以检测异常的出站网络调用
- 审查所有第三方 action,并将不必要的替换为内联脚本
- 要求对
.github/workflows/ 的任何变更进行 CODEOWNERS 审批
注意事项:不使用 Dependabot 的 SHA 固定意味着错过 action 的合法安全更新。过于严格的权限可能破坏合法工作流。使用 pull_request_target 进行基于标签的门控,如果工作流检出 PR 代码仍会暴露机密。
输出格式
GitHub Actions 安全审计
================================
仓库:org/web-application
日期:2026-02-23
工作流分析:
工作流总数:8
Action 引用总数:34
SHA 固定:
[失败] 12/34 个 action 使用可变标签而非 SHA 摘要
- .github/workflows/ci.yml: actions/setup-node@v4
- .github/workflows/deploy.yml: aws-actions/configure-aws-credentials@v4
权限:
[失败] 3/8 个工作流没有明确权限定义(继承默认值)
[警告] 1/8 个工作流请求 write-all 权限
脚本注入:
[失败] 2 个工作流步骤直接插入用户输入
- .github/workflows/pr-check.yml:23: ${{ github.event.pull_request.title }}
机密:
[通过] 工作流日志中没有暴露机密
[通过] 所有生产部署使用环境保护
评分:6/10(修复 5 个高危发现)