Apache禁止IP直接访问站点时自定义403错误页无法加载
Apache拦截IP直接访问时自定义403错误页不生效解决
问题现象
通过VirtualHost或.htaccess配置禁止用户通过IP直接访问站点时,/var/www/html/error.php定义的自定义错误模板无法加载,页面返回报错:Additionally, a 403 Forbidden error was encountered while trying to use an ErrorDocument to handle the request.
运行环境:Apache/2.4.38
初始VirtualHost配置:
ErrorDocument 400 /error.php ErrorDocument 401 /error.php ErrorDocument 403 /error.php ErrorDocument 404 /error.php ErrorDocument 500 /error.php <VirtualHost *:80> ServerName subdomain.example.com ServerAlias www.subdomain.example.com DocumentRoot /var/www/html ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost> <VirtualHost *:80> ServerName 1.1.1.1 ServerAlias 2001:2001:2001:2001:2001:2001:2001:2001 DocumentRoot /var/www/html <Location /> Require all denied </Location> </VirtualHost>
改用.htaccess配置拦截时也出现相同问题,初始.htaccess配置:
RewriteCond %{HTTP_HOST} ^1\.1\.1\.1$ RewriteRule .* - [F,L] #RewriteCond %{HTTP_HOST} !^2001\:2001\:2001\:2001\:2001\:2001$
根本原因
现有拦截规则覆盖了站点根目录下的所有请求路径。Apache触发403错误后,会发起内部子请求读取/error.php内容返回给客户端,这个内部子请求同样命中拦截规则被拒绝,导致自定义错误页加载失败,触发二级403报错。
解决方法
方法1:调整VirtualHost配置(推荐,性能优于.htaccess)
在IP访问对应的VirtualHost段中,先给错误页文件放开访问权限,再执行全路径拦截,修改后配置如下:
ErrorDocument 400 /error.php ErrorDocument 401 /error.php ErrorDocument 403 /error.php ErrorDocument 404 /error.php ErrorDocument 500 /error.php <VirtualHost *:80> ServerName subdomain.example.com ServerAlias www.subdomain.example.com DocumentRoot /var/www/html ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost> <VirtualHost *:80> ServerName 1.1.1.1 ServerAlias 2001:2001:2001:2001:2001:2001:2001:2001 DocumentRoot /var/www/html # 单独放开错误页访问权限 <Files "error.php"> Require all granted </Files> # 拦截其余所有路径 <Location /> Require all denied </Location> </VirtualHost>
配置修改完成后执行systemctl reload apache2重载Apache服务即可生效。
如果需要更高的安全性,也可以新建独立目录(比如/var/www/error/)存放错误页文件,在IP对应的VirtualHost中仅对该目录授权,完全避免站点其他文件被IP访问时暴露。
方法2:修改.htaccess拦截规则
如果使用.htaccess实现拦截,在规则中排除错误页路径,同时补全原配置中被注释的IPv6地址拦截逻辑,修改后内容如下:
# 匹配IPv4和IPv6的IP直接访问请求 RewriteCond %{HTTP_HOST} ^1\.1\.1\.1$ [OR] RewriteCond %{HTTP_HOST} ^2001\:2001\:2001\:2001\:2001\:2001\:2001\:2001$ # 排除错误页路径,不拦截内部读取请求 RewriteCond %{REQUEST_URI} !^/error.php$ # 返回403拦截 RewriteRule .* - [F,L]
内容的提问来源于stack exchange,提问作者Bilal Bhatti
相关产品推荐
相关产品推荐

