mirror of
https://github.com/alibaba/higress.git
synced 2026-05-21 11:17:28 +08:00
6.6 KiB
6.6 KiB
title, keywords, description
| title | keywords | description | |||||
|---|---|---|---|---|---|---|---|
| Nginx Rewrite 兼容迁移 |
|
nginx rewrite + set 安全迁移插件说明 |
功能说明
nginx-rewrite-compatible 插件提供与 nginx rewrite + set 指令组合等价的常见能力,包括路径重写、查询串追加或替换、正则捕获组变量保存,以及通过请求头将变量传递给上游服务。
这个插件面向从 Nginx 迁移到 Higress 的场景,作为安全替代方案,避免继续依赖受 CVE-2026-42945 影响的重写链路。
安全背景
CVE-2026-42945 是一个与 Nginx rewrite 和 set 指令组合相关的长期堆溢出问题,漏洞存在约 18 年。其触发条件集中在以下模式:
rewrite使用带?的替换目标,在一次 rewrite pass 中同时修改 URI 和 query string。set在后续步骤中继续引用前一次正则匹配得到的捕获组,如$1、$2。- 两次 pass 之间,rewrite 状态和捕获组状态没有保持一致,导致后续
set读取了不匹配的捕获组元数据,最终触发越界访问和堆溢出。
Higress 的 WASM 插件没有这个问题,原因是:
- 每个请求都在独立的 WASM 上下文中处理。
- 本插件在一次请求回调内完成“匹配、重写、变量保存、向上游透传”全过程,不依赖 Nginx rewrite module 的两阶段状态机。
- 捕获组结果只存在当前请求的内存和请求属性中,不会跨 pass 泄漏,也不会复用失配状态。
运行属性
插件执行阶段:默认阶段
插件执行优先级:100
配置字段
| 字段名 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
rules |
array of object | 是 | - | 重写规则列表,按顺序执行 |
rules 配置说明
| 字段名 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
regex |
string | 是 | - | 匹配请求 path 的正则表达式,不包含 query string |
replacement |
string | 是 | - | 新的路径模板,支持 $1、$2 等捕获组引用 |
query_append |
string | 否 | - | 追加到原 query string 的片段,支持 $1、$2 |
query_template |
string | 否 | - | 完全替换原 query string 的模板,支持 $1、$2 |
set_vars |
array of object | 否 | - | 将捕获组写入请求级变量,或按变量名前缀改写 query/header/cookie |
pass_to_upstream |
bool | 否 | false |
是否把当前规则的变量同时写入请求头传给上游 |
mode |
string | 否 | last |
规则流转模式,支持 break 和 last |
说明:
query_append和query_template不能同时配置。mode: break表示命中当前规则后停止继续匹配后续规则。mode: last表示命中当前规则后,使用重写后的 path 继续匹配后续规则。set_vars中,arg_前缀会修改请求 query parameter,http_前缀会修改请求 header,cookie_前缀会修改请求 cookie,其他变量名会通过proxywasm.SetProperty([]string{"nginx_rewrite_compatible","vars",name})保存。http_前缀对应的 header 名称会去掉前缀,并把下划线转换成横杠。- 当
pass_to_upstream: true时,变量还会额外写入请求头x-higress-rewrite-var-<name>。
set_vars 配置说明
| 字段名 | 类型 | 必填 | 说明 |
|---|---|---|---|
name |
string | 是 | 变量名。arg_/http_/cookie_ 前缀分别表示写 query parameter、header、cookie;其他名称表示自定义属性 |
capture_group |
int | 是 | 捕获组编号,0 表示整个匹配,1 表示第一个分组 |
Nginx 配置对照表
1. 简单路径重写
Nginx:
rewrite ^/old/(.*)$ /new/$1;
插件配置:
rules:
- regex: ^/old/(.*)$
replacement: /new/$1
2. 正则捕获组替换
Nginx:
rewrite ^/product/([0-9]+)$ /detail/$1;
插件配置:
rules:
- regex: ^/product/([0-9]+)$
replacement: /detail/$1
3. Query String 操作
追加 query:
rewrite ^/api/(.*)$ /internal?migrated=true;
rules:
- regex: ^/api/(.*)$
replacement: /internal
query_append: migrated=true
替换 query:
rewrite ^/x/(.*)/(.*)$ /y?a=$1&b=$2;
rules:
- regex: ^/x/(.*)/(.*)$
replacement: /y
query_template: a=$1&b=$2
4. 特殊变量前缀
rules:
- regex: "^/api/(.*)/(.*)$"
replacement: "/internal"
set_vars:
- name: original_path
capture_group: 1
- name: http_x_original
capture_group: 1
- name: arg_source
capture_group: 2
- name: cookie_track_id
capture_group: 1
语义:
original_path保存为请求属性,可供后续插件通过GetProperty(["nginx_rewrite_compatible","vars","original_path"])读取。http_x_original设置请求头x-original。arg_source设置 query parametersource。cookie_track_id设置 cookietrack_id。
5. 变量保存与传递
Nginx:
rewrite ^/api/(.*)$ /internal?migrated=true;
set $original_endpoint $1;
插件配置:
rules:
- regex: ^/api/(.*)$
replacement: /internal
query_append: migrated=true
set_vars:
- name: original_endpoint
capture_group: 1
pass_to_upstream: true
6. 多规则组合
Nginx:
rewrite ^/stage/(.*)$ /mid/$1;
rewrite ^/mid/(.*)$ /final/$1;
插件配置:
rules:
- regex: ^/stage/(.*)$
replacement: /mid/$1
mode: last
- regex: ^/mid/(.*)$
replacement: /final/$1
7. break / last 控制
Nginx break:
rewrite ^/stage/(.*)$ /mid/$1 break;
rules:
- regex: ^/stage/(.*)$
replacement: /mid/$1
mode: break
Nginx last:
rewrite ^/stage/(.*)$ /mid/$1 last;
rewrite ^/mid/(.*)$ /final/$1;
rules:
- regex: ^/stage/(.*)$
replacement: /mid/$1
mode: last
- regex: ^/mid/(.*)$
replacement: /final/$1
使用示例
rules:
- regex: ^/api/(.*)$
replacement: /internal
query_append: migrated=true
set_vars:
- name: original_endpoint
capture_group: 1
- name: http_x_original_endpoint
capture_group: 1
- name: arg_source
capture_group: 1
- name: cookie_track_id
capture_group: 1
pass_to_upstream: true
mode: break
- regex: ^/old/(.*)$
replacement: /new/$1
- regex: ^/x/(.*)/(.*)$
replacement: /y
query_template: a=$1&b=$2
set_vars:
- name: first
capture_group: 1
- name: second
capture_group: 2