install页去掉IP白名单门禁并修null告警, 新增0.0.0.0应急逃生通道

- install.php: sqlMdDbConfig 全新站 java/web 槽为 null, $val 闭包加 is_array 兜底,
  消除每个输入框的 array offset on null 告警; 门禁只留令牌层(全新站无白名单可言);
  安装成功页改为回显本次写入的完整配置供截图手抄, 背景自删
- admin_2fa_setup.php: 引导页白名单框上方显示当前访问IP; 应急模式免密进 boot 模式
  并挂红徽标; secInstallPending 让位改为 !secIsEmergency(), 避免与全局应急路由
  形成 install/引导页互跳死循环
- security.php: 新增 secIsEmergency() 判定白名单含 0.0.0.0; secIpAllowed 放行该条目;
  新增 secEmergencyGate() 在限流层前把非引导页/非本机请求 302 锁回引导页(用302防浏览器缓存)
- config.php: 补 0.0.0.0 应急用法与用完必删的说明注释
This commit is contained in:
ypsdf1
2026-10-09 19:56:34 +08:00
parent fc8c82b188
commit 0b63a99719
4 changed files with 122 additions and 11 deletions
+27 -2
View File
@@ -21,7 +21,10 @@ $boot = secBootSessionActive();
// 无 install.lock)时,本页先让位给数据库安装页;装完它自删,再回来配 2FA/白名单/令牌。 // 无 install.lock)时,本页先让位给数据库安装页;装完它自删,再回来配 2FA/白名单/令牌。
// 引导模式下 secGatePage 已先行 302,这里兜住「已引导 / 本机直连」两种入口; // 引导模式下 secGatePage 已先行 302,这里兜住「已引导 / 本机直连」两种入口;
// 已引导站点带 ?token= 过 install.php 的第三层门禁(令牌为空时 secTokenUrl 原样返回)。 // 已引导站点带 ?token= 过 install.php 的第三层门禁(令牌为空时 secTokenUrl 原样返回)。
if (secInstallPending()) { // ★ 0.0.0.0 应急时让位反向失效:install.php 属「其它任何页面」,会被 secEmergencyGate()
// 302 回本页 —— 若本页再 302 去 install.php 就成了两页互跳死循环。
// 应急的语义就是「直达引导配置页把白名单改回来」,故应急优先于装库让位。
if (secInstallPending() && !secIsEmergency()) {
header('Location: ' . secTokenUrl('install.php')); header('Location: ' . secTokenUrl('install.php'));
exit; exit;
} }
@@ -34,8 +37,17 @@ $needInit = !secAdminPassConfigured();
// 说明:本页只依赖 security.php(不加载 core.php), // 说明:本页只依赖 security.php(不加载 core.php),
// isAdminLoggedIn() 是 core 的函数,这里用等价的内联判定(admin_auth + 安全纪元)。 // isAdminLoggedIn() 是 core 的函数,这里用等价的内联判定(admin_auth + 安全纪元)。
$loggedIn = !empty($_SESSION['admin_auth']) && secSessionEpochOk(); $loggedIn = !empty($_SESSION['admin_auth']) && secSessionEpochOk();
$isEmergency = false;
if ($boot) { if ($boot) {
$mode = 'boot'; $mode = 'boot';
} elseif (secIsEmergency()) {
// ★ 0.0.0.0 应急(2026-10-09):boot / 访问令牌全丢时的最后通道 —— 按 boot
// 引导模式免密放行(本分支必须在 session 之前:应急时若 session 开着 2FA,
// 会被送去 admin_2fa.php,而那页又被全局应急路由 302 回本页 → 死循环)。
// 引导动作:删掉白名单里的 0.0.0.0 → 保存 → 重新生成令牌,即恢复常态。
$mode = 'boot';
$isEmergency = true;
secLog('emergency_setup_enter', 'ip=' . secClientIp());
} elseif ($loggedIn) { } elseif ($loggedIn) {
// 已登录:若 2FA 已启用但本会话未验证 → 先去验证页 // 已登录:若 2FA 已启用但本会话未验证 → 先去验证页
if (defined('SEC_2FA_ENABLED') && SEC_2FA_ENABLED && empty($_SESSION['admin_2fa_ok'])) { if (defined('SEC_2FA_ENABLED') && SEC_2FA_ENABLED && empty($_SESSION['admin_2fa_ok'])) {
@@ -346,7 +358,8 @@ $wlAllowsMe = secIpAllowed() || secIpInWhitelist($myIp, $whitelist);
<div class="top"> <div class="top">
<h1>🔐 后台安全配置</h1> <h1>🔐 后台安全配置</h1>
<div> <div>
<?php if ($mode === 'boot'): ?><span class="badge b-boot">引导模式(boot 令牌)</span><?php endif; ?> <?php if ($mode === 'boot' && !$isEmergency): ?><span class="badge b-boot">引导模式(boot 令牌)</span><?php endif; ?>
<?php if ($isEmergency): ?><span class="badge b-boot" style="background:#6e1c24;border-color:#ff4d5e;color:#fff">🚨 应急模式(0.0.0.0)</span><?php endif; ?>
<?php if ($mode === 'init'): ?><span class="badge b-boot">首次初始化</span><?php endif; ?> <?php if ($mode === 'init'): ?><span class="badge b-boot">首次初始化</span><?php endif; ?>
<?php <?php
// "← 返回"指向 admin_2fa.php / admin.php?token= —— 两者对非白名单 IP 都是 404。 // "← 返回"指向 admin_2fa.php / admin.php?token= —— 两者对非白名单 IP 都是 404。
@@ -360,6 +373,16 @@ $wlAllowsMe = secIpAllowed() || secIpInWhitelist($myIp, $whitelist);
<?php if ($err !== ''): ?><span class="msg err">❌ <?php echo $err; ?></span><?php endif; ?> <?php if ($err !== ''): ?><span class="msg err">❌ <?php echo $err; ?></span><?php endif; ?>
<?php if ($ok !== ''): ?><span class="msg ok">✅ <?php echo $ok; ?></span><?php endif; ?> <?php if ($ok !== ''): ?><span class="msg ok">✅ <?php echo $ok; ?></span><?php endif; ?>
<?php if ($isEmergency): ?>
<div class="msg err" style="display:block;margin-bottom:14px;line-height:1.7">
🚨 <b>应急模式生效中:白名单里存在条目 <code>0.0.0.0</code>,全站其它页面已全部锁定并跳转到本页。</b><br>
恢复步骤(做完再离开):
① 在下方「IP 白名单」里<strong>删掉 <code>0.0.0.0</code></strong> 并点「保存白名单」(确保你的 IP 在列表里);
② 点「重新生成令牌」<strong>重置全部令牌</strong>(原令牌视为已泄露);
③ 刷新本页确认 🚨 徽标消失。
</div>
<?php endif; ?>
<?php if ($mode === 'boot' && !$wlAllowsMe): ?> <?php if ($mode === 'boot' && !$wlAllowsMe): ?>
<!-- boot 恢复模式的唯一正事:把当前 IP 加进白名单。其它管理页对你一律 404,这是设计如此。 --> <!-- boot 恢复模式的唯一正事:把当前 IP 加进白名单。其它管理页对你一律 404,这是设计如此。 -->
<span class="msg" style="background:rgba(210,153,34,0.10);border:1px solid rgba(210,153,34,0.40);color:#d29922"> <span class="msg" style="background:rgba(210,153,34,0.10);border:1px solid rgba(210,153,34,0.40);color:#d29922">
@@ -447,6 +470,8 @@ $wlAllowsMe = secIpAllowed() || secIpInWhitelist($myIp, $whitelist);
<?php if (count($whitelist) > 0): ?> <?php if (count($whitelist) > 0): ?>
<div style="margin-bottom:10px"><?php foreach ($whitelist as $w): ?><span class="wl-item"><?php echo htmlspecialchars($w, ENT_QUOTES, 'UTF-8'); ?></span><?php endforeach; ?></div> <div style="margin-bottom:10px"><?php foreach ($whitelist as $w): ?><span class="wl-item"><?php echo htmlspecialchars($w, ENT_QUOTES, 'UTF-8'); ?></span><?php endforeach; ?></div>
<?php endif; ?> <?php endif; ?>
<div class="hint" style="margin-bottom:6px">当前访问 IP:<code id="myIpTxt"><?php echo htmlspecialchars($myIp, ENT_QUOTES, 'UTF-8'); ?></code>
—— 白名单里<strong>必须包含它</strong>,否则保存后你会把自己挡在门外(含 0.0.0.0 应急条目时本页是唯一入口,改完记得删掉它)。</div>
<textarea name="whitelist" id="wlBox" placeholder="每行一个 IP 或 CIDR 网段,例如:&#10;203.0.113.8&#10;192.168.1.0/24"><?php echo htmlspecialchars(implode("\n", $whitelist), ENT_QUOTES, 'UTF-8'); ?></textarea> <textarea name="whitelist" id="wlBox" placeholder="每行一个 IP 或 CIDR 网段,例如:&#10;203.0.113.8&#10;192.168.1.0/24"><?php echo htmlspecialchars(implode("\n", $whitelist), ENT_QUOTES, 'UTF-8'); ?></textarea>
<div class="row" style="margin-top:10px"> <div class="row" style="margin-top:10px">
<button type="button" class="btn btn-gray" onclick="addMyIp()">+ 把我的 IP 加入</button> <button type="button" class="btn btn-gray" onclick="addMyIp()">+ 把我的 IP 加入</button>
+5
View File
@@ -116,5 +116,10 @@ define('CAPTCHA_PROVIDER', 'CF'); // ← 只改这个值:'CF' 用 Cloudflare
// 被锁在外面时的恢复方法:宝塔/SSH 查看本文件补全后的 SEC_BOOT_TOKEN,访问 // 被锁在外面时的恢复方法:宝塔/SSH 查看本文件补全后的 SEC_BOOT_TOKEN,访问
// https://你的域名/plugin/admin_2fa_setup.php?boot=<令牌> // https://你的域名/plugin/admin_2fa_setup.php?boot=<令牌>
// 进入配置页把自己当前 IP 加入白名单(boot 令牌本身也是配置页入口)。 // 进入配置页把自己当前 IP 加入白名单(boot 令牌本身也是配置页入口)。
// ★ 令牌全丢的最后手段(2026-10-09):宝塔/SSH 手工给下面 SEC-UPDATE 区的
// ADMIN_IP_WHITELIST 数组加一条字面量 '0.0.0.0' —— 应急模式立即生效:
// 除服务器本机外全站所有页面/API 一律 302 锁回 admin_2fa_setup.php(免密进入),
// 按该页红色横幅指引删掉 0.0.0.0 + 「重新生成令牌」即恢复常态。
// ⚠️ 0.0.0.0 只是应急门票(等价全网可进引导页),用完必须立刻删除。
// >>>SEC-UPDATE-BEGIN 本区段由 admin_2fa_setup.php 自动维护,请勿手工改动标记行 // >>>SEC-UPDATE-BEGIN 本区段由 admin_2fa_setup.php 自动维护,请勿手工改动标记行
// >>>SEC-UPDATE-END // >>>SEC-UPDATE-END
+44 -9
View File
@@ -23,8 +23,9 @@ require_once __DIR__ . '/security.php';
// ① 已装过 → 与文件不存在完全一致的表现(本页也可能还没来得及自删) // ① 已装过 → 与文件不存在完全一致的表现(本页也可能还没来得及自删)
if (is_file(__DIR__ . '/install.lock')) secNginx404(); if (is_file(__DIR__ . '/install.lock')) secNginx404();
// ② IP 白名单 / boot 引导令牌 / 未引导放行 // ② 不做 IP 白名单验证(2026-10-09 需求):全新站根本没有白名单可言,拿白名单
secGatePage(true); // 挡安装页只会把部署者锁在门外;已引导站点由下面 ③ 的令牌层把关(?token= / ?boot=)。
// 原 secGatePage(true) 在「已引导但没装库」时会把非白名单 IP 挡成 404。
// ③ 动态访问令牌(config 里有 SEC_ACCESS_TOKEN 时才生效;全新部署为空 → 放行) // ③ 动态访问令牌(config 里有 SEC_ACCESS_TOKEN 时才生效;全新部署为空 → 放行)
secTokenGate(true); secTokenGate(true);
secEnsureSession(); secEnsureSession();
@@ -35,6 +36,7 @@ define('INSTALL_MD', defined('SQL_MD_PATH') ? SQL_MD_PATH : __DIR__ . '/sql.md
$cur = sqlMdDbConfig(); // static 缓存,此刻读的是「写入前」的旧配置,仅用于回显 $cur = sqlMdDbConfig(); // static 缓存,此刻读的是「写入前」的旧配置,仅用于回显
$err = ''; $err = '';
$ok = ''; $ok = '';
$saved = null; // 本次 POST 成功写入的配置 → 完成页回显供截图/手抄
// CSRF:会话级随机数(不依赖 SEC_ACCESS_TOKEN,全新部署时它还是空的) // CSRF:会话级随机数(不依赖 SEC_ACCESS_TOKEN,全新部署时它还是空的)
if (empty($_SESSION['inst_csrf'])) { if (empty($_SESSION['inst_csrf'])) {
@@ -383,14 +385,19 @@ $val = function ($k, $d = '') use ($cur, $err) {
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $err !== '' && isset($_POST[$k])) { if ($_SERVER['REQUEST_METHOD'] === 'POST' && $err !== '' && isset($_POST[$k])) {
return htmlspecialchars((string)$_POST[$k], ENT_QUOTES, 'UTF-8'); return htmlspecialchars((string)$_POST[$k], ENT_QUOTES, 'UTF-8');
} }
if ($k === 'dir') return htmlspecialchars($cur['dir'], ENT_QUOTES, 'UTF-8'); $cur = is_array($cur) ? $cur : array();
if ($k === 'dir') return htmlspecialchars(isset($cur['dir']) ? (string)$cur['dir'] : '', ENT_QUOTES, 'UTF-8');
if ($k === 'mode') return ''; if ($k === 'mode') return '';
if (preg_match('/^(java|web)_(host|port|name|user|pass)$/', $k, $m)) { if (preg_match('/^(java|web)_(host|port|name|user|pass)$/', $k, $m)) {
$e = $cur[$m[1]]; // ★ 全新站 sql.md 配置区账密全空 → sqlMdDbConfig 的 java/web 槽是 null
// ("字段不全 → null → 该侧兜底 db"),直接 $e[...] 在 PHP 8 会每个输入框
// 报一条 "Trying to access array offset on null"(实录:test12 第 391 行)。
$e = (isset($cur[$m[1]]) && is_array($cur[$m[1]])) ? $cur[$m[1]] : array();
$map = array('host' => 'host', 'port' => 'port', 'name' => 'name', 'user' => 'user', 'pass' => 'pass'); $map = array('host' => 'host', 'port' => 'port', 'name' => 'name', 'user' => 'user', 'pass' => 'pass');
return htmlspecialchars((string)$e[$map[$m[2]]], ENT_QUOTES, 'UTF-8'); $rv = isset($e[$map[$m[2]]]) ? (string)$e[$map[$m[2]]] : '';
return htmlspecialchars($rv, ENT_QUOTES, 'UTF-8');
} }
return htmlspecialchars($d, ENT_QUOTES, 'UTF-8'); return htmlspecialchars((string)$d, ENT_QUOTES, 'UTF-8');
}; };
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
@@ -447,12 +454,40 @@ ul{margin:6px 0;padding-left:20px}
<ul> <ul>
<li>配置已写入 <code>sql.md</code> 并回读校验通过。</li> <li>配置已写入 <code>sql.md</code> 并回读校验通过。</li>
<li>已生成 <code>install.lock</code>,本页再次访问将返回 404。</li> <li>已生成 <code>install.lock</code>,本页再次访问将返回 404。</li>
<li><code>install.php</code> 已自我删除。</li> <li><code>install.php</code> 已自我删除(后台静默完成,页面照常停留供你截图留档)。</li>
</ul> </ul>
<?php if (is_array($saved)): ?>
<div style="margin-top:10px;border-top:1px solid #26543a;padding-top:10px">
<div style="font-weight:600;margin:6px 0">📋 本次写入的配置 —— 请截图或手抄留档:</div>
<table style="width:100%;border-collapse:collapse;font-size:13px">
<tr>
<td style="padding:4px 8px;color:#9ff0bb;white-space:nowrap">运行模式</td>
<td><code><?php echo htmlspecialchars($saved['mode'] === 'mysql' ? 'mysql' : 'db(SQLite 文件)', ENT_QUOTES, 'UTF-8'); ?></code></td>
</tr>
<?php if ($saved['mode'] !== 'mysql'): ?>
<tr>
<td style="padding:4px 8px;color:#9ff0bb;white-space:nowrap">存储位置</td>
<td><code><?php echo htmlspecialchars($saved['dir'] === '' ? './db/(默认)' : $saved['dir'], ENT_QUOTES, 'UTF-8'); ?></code></td>
</tr>
<?php else: ?>
<?php foreach (array('java' => 'Java 侧(sync.php · Java.db)', 'web' => 'PHP 侧(web.db)') as $slot => $label): ?>
<?php $e = $saved[$slot]; ?>
<tr>
<td style="padding:4px 8px;color:#9ff0bb;vertical-align:top;white-space:nowrap"><?php echo $label; ?></td>
<td><?php if ($e['host'] === '' && $e['name'] === ''): ?><code>(空 → 自动回退 db 文件)</code><?php else: ?><code><?php echo htmlspecialchars($e['host'] . ':' . $e['port'] . ' · 库名 ' . $e['name'] . ' · 账号 ' . $e['user'] . ' · 密码 ' . $e['pass'], ENT_QUOTES, 'UTF-8'); ?></code><?php endif; ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</table>
<div style="color:#9ff0bb;font-size:12.5px;margin-top:6px">本页已随安装完成而删除 —— 这是最后一处能整份查看该配置的页面;完整配置仍保存在 <code>sql.md</code>。</div>
</div>
<?php endif; ?>
下一步: 下一步:
<ul> <ul>
<li>db 模式 → 直接访问 <a href="admin_login.php" style="color:#7fb0ff">后台登录页</a>。</li> <li><strong>先去 <a href="admin_2fa_setup.php" style="color:#7fb0ff">安全配置引导页</a></strong>:把你当前的 IP 加入白名单、保存访问令牌、设置 2FA。</li>
<li>mysql 模式 → 后台首访会自动建表(已在本页实连并验证过建表权限)。</li> <li>mysql 模式 → 配完安全项首次进后台会自动建表(已在本页实连并验证过建表权限);db 模式 → 配完即可登录。</li>
<li>记得让 <strong>Java 端</strong>(api/sync.php 所在的独立站点)也用同一份配置:改 sync.php 时两处都要传。</li> <li>记得让 <strong>Java 端</strong>(api/sync.php 所在的独立站点)也用同一份配置:改 sync.php 时两处都要传。</li>
</ul> </ul>
</div> </div>
+46
View File
@@ -273,6 +273,25 @@ function secCidrMatch($ip, $cidr) {
* 规则:127.0.0.1/::1 永远放行(服务器本机逃生舱); * 规则:127.0.0.1/::1 永远放行(服务器本机逃生舱);
* 白名单为空 → 除本机外任何人一律拒绝(含 IP 缺失的异常请求)。 * 白名单为空 → 除本机外任何人一律拒绝(含 IP 缺失的异常请求)。
*/ */
/**
* 0.0.0.0 应急模式(2026-10-09):白名单里出现字面条目 `0.0.0.0`。
*
* 场景:boot 引导令牌与后台访问令牌全丢、又没有别的入口 —— 只要能上服务器
* (宝塔/SSH)把 config.php 的 ADMIN_IP_WHITELIST 加上一条 0.0.0.0,即可临时恢复:
* - 全站其它页面/API 一律被 security.php 尾部的全局应急路由 302 回
* admin_2fa_setup.php(应急条目只买得到这一张门票,用来删掉它自己 + 重置令牌);
* - admin_2fa_setup.php 以 boot 引导模式免密放行(见该页 $isEmergency 分支);
* - 服务器本机 127.0.0.1 / ::1 不受应急路由限制(宝塔/SSH 永远有救)。
* 用完必须立刻删掉 0.0.0.0 —— 它等价于"全网都能进引导页"。
*/
function secIsEmergency() {
if (!defined('ADMIN_IP_WHITELIST') || !is_array(ADMIN_IP_WHITELIST)) return false;
foreach (ADMIN_IP_WHITELIST as $e) {
if (trim((string)$e) === '0.0.0.0') return true;
}
return false;
}
function secIpAllowed() { function secIpAllowed() {
$ip = secClientIp(); $ip = secClientIp();
if ($ip === '') { if ($ip === '') {
@@ -284,6 +303,9 @@ function secIpAllowed() {
foreach (ADMIN_IP_WHITELIST as $entry) { foreach (ADMIN_IP_WHITELIST as $entry) {
$entry = trim((string)$entry); $entry = trim((string)$entry);
if ($entry === '') continue; if ($entry === '') continue;
// ★ 0.0.0.0 = 应急全放行条目:IP 层直接开门,但非引导页根本到不了门禁 ——
// security.php 尾部的全局应急路由会在 require 阶段就把它们 302 回引导页。
if ($entry === '0.0.0.0') return true;
if ($entry === $ip) return true; if ($entry === $ip) return true;
if (strpos($entry, '/') !== false && secCidrMatch($ip, $entry)) return true; if (strpos($entry, '/') !== false && secCidrMatch($ip, $entry)) return true;
} }
@@ -617,6 +639,9 @@ function secGatePage($allowBoot = false) {
// → 先放行,让部署者完成首次配置;后台主入口改跳配置页,这就是"引导"的落点。 // → 先放行,让部署者完成首次配置;后台主入口改跳配置页,这就是"引导"的落点。
if (!secIsBootstrapped()) { if (!secIsBootstrapped()) {
secLog('ip_gate_open_bootstrap', 'path=' . (isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '-')); secLog('ip_gate_open_bootstrap', 'path=' . (isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '-'));
// ★ 应急模式下直接放行:全局钩子只放 admin_2fa_setup.php 走到这里,
// 不能再把它转送去 install(那是常规首跑的顺序,应急时以自救为先)。
if (secIsEmergency()) return;
$script = basename(isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : ''); $script = basename(isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : '');
// ★ 首跑顺序(2026-10-09):装库先于安全配置 —— install.php 还没跑完 // ★ 首跑顺序(2026-10-09):装库先于安全配置 —— install.php 还没跑完
// (文件在场、无 install.lock)时,任何引导入口一律先 302 到自毁式安装页; // (文件在场、无 install.lock)时,任何引导入口一律先 302 到自毁式安装页;
@@ -1457,6 +1482,27 @@ function secRateTrusted() {
return false; return false;
} }
/**
* 全局应急路由(2026-10-09):include security.php 时自动执行一次(在限流层之前)。
*
* 白名单含 0.0.0.0 时,除 admin_2fa_setup.php 与服务器本机外,任何加载本文件的
* 入口(admin 系 + core 系全部页面/API)一律 302 送回应急引导页 —— 0.0.0.0 只放行
* 到那一页,进去删掉应急条目 + 重置令牌即恢复常态。
* 用 302 不用 301:301 会被浏览器永久缓存,改回白名单后客户端仍会继续乱跳。
* 无 REMOTE_ADDR(CLI/内部调用)不参与。
*/
function secEmergencyGate() {
if (empty($_SERVER['REMOTE_ADDR'])) return;
if (!secIsEmergency()) return;
$script = basename(isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : '');
if ($script === 'admin_2fa_setup.php') return; // 唯一放行页(引导用户自救)
if (secIsLocalIp(secClientIp())) return; // 本机恒通:宝塔/SSH 永远有救
secLog('emergency_route', 'path=' . (isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '-'));
header('Location: admin_2fa_setup.php', true, 302);
exit;
}
secEmergencyGate();
/** 第四层入口:include security.php 时自动执行一次。 */ /** 第四层入口:include security.php 时自动执行一次。 */
function secRateLimitGate() { function secRateLimitGate() {
if (PHP_SAPI === 'cli') return; // 命令行脚本不参与限流 if (PHP_SAPI === 'cli') return; // 命令行脚本不参与限流