Linux

关注公众号 jb51net

关闭
首页 > 网站技巧 > 服务器 > Linux > Apache LimitInternalRecursion防止重写死循环

Apache通过LimitInternalRecursion指令防止重写死循环

作者:冷炫風刃

LimitInternalRecursion 是 Apache 限制内部重定向和子请求嵌套深度的熔断指令,本文主要介绍了Apache通过LimitInternalRecursion指令防止重写死循环,感兴趣的可以了解一下

LimitInternalRecursion 不能防止重写死循环,它只在死循环发生后强制中断并报错。 它是 Apache 的安全熔断机制,不是预防手段。真正要防死循环,得靠规则设计和日志观测。

LimitInternalRecursion 是什么,为什么它不“防止”循环

这个指令设置的是内部重定向(internal redirect)和子请求(subrequest)的嵌套深度上限,默认值是 10。当 mod_rewrite 触发的重写链超过该次数,Apache 就会中止处理,并记录类似 [alert] mod_rewrite: maximum number of internal redirects reached 的错误——这说明循环已经发生了,只是被拦下了。

它不分析规则逻辑,也不提前拦截;就像汽车的安全气囊,撞上了才弹出来。

死循环场景示例

# ❌ 危险配置:无条件重写导致无限循环
RewriteEngine On
RewriteRule ^(.*)$ /index.php?page=$1 [L]
# 问题:/index.php 匹配 ^(.*)$,再次重写 → 死循环

LimitInternalRecursion 指令详解

# 默认配置(Apache 2.4+)
LimitInternalRecursion 10
# 生产环境建议(根据应用复杂度调整)
LimitInternalRecursion 5
# 调试时临时增大(配合 RewriteLogLevel)
<IfDefine DEBUG>
    LimitInternalRecursion 20
</IfDefine>
参数值行为适用场景
0禁用重写(不推荐)仅静态资源服务器
1-3严格限制简单路由,无嵌套重写
5-10平衡配置(默认)现代 CMS/框架(WordPress/Laravel)
20+宽松限制复杂多级代理/遗留系统

与 mod_rewrite 协同的完整方案

1. 基础防护配置

<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /var/www/html
    # 核心:限制内部递归深度
    LimitInternalRecursion 5
    # 辅助:限制单请求子请求数(防止间接循环)
    LimitRequestFields 50
    LimitRequestFieldSize 8190
    <Directory /var/www/html>
        RewriteEngine On
        # 关键:使用 [END] 标志(Apache 2.4+)替代 [L]
        # [L] 仅停止当前轮,[END] 完全终止重写处理
        RewriteRule ^api/(.*)$ /api/index.php?path=$1 [END]
        # 传统 [L] 需配合条件避免循环
        RewriteCond %{ENV:REDIRECT_STATUS} ^$
        RewriteRule ^(.*)$ /index.php [L]
    </RewriteCond>
    </Directory>
</VirtualHost>

2. 复杂路由的安全模式

<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 组合时的特殊处理

# 反向代理场景易触发多级重写
<VirtualHost *:443>
    SSLEngine on
    # 代理场景需更大递归深度(子请求+重写)
    LimitInternalRecursion 10
    RewriteEngine On
    # 关键:排除代理目标路径,防止回环
    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>

关键关联指令对比

指令作用层级防护目标与 LimitInternalRecursion 关系
LimitInternalRecursion服务器/虚拟主机/目录重写/映射死循环核心防线
LimitRequestFields服务器HTTP 头溢出辅助防护
RewriteOptions MaxRedirects目录外部重定向次数仅限制外部 301/302,不防内部重写
LimitRequestBody服务器/目录请求体大小防止大请求导致的间接递归

死循环检测与调试

日志分析配置

# 开发/调试环境启用详细重写日志
<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>

典型死循环特征

# 错误日志中的循环迹象
[rewrite:trace4] ... (1) init rewrite engine
[rewrite:trace4] ... (1) applying pattern '^/(.*)$' to uri 'index.php'
[rewrite:trace4] ... (2) init rewrite engine  <-- 数字递增表示递归
[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.

现代框架的安全模板

# Laravel / Symfony / 类似 MVC 框架
<Directory /var/www/laravel/public>
    RewriteEngine On
    # 严格递归限制(框架路由已处理多级逻辑)
    LimitInternalRecursion 2
    # 发送所有请求到 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>

关键最佳实践

核心要点:LimitInternalRecursion 是最后防线,良好设计的重写规则应通过 [END] 标志和 REDIRECT_STATUS 条件自我防循环,而非依赖递归限制。

 到此这篇关于Apache通过LimitInternalRecursion指令防止重写死循环的文章就介绍到这了,更多相关Apache LimitInternalRecursion防止重写死循环内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文