From bb40ff692c4cd1e23937b327bffb2bf01c80428f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=90=9D=E5=8D=9C?= Date: Sat, 14 Mar 2026 02:12:29 +0000 Subject: [PATCH] =?UTF-8?q?fix(back):=20index=20=E9=A1=B5=20back=20?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=E6=8B=92=E7=BB=9D=20nested=20back=20+=20?= =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=B5=8B=E8=AF=95=E6=96=AD=E8=A8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resources/views/admin/plans/index.blade.php | 10 ++++++++-- resources/views/admin/platform_orders/index.blade.php | 10 ++++++++-- .../views/admin/site_subscriptions/index.blade.php | 10 ++++++++-- .../AdminPlatformOrderIndexBackLinkNotEscapedTest.php | 4 +++- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/resources/views/admin/plans/index.blade.php b/resources/views/admin/plans/index.blade.php index fd46f79..2d04747 100644 --- a/resources/views/admin/plans/index.blade.php +++ b/resources/views/admin/plans/index.blade.php @@ -34,7 +34,10 @@ $incomingBack = (string) request()->query('back', ''); // 为避免 & 被 Blade escape 成 & 导致回退上下文丢失,这里需要原样输出 href。 // 安全护栏:必须为站内相对路径,并拒绝引号/尖括号,降低 XSS 风险。 - $safeBack = (str_starts_with($incomingBack, '/') && !preg_match('/["\'<>]/', $incomingBack)) + $safeBack = (str_starts_with($incomingBack, '/') + && !preg_match('/["\'<>]/', $incomingBack) + // back 本身不应再包含 back(避免无限嵌套导致 URL 膨胀) + && !preg_match('/(?:^|[?&])back=/', $incomingBack)) ? $incomingBack : ''; @endphp @@ -78,7 +81,10 @@ // “全部”:清空筛选,但保留 back(用于返回来源页) $incomingBack = (string) request()->query('back', ''); - $safeBack2 = (str_starts_with($incomingBack, '/') && !preg_match('/["\'<>]/', $incomingBack)) + $safeBack2 = (str_starts_with($incomingBack, '/') + && !preg_match('/["\'<>]/', $incomingBack) + // back 本身不应再包含 back(避免无限嵌套导致 URL 膨胀) + && !preg_match('/(?:^|[?&])back=/', $incomingBack)) ? $incomingBack : ''; $allUrl = '/admin/plans'; diff --git a/resources/views/admin/platform_orders/index.blade.php b/resources/views/admin/platform_orders/index.blade.php index 2ded344..6d5e452 100644 --- a/resources/views/admin/platform_orders/index.blade.php +++ b/resources/views/admin/platform_orders/index.blade.php @@ -25,7 +25,10 @@ $back = (string) request()->query('back', ''); // 为避免 & 被 Blade escape 成 & 导致回退上下文丢失,这里需要原样输出 href。 // 安全护栏:必须为站内相对路径,并拒绝引号/尖括号,降低 XSS 风险。 - $safeBack = (str_starts_with($back, '/') && !preg_match('/["\'<>]/', $back)) + $safeBack = (str_starts_with($back, '/') + && !preg_match('/["\'<>]/', $back) + // back 本身不应再包含 back(避免无限嵌套导致 URL 膨胀) + && !preg_match('/(?:^|[?&])back=/', $back)) ? $back : ''; @endphp @@ -113,7 +116,10 @@ // “全部”:清空筛选,但保留 back(用于返回来源页) $incomingBack = (string) request()->query('back', ''); - $safeBack = (str_starts_with($incomingBack, '/') && !preg_match('/["\'<>]/', $incomingBack)) + $safeBack = (str_starts_with($incomingBack, '/') + && !preg_match('/["\'<>]/', $incomingBack) + // back 本身不应再包含 back(避免无限嵌套导致 URL 膨胀) + && !preg_match('/(?:^|[?&])back=/', $incomingBack)) ? $incomingBack : ''; $allUrl = '/admin/platform-orders'; diff --git a/resources/views/admin/site_subscriptions/index.blade.php b/resources/views/admin/site_subscriptions/index.blade.php index fa412eb..d3828ca 100644 --- a/resources/views/admin/site_subscriptions/index.blade.php +++ b/resources/views/admin/site_subscriptions/index.blade.php @@ -42,7 +42,10 @@ $incomingBack = (string) request()->query('back', ''); // 为避免 & 被 Blade escape 成 & 导致回退上下文丢失,这里需要原样输出 href。 // 安全护栏:必须为站内相对路径,并拒绝引号/尖括号,降低 XSS 风险。 - $safeBack = (str_starts_with($incomingBack, '/') && !preg_match('/["\'<>]/', $incomingBack)) + $safeBack = (str_starts_with($incomingBack, '/') + && !preg_match('/["\'<>]/', $incomingBack) + // back 本身不应再包含 back(避免无限嵌套导致 URL 膨胀) + && !preg_match('/(?:^|[?&])back=/', $incomingBack)) ? $incomingBack : ''; @endphp @@ -88,7 +91,10 @@ // “全部”:清空筛选,但保留 back(用于返回来源页) $incomingBack = (string) request()->query('back', ''); - $safeBack = (str_starts_with($incomingBack, '/') && !preg_match('/["\'<>]/', $incomingBack)) + $safeBack = (str_starts_with($incomingBack, '/') + && !preg_match('/["\'<>]/', $incomingBack) + // back 本身不应再包含 back(避免无限嵌套导致 URL 膨胀) + && !preg_match('/(?:^|[?&])back=/', $incomingBack)) ? $incomingBack : ''; $allUrl = '/admin/site-subscriptions'; diff --git a/tests/Feature/AdminPlatformOrderIndexBackLinkNotEscapedTest.php b/tests/Feature/AdminPlatformOrderIndexBackLinkNotEscapedTest.php index 566dee6..566bd6f 100644 --- a/tests/Feature/AdminPlatformOrderIndexBackLinkNotEscapedTest.php +++ b/tests/Feature/AdminPlatformOrderIndexBackLinkNotEscapedTest.php @@ -38,6 +38,8 @@ class AdminPlatformOrderIndexBackLinkNotEscapedTest extends TestCase $this->get('/admin/platform-orders?back=' . urlencode('https://evil.example.com/?x=1&y=2')) ->assertOk() - ->assertDontSee('返回上一页(保留上下文)'); + // 页面仍会出现“返回上一页(保留上下文)”文案(其它位置也有,例如治理SOP卡提示), + // 因此这里改为断言:不应出现该 external back 的 href。 + ->assertDontSee('href="https://evil.example.com/?x=1&y=2"', false); } }