From 61484090f93ade045af2c20df023cdd50e737aaa Mon Sep 17 00:00:00 2001 From: ryan Date: Sat, 8 Aug 2026 22:37:40 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=BA=90=E7=AB=99?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E9=A1=B5=E3=80=8C=E4=BB=85=E9=92=88=E5=AF=B9?= =?UTF-8?q?=20GET=20=E8=AF=B7=E6=B1=82=E3=80=8D=E5=AF=BC=E8=87=B4=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E5=8F=91=E5=B8=83=E5=A4=B1=E8=B4=A5=E5=B9=B6=E5=9B=9E?= =?UTF-8?q?=E6=BB=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yaml | 2 +- docs/changelog/index.md | 1 + docs/reference/configuration.md | 2 +- pkg/render/openresty/origin_error_page.go | 16 +++++----------- pkg/render/openresty/origin_error_page_test.go | 11 +++++++---- 5 files changed, 15 insertions(+), 17 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index b9c3e2ae..59c1fcc1 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -110,7 +110,7 @@ services: - ./data/agent/:/data environment: OPENFLARE_SERVER_URL: "http://host.docker.internal:3000" - OPENFLARE_AGENT_TOKEN: "af2fb112f36a0055ec25dd164c908fea" + OPENFLARE_AGENT_TOKEN: "7c7c4c13df0f3a77866bcd8cde492610" LOG_LEVEL: "debug" extra_hosts: - "host.docker.internal:host-gateway" diff --git a/docs/changelog/index.md b/docs/changelog/index.md index dcebe0e8..39780c2f 100644 --- a/docs/changelog/index.md +++ b/docs/changelog/index.md @@ -28,6 +28,7 @@ sidebar: false ### 修复 +- 修复源站错误页「仅针对 GET 请求」导致配置发布失败并回滚:`proxy_intercept_errors` 不能写在 `limit_except` 内,现改为内部错误页按请求方法处理,非 GET 请求保留原始状态码且不注入自定义错误页,配置可通过 `openresty -t` 校验。 - 修复 PoW 挑战页潜在 XSS:错误提示与状态文案改用纯文本渲染,挑战通过后的 `redir` 跳转参数仅允许 http/https 协议,防止异常文本被当作 HTML 执行或跳转到危险协议。 - 修复邮件发送的邮件头注入风险:标题、发件人、收件人在写入邮件头前清除 CR/LF 换行符,防止注入额外邮件头(CWE-93)。 - 修复 UptimeKuma 同步调试日志泄露凭据:输出日志前对 password/token/secret 等敏感字段打码,避免凭据进入日志。 diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md index b8652188..7ae9318d 100644 --- a/docs/reference/configuration.md +++ b/docs/reference/configuration.md @@ -266,7 +266,7 @@ Server 的所有核心基础配置定义在 `config.yaml` 中,且均支持环 | 配置键 (Key) | 数据类型 | 作用说明 | 默认值 | | --- | --- | --- | --- | | `origin_error_page_enabled` | `bool` | 是否启用全局源站错误页。开启后,源站或网关返回的匹配状态码由自定义/默认 HTML 替换,**HTTP 状态码保持原值**;关闭后不生成相关指令,恢复透传。修改后需发布配置版本生效 | `true` | -| `origin_error_page_get_only` | `bool` | 是否仅对 **GET** 请求生效。开启后仅 GET 的匹配错误状态码返回自定义错误页;POST/PUT 等其它方法透传源站响应 | `false` | +| `origin_error_page_get_only` | `bool` | 是否仅对 **GET** 请求生效。开启后仅 GET 的匹配错误状态码返回自定义错误页;POST/PUT 等其它方法不返回自定义错误页(保留原始错误状态码) | `false` | | `origin_error_page_status_codes` | `json` | 触发错误页的状态码标签 JSON 数组。支持单码(如 `522`)与闭区间(如 `500-599`);单码与区间两端均须在 **400–599**,且 `lo ≤ hi`。启用时展开结果不能为空 | `["500-599"]` | | `origin_error_page_html` | `string` | 错误页自定义 HTML。空字符串表示使用内置 OpenFlare 默认模板(极简白底);支持占位符 `{{status}}`(与 HTTP 状态码一致)、`{{host}}`(请求 Host)。最大 **256 KiB**(按字节)。勿嵌入不可信第三方脚本 | 空 | diff --git a/pkg/render/openresty/origin_error_page.go b/pkg/render/openresty/origin_error_page.go index f4f007e2..9b4e7f16 100644 --- a/pkg/render/openresty/origin_error_page.go +++ b/pkg/render/openresty/origin_error_page.go @@ -130,17 +130,11 @@ func renderOriginErrorPageIntercept(cfg ConfigSnapshot) string { if _, err := ExpandStatusCodeTags(effectiveOriginErrorPageStatusTags(cfg)); err != nil { return "" } - // Always enable intercept for GET (and all methods when get_only is false). - // limit_except GET applies to non-GET methods: turn intercept off so origin - // error bodies (e.g. JSON 5xx) pass through unchanged. - var builder strings.Builder - builder.WriteString(" proxy_intercept_errors on;\n") - if cfg.OriginErrorPageGetOnly { - builder.WriteString(" limit_except GET {\n") - builder.WriteString(" proxy_intercept_errors off;\n") - builder.WriteString(" }\n") - } - return builder.String() + // Intercept at the proxy level for all methods. nginx does not allow + // proxy_intercept_errors inside limit_except (only allow/deny are valid + // there), so GET-only is enforced in the internal error location's Lua: + // non-GET requests exit with the original status and no custom HTML. + return " proxy_intercept_errors on;\n" } // renderOriginErrorPageServerBits emits server-level error_page + internal location. diff --git a/pkg/render/openresty/origin_error_page_test.go b/pkg/render/openresty/origin_error_page_test.go index 924300e8..9466061d 100644 --- a/pkg/render/openresty/origin_error_page_test.go +++ b/pkg/render/openresty/origin_error_page_test.go @@ -88,11 +88,14 @@ func TestRenderOriginErrorPageGetOnly(t *testing.T) { if !strings.Contains(out, "proxy_intercept_errors on") { t.Fatal("missing intercept on") } - if !strings.Contains(out, "limit_except GET") { - t.Fatal("get_only must emit limit_except GET") + // nginx rejects proxy_intercept_errors inside limit_except (only allow/deny + // are valid there), which made the generated config fail `openresty -t` and + // caused apply rollback. GET-only must rely on the internal location's Lua. + if strings.Contains(out, "limit_except") { + t.Fatal("get_only must not emit limit_except (proxy_intercept_errors is not allowed there)") } - if !strings.Contains(out, "proxy_intercept_errors off") { - t.Fatal("get_only must turn intercept off for non-GET") + if strings.Contains(out, "proxy_intercept_errors off") { + t.Fatal("get_only must not emit proxy_intercept_errors off") } if !strings.Contains(out, `get_only = true`) { t.Fatal("internal location must set get_only = true")