CodeQL là công cụ phân tích mã ngữ nghĩa của GitHub. Không giống như các công cụ dựa trên mẫu, CodeQL xử lý mã dưới dạng dữ liệu—bạn truy vấn mã bằng ngôn ngữ chuyên biệt để tìm các lỗ hổng phức tạp mà các công cụ đơn giản hơn bỏ sót.
CodeQL hoạt động như thế nào
CodeQL hoạt động theo hai giai đoạn:
1. Database Creation
Source Code → CodeQL Extractor → CodeQL Database
2. Query Execution
CodeQL Database + Queries → Results
Database Creation phân tích mã của bạn thành cơ sở dữ liệu quan hệ có chứa:
- Các nút Cây cú pháp trừu tượng (AST)
- Thông tin luồng dữ liệu
- Biểu đồ luồng điều khiển
- Nhập thông tin
- Biểu đồ cuộc gọi
Thực thi truy vấn chạy truy vấn QL dựa trên cơ sở dữ liệu này để tìm mẫu.
Cài đặt
CodeQL CLI
# macOS
brew install codeql
# Download from GitHub
# https://github.com/github/codeql-cli-binaries/releases
# Verify installation
codeql --version
# CodeQL command-line toolchain release 2.16.0
Gói truy vấn tiêu chuẩn
# Download standard libraries and queries
codeql pack download codeql/python-queries
codeql pack download codeql/javascript-queries
codeql pack download codeql/java-queries
Tạo cơ sở dữ liệu CodeQL
Trước khi chạy truy vấn, bạn phải tạo cơ sở dữ liệu từ mã nguồn của mình:
# Python project
codeql database create ./codeql-db \\
--language=python \\
--source-root=./src
# JavaScript/TypeScript project
codeql database create ./codeql-db \\
--language=javascript \\
--source-root=.
# Java project (requires build)
codeql database create ./codeql-db \\
--language=java \\
--command='mvn clean compile'
Lưu ý: Các ngôn ngữ được biên dịch (Java, C++, Go) yêu cầu CodeQL để tuân thủ quá trình xây dựng. Các ngôn ngữ được thông dịch (Python, JavaScript) không cần lệnh xây dựng.
Chạy truy vấn bảo mật
Sử dụng gói truy vấn
# Run all security queries for Python
codeql database analyze ./codeql-db \\
codeql/python-queries:codeql-suites/python-security-extended.qls \\
--format=sarif-latest \\
--output=results.sarif
# Run specific query
codeql database analyze ./codeql-db \\
codeql/python-queries:Security/CWE-089/SqlInjection.ql \\
--format=sarif-latest \\
--output=sql-injection.sarif
Bộ truy vấn
| Suite | Mô tả | Trường hợp sử dụng |
|---|---|---|
security-extended.qls |
Truy vấn bảo mật toàn diện | Kiểm toán bảo mật sâu |
security-and-quality.qls |
Bảo mật + chất lượng mã | Quét CI chung |
code-scanning.qls |
Mặc định quét mã GitHub | kiểm tra quan hệ công chúng |
Hiểu ngôn ngữ QL
QL là ngôn ngữ truy vấn hướng đối tượng, khai báo. Tìm hiểu kiến thức cơ bản giúp bạn hiểu kết quả truy vấn và viết truy vấn tùy chỉnh.
Cấu trúc truy vấn cơ bản
/**
* @name Find calls to eval
* @description Detects calls to the eval function
* @kind problem
* @problem.severity warning
* @id py/call-to-eval
*/
import python
from Call call, Name name
where
call.getFunc() = name and
name.getId() = "eval"
select call, "Call to eval() detected"
Các thành phần Query:
import python- Nhập thư viện chuẩn Pythonfrom ... where ... select- Cấu trúc truy vấn giống SQL@kind problem- Truy vấn tạo ra kết quả kiểu cảnh báo@problem.severity- cảnh báo, lỗi hoặc khuyến nghị
Tìm SQL injection (Python)
/**
* @name SQL injection vulnerability
* @description User input flows to SQL query without sanitization
* @kind path-problem
* @problem.severity error
* @id py/sql-injection
*/
import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
import semmle.python.Concepts
module SqlInjectionConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof RemoteFlowSource
}
predicate isSink(DataFlow::Node sink) {
exists(SqlExecution sql | sql.getSql() = sink)
}
}
module SqlInjectionFlow = TaintTracking::Global<SqlInjectionConfig>;
from SqlInjectionFlow::PathNode source, SqlInjectionFlow::PathNode sink
where SqlInjectionFlow::flowPath(source, sink)
select sink.getNode(), source, sink, "SQL injection from $@", source.getNode(), "user input"
Truy vấn này:
- Xác định nguồn (đầu vào của người dùng từ các yêu cầu HTTP)
- Xác định phần chìm (thực thi SQL hàm)
- Sử dụng tính năng theo dõi vết bẩn để tìm đường dẫn từ nguồn đến bồn chứa
- Báo cáo lỗ hổng với đường dẫn luồng dữ liệu
Các khái niệm QL phổ biến
Các lớp và vị từ:
// Class representing function calls
class DangerousCall extends Call {
DangerousCall() {
this.getFunc().(Name).getId() in ["eval", "exec", "compile"]
}
}
// Predicate (reusable condition)
predicate isUserInput(Expr e) {
exists(Call call |
call.getFunc().(Attribute).getName() = "get" and
call.getFunc().(Attribute).getObject().(Name).getId() in ["request", "args", "form"] and
call = e
)
}
Luồng dữ liệu:
// Track data from source to sink
from DataFlow::Node source, DataFlow::Node sink
where
source instanceof RemoteFlowSource and
sink = any(Call c | c.getFunc().(Name).getId() = "eval").getAnArg() and
DataFlow::localFlow(source, sink)
select sink, "User input flows to eval"
Tích hợp quét mã GitHub
Cách dễ nhất để sử dụng CodeQL là thông qua tính năng Quét mã miễn phí của GitHub.
Bật quét mã
- Đi tới kho lưu trữ của bạn trên GitHub
- Nhấp vào Security > Quét mã
- Nhấp vào Thiết lập quét mã
- Chọn Phân tích CodeQL
- Xem lại và quy trình làm việc của commit
Quy trình làm việc mặc định
# .github/workflows/codeql.yml
name: "CodeQL"
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
schedule:
- cron: '0 6 * * 1' # Weekly on Monday
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: ['python', 'javascript']
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
queries: +security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{ matrix.language }}"
Truy vấn tùy chỉnh trong CI
Thêm truy vấn của riêng bạn vào phân tích:
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
queries: +security-and-quality
# Add custom query pack
packs: my-org/my-custom-queries@1.0.0
Hoặc tham khảo các truy vấn địa phương:
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: python
queries: ./codeql/custom-queries/
Viết truy vấn tùy chỉnh
Cấu trúc gói truy vấn
my-queries/
├── qlpack.yml # Pack metadata
├── codeql-suites/
│ └── my-suite.qls # Query suite definition
└── src/
└── security/
├── HardcodedCredentials.ql
└── InsecureRandomness.ql
qlpack.yml:
name: my-org/my-queries
version: 1.0.0
dependencies:
codeql/python-all: "*"
Bộ Query (my-suite.qls):
- queries: .
- include:
kind: problem
- include:
kind: path-problem
Ví dụ: Phát hiện bí mật được mã hóa cứng
/**
* @name Hardcoded credentials
* @description Credentials should not be hardcoded in source code
* @kind problem
* @problem.severity error
* @precision high
* @id py/hardcoded-credentials
* @tags security
* external/cwe/cwe-798
*/
import python
predicate isCredentialVariable(Name name) {
name.getId().toLowerCase().regexpMatch(".*\\b(password|passwd|pwd|secret|api_key|apikey|token|auth)\\b.*")
}
from Assign assign, Name target, StrConst value
where
assign.getATarget() = target and
assign.getValue() = value and
isCredentialVariable(target) and
value.getText().length() > 4 // Ignore empty/short strings
select assign, "Potential hardcoded credential in variable '" + target.getId() + "'"
Kiểm tra truy vấn của bạn
CodeQL hỗ trợ kiểm tra đơn vị cho các truy vấn:
my-queries/
└── test/
└── security/
├── HardcodedCredentials/
│ ├── test.py # Test code
│ └── HardcodedCredentials.expected # Expected results
test.py:
# Test file for hardcoded credentials detection
password = "secret123" # $result
api_key = "AKIA1234567890ABCDEF" # $result
username = "admin" # Safe - not a credential variable
safe_value = get_password_from_vault() # Safe - not a string literal
Chạy thử nghiệm:
codeql test run my-queries/test/
Thực tiễn tốt nhất
1. Bắt đầu với Truy vấn Chuẩn
Các truy vấn tích hợp của CodeQL đã được kiểm tra kỹ lưỡng. Chỉ tùy chỉnh khi bạn có nhu cầu cụ thể.
2. Sử dụng truy vấn đường dẫn cho luồng dữ liệu
Truy vấn đường dẫn (@kind path-problem) hiển thị luồng dữ liệu hoàn chỉnh từ nguồn đến phần chìm, giúp dễ hiểu và khắc phục các lỗ hổng hơn.
3. Điều chỉnh cơ sở mã của bạn
Loại trừ mã được tạo và thư mục nhà cung cấp:
# codeql-config.yml
paths-ignore:
- node_modules
- vendor
- "**/*.generated.py"
4. Cơ sở dữ liệu bộ đệm
Việc tạo cơ sở dữ liệu CodeQL rất tốn kém. Lưu trữ nó trong CI:
- name: Cache CodeQL database
uses: actions/cache@v3
with:
path: .codeql-db
key: codeql-${{ hashFiles('**/*.py') }}
5. Xem lại cảnh báo một cách có hệ thống
Quét mã GitHub hiển thị cảnh báo trong tab Bảo mật. Phân loại chúng:
- Dismiss kèm theo lý do nếu dương tính giả
- Tạo vấn đề cho các lỗ hổng thực sự
- Fix trong PR để sửa lỗi dễ dàng
CodeQL so với các công cụ khác
| tính năng | CodeQL | Semgrep | SonarQube |
|---|---|---|---|
| Độ sâu phân tích | sâu nhất | Dựa trên mẫu | sâu |
| Tốc độ | Chậm | Nhanh | Trung bình |
| Quy tắc tùy chỉnh | Phức tạp (QL) | Dễ dàng (YAML) | Trung bình |
| Luồng dữ liệu | Tuyệt vời | Chỉ chuyên nghiệp | Tốt |
| Miễn phí cho các repo riêng tư | Đã trả tiền | Bị giới hạn | Cộng đồng Ed |
| Tích hợp GitHub | Bản địa | Tốt | Tốt |
Sử dụng CodeQL khi:
- Bạn cần tìm những lỗ hổng phức tạp
- Bạn đang sử dụng GitHub và muốn tích hợp gốc
- Bạn có thời gian để phân tích kỹ lưỡng (quét hàng tuần)
- Bạn đang kiểm tra mã quan trọng về bảo mật
Giá bảo mật nâng cao của GitHub
- Free cho các kho lưu trữ công cộng
- Paid dành cho kho riêng (giấy phép GitHub Advanced Security)
- Bao gồm: Quét mã, Quét bí mật, Đánh giá phụ thuộc
Khắc phục sự cố
Tạo cơ sở dữ liệu không thành công
# Verbose output for debugging
codeql database create ./codeql-db \\
--language=python \\
--source-root=. \\
--verbosity=progress
Hết thời gian truy vấn
# Increase timeout (default 5 minutes)
codeql database analyze ./codeql-db \\
codeql/python-queries:codeql-suites/python-security-extended.qls \\
--timeout=1800 # 30 minutes
Quá nhiều kết quả
# Limit to high-precision queries
codeql database analyze ./codeql-db \\
codeql/python-queries:codeql-suites/python-security-extended.qls \\
--sarif-add-snippets \\
--threads=4
Bài học chính
- CodeQL là phân tích sâu nhất — Tốt nhất để tìm các lỗ hổng phức tạp
- Tạo cơ sở dữ liệu là một bước riêng biệt — Lập kế hoạch cho thời gian xây dựng
- QL mạnh mẽ nhưng phức tạp — Bắt đầu với các truy vấn tiêu chuẩn
- Tích hợp GitHub liền mạch — Miễn phí cho nguồn mở
- Kết hợp với các công cụ nhanh hơn — Sử dụng Semgrep cho tiền commit, CodeQL để quét sâu hàng tuần
Giờ đây, bạn đã có bộ công cụ SAST toàn diện: SonarQube để hiển thị trên toàn nền tảng, Semgrep để có các quy tắc tùy chỉnh nhanh và CodeQL để phân tích ngữ nghĩa sâu. Xếp lớp các công cụ này để phát hiện các lỗ hổng ở mọi giai đoạn phát triển.