L’interface est localisée ; les présentations et documents des Skills sont traduits automatiquement par IA dans votre langue. Le code, les commandes, chemins et termes techniques restent en version originale, et le document de l’auteur fait foi.
Explorer les Skills
Développement · SKILL.md

securing-github-actions-workflows

securing-github-actions-workflows

本技能涵盖加固 GitHub Actions 工作流以防范供应链攻击、凭据盗窃和权限提升。 内容包括将 action 固定到 SHA 摘要、最小化 GITHUB_TOKEN 权限、防止机密泄露、 防止工作流表达式中的脚本注入,以及为工作流变更实施必要的审阅者机制。

Independent GitHub snapshot · Automated classification · Original documentation governs

Documentation de la Skill

GitHub

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

# 安全:固定到不可变的 SHA 摘要
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11  # v4.1.1

# 使用 Dependabot 自动更新固定的 SHA
# .github/dependabot.yml
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  # 用于基于 OIDC 的云认证
    steps:
      - name: Deploy
        run: echo "deploying"

步骤 3:防止脚本注入

# 存在漏洞:run 步骤中包含用户控制的输入
- run: echo "PR title is ${{ github.event.pull_request.title }}"

# 安全:使用环境变量(由 shell 正确转义)
- 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}"

# 安全:使用 actions/github-script 处理复杂操作
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea
  with:
    script: |
      const title = context.payload.pull_request.title;
      console.log(`PR title: ${title}`);

步骤 4:安全处理 Fork Pull Request

# 危险:pull_request_target 以基础仓库权限运行
# on: pull_request_target  # 除非绝对必要,否则避免使用

# 安全:pull_request 在 fork 上下文中以有限权限运行
on:
  pull_request:
    branches: [main]

# 如果必须使用 pull_request_target,切勿检出 PR 代码:
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:
      # 切勿执行:带 ref: ${{ github.event.pull_request.head.sha }} 的 actions/checkout
      - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
        # 这会检出基础分支,而非 PR 分支

步骤 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:实施工作流变更控制

# 要求 CODEOWNERS 审批工作流变更
# .github/CODEOWNERS
.github/workflows/ @security-team @platform-team
.github/actions/ @security-team @platform-team

# 组织设置:
# 1. 设置 > Actions > 常规 > Fork PR 策略
#    - 首次贡献者需要审批
#    - 所有外部协作者需要审批
# 2. 设置 > Actions > 常规 > 工作流权限
#    - 读取仓库内容和包的权限
#    - 不允许 GitHub Actions 创建和审批 PR

关键概念

术语定义
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 的仓库自动拉取恶意版本。

方法:

  1. 立即在所有仓库中将所有 action 固定到 SHA 摘要
  2. 为 github-actions 生态系统配置 Dependabot 以管理 SHA 更新
  3. 限制 GITHUB_TOKEN 权限,使即便受攻陷的 action 也只有最小访问权限
  4. 添加 StepSecurity harden-runner 以检测异常的出站网络调用
  5. 审查所有第三方 action,并将不必要的替换为内联脚本
  6. 要求对 .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 个高危发现)
Skills enregistrées