Apache通過LimitInternalRecursion指令防止重寫死循環(huán)
LimitInternalRecursion 不能防止重寫死循環(huán),它只在死循環(huán)發(fā)生后強制中斷并報錯。 它是 Apache 的安全熔斷機制,不是預(yù)防手段。真正要防死循環(huán),得靠規(guī)則設(shè)計和日志觀測。
LimitInternalRecursion 是什么,為什么它不“防止”循環(huán)
這個指令設(shè)置的是內(nèi)部重定向(internal redirect)和子請求(subrequest)的嵌套深度上限,默認值是 10。當 mod_rewrite 觸發(fā)的重寫鏈超過該次數(shù),Apache 就會中止處理,并記錄類似 [alert] mod_rewrite: maximum number of internal redirects reached 的錯誤——這說明循環(huán)已經(jīng)發(fā)生了,只是被攔下了。
它不分析規(guī)則邏輯,也不提前攔截;就像汽車的安全氣囊,撞上了才彈出來。
- 它控制兩個維度:第一個數(shù)字是內(nèi)部重定向鏈長度(即重寫跳轉(zhuǎn)次數(shù)),第二個是子請求嵌套深度(如 mod_dir 查 DirectoryIndex 時的遞歸)
- 只寫一個數(shù)字(如 LimitInternalRecursion 20)會同時設(shè)為兩者
- 該指令作用域為 server config、virtual host 或 directory,不能在 .htaccess 中使用
- 調(diào)高它(比如設(shè)成 20)僅用于臨時定位問題,絕不能作為“解決死循環(huán)”的方案
死循環(huán)場景示例
# ? 危險配置:無條件重寫導(dǎo)致無限循環(huán) RewriteEngine On RewriteRule ^(.*)$ /index.php?page=$1 [L] # 問題:/index.php 匹配 ^(.*)$,再次重寫 → 死循環(huán)
LimitInternalRecursion 指令詳解
# 默認配置(Apache 2.4+)
LimitInternalRecursion 10
# 生產(chǎn)環(huán)境建議(根據(jù)應(yīng)用復(fù)雜度調(diào)整)
LimitInternalRecursion 5
# 調(diào)試時臨時增大(配合 RewriteLogLevel)
<IfDefine DEBUG>
LimitInternalRecursion 20
</IfDefine>| 參數(shù)值 | 行為 | 適用場景 |
|---|---|---|
| 0 | 禁用重寫(不推薦) | 僅靜態(tài)資源服務(wù)器 |
| 1-3 | 嚴格限制 | 簡單路由,無嵌套重寫 |
| 5-10 | 平衡配置(默認) | 現(xiàn)代 CMS/框架(WordPress/Laravel) |
| 20+ | 寬松限制 | 復(fù)雜多級代理/遺留系統(tǒng) |
與 mod_rewrite 協(xié)同的完整方案
1. 基礎(chǔ)防護配置
<VirtualHost *:80>
ServerName example.com
DocumentRoot /var/www/html
# 核心:限制內(nèi)部遞歸深度
LimitInternalRecursion 5
# 輔助:限制單請求子請求數(shù)(防止間接循環(huán))
LimitRequestFields 50
LimitRequestFieldSize 8190
<Directory /var/www/html>
RewriteEngine On
# 關(guān)鍵:使用 [END] 標志(Apache 2.4+)替代 [L]
# [L] 僅停止當前輪,[END] 完全終止重寫處理
RewriteRule ^api/(.*)$ /api/index.php?path=$1 [END]
# 傳統(tǒng) [L] 需配合條件避免循環(huán)
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(.*)$ /index.php [L]
</RewriteCond>
</Directory>
</VirtualHost>2. 復(fù)雜路由的安全模式
<Directory /var/www/app>
RewriteEngine On
# 防御層1:嚴格遞歸限制
LimitInternalRecursion 3
# 防御層2:標記已重寫請求(雙重保險)
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule ^ - [L]
# 防御層3:排除已處理 URI 模式
RewriteCond %{REQUEST_URI} !\.php$
RewriteCond %{REQUEST_URI} !^/(assets|uploads)/
RewriteRule ^(.*)$ /router.php?uri=$1 [QSA,L]
# 錯誤處理:遞歸超限返回 500
ErrorDocument 500 /error/loop-detected.html
</Directory>3. 與 Proxy 組合時的特殊處理
# 反向代理場景易觸發(fā)多級重寫
<VirtualHost *:443>
SSLEngine on
# 代理場景需更大遞歸深度(子請求+重寫)
LimitInternalRecursion 10
RewriteEngine On
# 關(guān)鍵:排除代理目標路徑,防止回環(huán)
RewriteCond %{REQUEST_URI} !^/proxy-backend/
RewriteRule ^/api/(.*)$ /proxy-backend/api/$1 [P,L]
ProxyPass /proxy-backend/ http://localhost:8080/
ProxyPassReverse /proxy-backend/ http://localhost:8080/
# 代理錯誤時停止遞歸
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteRule ^/ws/(.*)$ ws://localhost:8081/$1 [P,L]
</VirtualHost>關(guān)鍵關(guān)聯(lián)指令對比
| 指令 | 作用層級 | 防護目標 | 與 LimitInternalRecursion 關(guān)系 |
|---|---|---|---|
| LimitInternalRecursion | 服務(wù)器/虛擬主機/目錄 | 重寫/映射死循環(huán) | 核心防線 |
| LimitRequestFields | 服務(wù)器 | HTTP 頭溢出 | 輔助防護 |
| RewriteOptions MaxRedirects | 目錄 | 外部重定向次數(shù) | 僅限制外部 301/302,不防內(nèi)部重寫 |
| LimitRequestBody | 服務(wù)器/目錄 | 請求體大小 | 防止大請求導(dǎo)致的間接遞歸 |
死循環(huán)檢測與調(diào)試
日志分析配置
# 開發(fā)/調(diào)試環(huán)境啟用詳細重寫日志
<IfDefine DEBUG_REWRITE>
LogLevel rewrite:trace8
# 自定義日志格式包含遞歸深度
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{REDIRECT_STATUS}e\" %{rewrite_uri}n" rewrite_log
CustomLog logs/rewrite.log rewrite_log
</IfDefine>典型死循環(huán)特征
# 錯誤日志中的循環(huán)跡象
[rewrite:trace4] ... (1) init rewrite engine
[rewrite:trace4] ... (1) applying pattern '^/(.*)$' to uri 'index.php'
[rewrite:trace4] ... (2) init rewrite engine <-- 數(shù)字遞增表示遞歸
[rewrite:trace4] ... (2) applying pattern '^/(.*)$' to uri 'index.php'
...
[rewrite:trace1] ... (11) init rewrite engine <-- 超過 LimitInternalRecursion
[core:error] ... Request exceeded the limit of 10 internal redirects
due to probable configuration error. Use 'LimitInternalRecursion'
to increase the limit if necessary.現(xiàn)代框架的安全模板
# Laravel / Symfony / 類似 MVC 框架
<Directory /var/www/laravel/public>
RewriteEngine On
# 嚴格遞歸限制(框架路由已處理多級邏輯)
LimitInternalRecursion 2
# 發(fā)送所有請求到 index.php(單次重寫)
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [END] # [END] 完全終止,比 [L] 更安全
</Directory>
# WordPress 典型配置
<Directory /var/www/wordpress>
RewriteEngine On
LimitInternalRecursion 3
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</Directory>關(guān)鍵最佳實踐
- 優(yōu)先使用 [END] 標志(Apache 2.4+):完全終止重寫處理,比 [L] 更防循環(huán)
- 始終設(shè)置 RewriteCond %{ENV:REDIRECT_STATUS} ^$:排除已重寫請求
- 遞歸深度寧小勿大:生產(chǎn)環(huán)境建議 3-5,異常時增大而非默認無限
- 配合 RewriteMap 復(fù)雜邏輯:避免在 RewriteRule 中堆砌條件導(dǎo)致隱性循環(huán)
核心要點:LimitInternalRecursion 是最后防線,良好設(shè)計的重寫規(guī)則應(yīng)通過 [END] 標志和 REDIRECT_STATUS 條件自我防循環(huán),而非依賴遞歸限制。
到此這篇關(guān)于Apache通過LimitInternalRecursion指令防止重寫死循環(huán)的文章就介紹到這了,更多相關(guān)Apache LimitInternalRecursion防止重寫死循環(huán)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Apache中使非偽靜態(tài)url跳轉(zhuǎn)到偽靜態(tài)url的方法
這篇文章主要介紹了Apache中使非偽靜態(tài)url跳轉(zhuǎn)到偽靜態(tài)url的方法,主要是在使用.htaccess時的問題,需要的朋友可以參考下2015-07-07
讓Apache支持Rewrite靜態(tài)頁面重寫的方法
Apache下Rewrite靜態(tài)頁面重寫的方法,需要的朋友可以參考下。2010-07-07

