Kibana CodeQL 安全扫描实战:自定义查询的本地开发、单元测试、远程 SARIF 获取与内联抑制

📅 发布时间:2026/9/17 8:23:03
Kibana CodeQL 安全扫描实战:自定义查询的本地开发、单元测试、远程 SARIF 获取与内联抑制
Kibana CodeQL 安全扫描实战自定义查询的本地开发、单元测试、远程 SARIF 获取与内联抑制【免费下载链接】kibanaYour window into all of your data项目地址: https://gitcode.com/GitHub_Trending/ki/kibanaKibana 仓库内置了一套完整的 CodeQL 安全扫描工作流以 .github/codeql 目录承载自定义安全查询qlpack以 quick_check.sh 脚本在 Docker 中完成本地建库、分析与单元测试以 fetch_sarif.mjs 脚本从 GitHub 拉取远端扫描结果。本文基于仓库中的 CodeQL 技能文档 与配套源码系统讲解这套体系的目录布局、本地运行方式、单元测试结构、新查询编写规范、内联抑制inline suppression约定以及常见故障排查读完后可直接在本地复现 Kibana 的 CodeQL 开发-测试-验证闭环。整体目录布局Kibana 的 CodeQL 相关资产分布在两个位置.github/codeql/查询与配置和scripts/codeql/本地运行工具.github/codeql/ ├── codeql-config.yml # Main config (paths-ignore, packs, query-filters) ├── custom-queries/ │ ├── qlpack.yml # QL pack definition (name: kibana-custom-queries) │ ├── codeql-pack.lock.yml │ ├── suppression/ # Alert suppression logic │ │ ├── AlertSuppression.ql │ │ └── AlertSuppression.qll │ └── category/ # e.g. dos/, xss/ │ ├── RuleName.ql # Query file │ ├── RuleName.qhelp # Help docs (XML) │ ├── RuleName.md # Human-readable docs │ ├── category-security.qls # Query suite │ └── RuleName/ # Unit test directory │ ├── RuleName.qlref # Points to the .ql file (relative to qlpack root) │ ├── RuleName.expected # Expected test output │ └── test.js # Test source code scripts/codeql/ ├── quick_check.sh # Local analysis via Docker └── codeql.dockerfile # Docker image (ubuntu CodeQL CLI)各组成部分在仓库中均有真实落地可以逐一对照qlpack.yml 定义查询包元信息包名为kibana-custom-queries版本1.0.0依赖官方的codeql/javascript-all库提取器extractor为javascriptname: kibana-custom-queries version: 1.0.0 dependencies: codeql/javascript-all: * extractor: javascriptcodeql-config.yml 是 GitHub CodeQL 分析的主配置包含三部分paths-ignore大规模排除测试夹具**/__fixtures__/**、mock/stub 目录、*.test.*/*.spec.*文件、dev_docs、docs、examples、scripts等非产品代码路径保证扫描聚焦于真实运行代码query-filters排除官方库中与 Kibana 技术栈无关的规则目录codeql/javascript-queries/AngularJS、codeql/javascript-queries/Electronpacks与queries声明官方githubsecuritylab/codeql-javascript-queries查询包并通过uses: ./.github/codeql/custom-queries把自定义查询纳入分析。自定义查询目前已按风险类别组织为dos/拒绝服务与xss/跨站脚本两类另有suppression/承载抑制逻辑。例如 custom-queries/README.md 记录了UnboundedArrayInRoute规则ID 为js/kibana/unbounded-array-in-route用于检测缺少maxSize约束的schema.arrayOf()调用修复方式是添加{ maxSize: N }第二个参数。本地运行分析quick_check.shquick_check.sh 是本地 CodeQL 全流程入口它通过 Docker 构建 CodeQL 数据库并对真实源码运行查询。三种典型用法# 用整个自定义查询目录分析指定源码目录 bash scripts/codeql/quick_check.sh -s source_dir -q .github/codeql/custom-queries # 用单个查询文件分析 bash scripts/codeql/quick_check.sh -s source_dir -q .github/codeql/custom-queries/dos/UnboundedArrayInRoute.ql # 指定结果目录 bash scripts/codeql/quick_check.sh -s source_dir -r .codeql-results -q .github/codeql/custom-queries选项说明选项说明-s source_dir分析模式必填要扫描的源码目录-q query_dir\|query_file自定义查询目录或单个.ql文件-r results_dir数据库与 SARIF 的存放位置默认.codeql/-t改为运行单元测试而非分析配合-q使用不需要-s输出SARIF 文件位于results_dir/database/results.sarif若系统安装了jq脚本会自动打印彩色摘要Rule / Message / File / Line / Security Severity。从源码可以看到脚本的完整执行链路架构适配quick_check.sh#L47-L54先通过uname -m检测本机架构由于 CodeQL CLI 二进制不支持 arm64在 Apple Siliconarm64机器上会自动附加--platform linux/amd64以模拟运行方式执行。镜像构建quick_check.sh#L56-L63首次运行时本地构建名为codeql-env的镜像构建上下文为scripts/codeql/Dockerfile 见下节。建库quick_check.sh#L112-L122把源码目录挂载进容器执行codeql database create /workspace/shared/codeql-db --languagejavascript --source-root/workspace/source-code --overwrite。分析quick_check.sh#L124-L170分三种分支——-q指向单个.ql文件脚本从该文件所在目录逐级向上查找qlpack.yml/codeql-pack.ymlquick_check.sh#L130-L149找到 qlpack 根后以相对路径挂载执行codeql database analyze-q指向目录直接挂载该目录分析未指定-q回退到官方查询集运行codeql database analyze ... javascript-security-and-quality.qls githubsecuritylab/codeql-javascript-queries ... --downloadquick_check.sh#L165-L170。摘要打印quick_check.sh#L178-L219用jq解析 SARIF 的runs[].results[]按ruleId关联tool.driver.rules取出security-severity并着色输出无jq时提示安装并指引用 SARIF 查看器查看完整结果。quick_check.sh#L5 附近还定义了固定常量语言固定为javascript输出格式sarif-latest默认结果目录.codeql镜像名codeql-env。配套镜像 codeql.dockerfile 基于ubuntu:latest安装git、nodejs、jq等基础工具后下载并解压 CodeQL CLIv2.23.2官方 bundle 到/usr/local/codeql-home并以非 root 用户codeql运行USER codeql入口为ENTRYPOINT [/bin/bash, -c]便于docker run直接传入codeql子命令。CodeQL 单元测试单元测试用于验证“查询是否精准命中目标行”。每个测试位于以查询命名的子目录中结构如下category/RuleName/ ├── RuleName.qlref # Reference: category/RuleName.ql ├── test.js # Source code with // $ Alert annotations └── RuleName.expected # Expected output (auto-generated or hand-written)标注约定行尾// $ Alert表示查询应当标记该行未标注// $ Alert的行不应被标记.expected文件为管道分隔格式| location | message |。以仓库中现成的 dos/UnboundedArrayInRoute 测试为例UnboundedArrayInRoute.qlref 内容只有一行dos/UnboundedArrayInRoute.ql即相对 qlpack 根custom-queries/的查询路径test.js 是一组带标注的模拟路由校验代码覆盖多种正负用例例如// BAD: Direct router pattern without maxSize router.post( { path: /api/bad/direct-array, validate: { body: schema.arrayOf(schema.string()), // $ Alert }, }, handler );测试还包含嵌套在schema.object内的数组、只有minSize没有maxSize的空 options 等边界场景以及测试所需的__fixtures__/桩模块UnboundedArrayInRoute.expected 记录预期的告警行与消息。通过 Docker 运行测试复用codeql-env镜像首次运行自动构建# 运行某个具体测试目录 bash scripts/codeql/quick_check.sh -t -q .github/codeql/custom-queries/dos/UnboundedArrayInRoute # 运行 qlpack 下全部测试 bash scripts/codeql/quick_check.sh -t -q .github/codeql/custom-queries从 quick_check.sh#L68-L98 可以看到测试模式的实现-t与-q组合使用时脚本先向上定位 qlpack 根目录找不到则报错退出再把测试路径换算为相对 qlpack 根的路径最后在容器内执行codeql test run /workspace/queries/TEST_REL_PATH --additional-packs /workspace/queries--additional-packs保证查询内import dos.KibanaDoSExclusions这类 qlpack 内部导入可以解析。CI 中的单元测试.github/workflows/codeql-pr.yml 工作流在 PR 触发目标分支main且改动涉及 JS/TS 源码或.github/codeql/**时自动执行三件事权限检查codeql-pr.yml#L18-L50先确认 PR 作者具有admin/maintain/write权限避免外部 PR 触发耗时的分析任务单元测试codeql-pr.yml#L73-L87find .github/codeql/custom-queries -name *.qlref收集所有测试目录并去重逐个执行codeql test run $testdir --additional-packs .github/codeql/custom-queries若一个测试目录都找不到会直接失败防止测试被静默跳过正式分析codeql-pr.yml#L89-L123codeql-action/init指定config-file: ./.github/codeql/codeql-config.yml分析时设置环境变量CODEQL_EXTRACTOR_JAVASCRIPT_OPTION_SKIP_TYPES: true以跳过类型信息提取加快大型仓库的扫描速度。编写新查询编写新查询遵循五步流程对应技能文档 “Writing a New Query” 一节创建.ql文件放在.github/codeql/custom-queries/category/使用id js/kibana/descriptive-id必须全局唯一包含kind problem污点跟踪类查询用path-problem设置problem.severity与security-severityimport javascript引入官方 JavaScript 库可参考 UnboundedArrayInRoute.ql 的既有写法。以现有 DoS 查询为例它的核心思路是先通过schemaVariable()谓词定位从kbn/config-schema导入的schema绑定同时兼容具名导入与命名空间导入再在SchemaArrayOfCall类中匹配arrayOf属性调用并用hasMaxSize()排除已提供maxSize选项的调用/** * Gets the local variable bound to schema imported from kbn/config-schema */ LocalVariable schemaVariable() { exists(ImportDeclaration decl, ImportSpecifier spec | decl.getImportedPathExpr().getStringValue() kbn/config-schema and spec decl.getASpecifier() and ( spec.getImportedName() schema or spec instanceof ImportNamespaceSpecifier ) and result spec.getLocal().getVariable() ) }from SchemaArrayOfCall arrayCall where not arrayCall.hasMaxSize() and not shouldExcludeFileFromDoSRules(arrayCall) select arrayCall, This schema.arrayOf() call does not specify a maxSize. Unbounded input can cause Denial of Service (DoS) vulnerabilities. Consider adding { maxSize: N } as the second argument.注意查询头部还引用了共享的排除逻辑import dos.KibanaDoSExclusions通过shouldExcludeFileFromDoSRules过滤已知误报文件这是 Kibana 自定义查询控制精确率precision medium的一种手段。创建单元测试目录category/RuleName/RuleName.qlref内容为category/RuleName.qltest.js内含// $ Alert标注的测试用例运行测试生成.expected并人工核对是否符合预期。添加.qhelpXML与/或.md作为规则文档。可选若需将多条查询成组运行添加.qls查询套件现有示例如 dos-security.qls。本地实测用quick_check.sh对真实 Kibana 源码跑一遍确认查询在生产代码上的行为。获取远程 SARIF / 扫描结果fetch_sarif.mjs 脚本用于从 GitHub 拉取某个 PR 或分支的 CodeQL 结果# 按 PR 号 GITHUB_TOKENghp_xxx node .agents/skills/codeql/scripts/fetch_sarif.mjs 252121 # 按完整 ref GITHUB_TOKENghp_xxx node .agents/skills/codeql/scripts/fetch_sarif.mjs refs/heads/main要求环境变量GITHUB_TOKEN需具备security_events权限scope脚本依赖octokit/rest已在 Kibana 依赖中。从 fetch_sarif.mjs 源码可以看到它固定针对elastic/kibana仓库执行四个步骤解析 ref输入为纯数字时自动转换为refs/pull/N/mergefetch_sarif.mjs#L44否则原样作为分支 ref 使用列出分析记录调用codeScanning.listRecentAnalyses获取该 ref 最近的 CodeQL 分析取前 10 条无结果直接退出下载 SARIF取最新一条分析经getSarif→analyses_url→ 分析详情 URL 三级跳转以Accept: application/sarifjson拉取完整 SARIF然后遍历runs[].results[]按ruleId关联规则表打印Rule / Severity / Message / File:Line摘要fetch_sarif.mjs#L94-L116拉取告警列表调用codeScanning.listAlertsForRepo获取同一 ref 的 code scanning alerts每页 100 条打印编号、规则、严重级别、状态与最近实例位置。这使开发者无需打开 Web 界面即可在终端核对 CI 扫描结果适合在本地修复误报或确认新告警后与远端数据比对。内联抑制Inline Suppressions对于确实安全的告警Kibana 采用行内抑制注释格式为// codeql[rule-id] justification text且每条抑制必须附带具体理由说明为什么该处是安全的。有效示例// codeql[js/path-injection] User input is validated against an allowlist before use return fs.readFileSync(/etc/${validatedPath}, utf8);无效示例应被标记出来缺少理由// codeql[js/path-injection]后跟任何解释泛化理由false positive、safe、not a vulnerability—— 没有说明实际缓解措施不完整理由如仅写sanitized—— 没有说明以何种机制完成净化。好的理由应描述具体的安全机制例如白名单校验、DOMPurify 转义、shell-quote 库、仅限测试代码等。支撑这套机制的是 suppression/AlertSuppression.ql它是一个kind alert-suppression查询IDjs/alert-suppression定义了单行注释节点SingleLineComment要求注释内不含换行符并复用官方AS::MakeAstNode, SingleLineComment机制使 GitHub 能识别并解析// codeql[...]注释中的规则 ID 与理由文本从而在平台上展示抑制理由。故障排查问题解决方案Docker 在 ARM 上构建失败确认设置了--platform linux/amd64脚本会自动处理见 quick_check.sh#L51-L54报qlpack.ymlnot found脚本从.ql文件所在目录逐级向上查找qlpack.yml—— 确保custom-queries/根目录下存在该文件测试产生.actual文件对比.actual与.expected的 diff ——.actual文件已被 gitignore查询什么都没命中检查 codeql-config.yml 的paths-ignore—— 测试/mock 目录被整体排除摘要因找不到jq而无法打印安装 jq如brew install jq小结Kibana 的 CodeQL 体系形成了“查询包 本地工具 CI 门禁 远端结果”的完整闭环查询包kibana-custom-queries 与 codeql-config.yml 决定扫描范围与规则集quick_check.sh在codeql-env容器CodeQL v2.23.2中统一完成建库、分析与codeql test run并在 arm64 上自动降级为 amd64 模拟执行单元测试.qlreftest.js.expected保证每条规则在改动前后行为可控并由 codeql-pr.yml 在 PR 上强制执行fetch_sarif.mjs补齐了远端结果核对环节内联抑制规范 AlertSuppression.ql 让每一次告警豁免都有据可查。更多查询写法细节可参考 CodeQL 官方“编写 CodeQL 查询”文档随 CodeQL CLI 发布仓库内现成的 dos/ 与 xss/ 查询目录则是最直接的可运行范例。【免费下载链接】kibanaYour window into all of your data项目地址: https://gitcode.com/GitHub_Trending/ki/kibana创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考