zsh — anti@lateresonance:~ (微重力交互终端 v1.0)
按 `~` 或 `Esc` 展开/收起
🛸 欢迎接入 Late Resonance(迟到的共鸣 · 微重力前哨站) 交互式终端。输入 help 查看可用指令(支持 `ls`, `cat`, `status`, `speedtest`, `anti`, `jelly`)。
anti@lateresonance:~ %

[2026 Remastered · 09] 为什么禁止 IP 访问不能只写 RewriteRule /404.html?从 Apache 重定向死循环与证书泄密到 TLS 握手层零泄露阻断

📅 发布于: 2026-11-04 21:45:00 · 🔄 更新于: 2026-11-04 21:45:00 · 📖 6485 字 (约 22 分钟阅读)

🛸 站长重制导读(Anti Gravi's Remaster Note)

本文是 「来时路 · 2026 重制企划(9/12)」 的第 9 篇,对应本站 2020 年 11 月 9 日发布的 《禁止使用ip访问页面的方法》(CID: 44)。

2020 年的原稿记录了一个非常高频的企业合规与安全需求:“网页只能通过域名 www.example.com 访问,禁止通过服务器 IP 1.2.4.8 直接访问”。原稿选择在 Apache (httpd.conf) 中定义两组 <VirtualHost>,利用匹配顺序将 ServerName 1.2.4.8 放在前面,并写了 RewriteRule ^.* /404.html。

把“拦截 IP 的默认虚拟主机”放在配置文件最前面(利用 Apache/Nginx 首个虚拟主机作为 Default VHost 的特性)这个大方向是对的!然而,原稿里的具体配置代码却埋着 4 个只要一上生产就会暴露的协议与逻辑漏洞:从 RewriteRule ^.* /404.html 触发内部无限重写死循环(500 错误)或返回 200 OK 软 404,到 HTTPS 下给 IP 虚拟主机挂载真实证书导致未进 Rewrite 先弹浏览器红叉、甚至向全网黑客扫描器主动出卖源站真实域名!


一、 2020 原稿 (CID: 44) 四大配置硬伤逐行筛查

我们先回顾 2020 年原稿第 35~63 行的 Apache httpd.conf 配置代码:

# 2020 原稿 (CID: 44) 第 35~51 行原始配置:
<VirtualHost 1.2.4.8:443>                           # 设置虚拟主机
    ServerName 1.2.4.8                              # 设置服务名为1.2.4.8
    DocumentRoot /home/example
    SSLEngine on                                    # 启用ssl,用于https访问
    SSLCertificateFile /home/example/server.crt
    SSLCertificateKeyFile /home/example/server.key
    RewriteEngine On                                # 启用重定向
    RewriteRule  ^.*  /404.html                     # 将请求重定向到页面根目录下的404.html
</virtualhost>

<VirtualHost 1.2.4.8:80>
    ServerName 1.2.4.8
    DocumentRoot /home/example
    RewriteEngine On
    RewriteRule  ^.*  /404.html
</virtualhost>

为什么这段看似直观的配置在真实环境里会连环翻车?

编号 2020 原稿 (CID: 44) 写法 真实运行后果与底层协议原理 2026 Remastered 勘误与根治方案
1. RewriteRule ^.* /404.html 内部死循环或返回 200 OK 裸写 RewriteRule ^.* /404.html(未加 RewriteCond 排除自身,也未加 [R=404,L]) 1) 当没有终止条件时,/404.html 自身依然匹配正则 ^.*,在目录级或次级内部请求中会触发 AH00124: Request exceeded the limit of 10 internal redirects 直接报 500 错误;
2) 即便在 VHost 顶层未循环,不带 R= 标志的内部重写返回给客户端的 HTTP 状态码竟然是 HTTP/1.1 200 OK(即拿着 200 成功状态码返回一段写着 404 的 HTML,俗称“软 404”),完全违反 HTTP 语义!
根本无需开启消耗性能的 RewriteEngine!在 Apache 中直接使用 RedirectMatch 404 ^/ 配合 ErrorDocument 404 /404.html(或直接 Require all denied 返回 403)
2. HTTPS 下先撞 TLS 证书警告,根本走不到 RewriteRule! 在 <VirtualHost 1.2.4.8:443> 中挂载 www.example.com 的证书 server.crt,试图用 RewriteRule 展示 404.html 网络分层先后顺序错误! 客户端访问 https://1.2.4.8 时,必须先完成第 6 层 TLS 握手,才能发送第 7 层 HTTP 请求去触发 RewriteRule。因为正规域名证书的 SAN 里没有 1.2.4.8 这个 IP,浏览器在 TLS 握手阶段就会当场拦截并弹出刺眼的红色警告 NET::ERR_CERT_COMMON_NAME_INVALID,用户根本看不到你的 404.html! 对未携带合法域名 SNI 的 :443 IP 直接访问,应当在 TLS 握手阶段直接掐断连接(Apache SSLStrictSNIVHostCheck on / Nginx ssl_reject_handshake on)
3. 向全网扫描器主动出卖源站证书(CDN 源站暴露元凶!) 在 IP 默认 :443 虚拟主机上配置真实的业务证书 server.crt 这是安全防护中最致命的忌讳!Censys、Shodan 与黑客脚本每天都在对全网 IPv4 的 443 端口发起无 SNI 握手探测。如果你在 IP 虚拟主机上挂了 www.example.com 的真证书,扫描器一握手就能拿到证书里的 Subject / SAN 域名——哪怕你前面套了 Cloudflare 或高防 CDN,源站真实 IP 也会在 5 分钟内被全网扒光并遭受直接 DDoS 旁路攻击! 默认 IP 虚拟主机严禁挂载任何包含真实业务域名的证书!必须在 TLS 握手层直接拒绝无 SNI / IP 访问
4. 404.html 引用 fonts.googleapis.com 导致国内白屏 原稿第 73 行 HTML 头部写了 <link href='//fonts.googleapis.com/css?family=Lato:100' rel='stylesheet'> 在国内网络环境下,浏览器为了渲染这行只有 12 个字的错误提示,会傻傻等待 fonts.googleapis.com 连接超时(长达 15~30 秒白屏转圈)! 错误页必须 100% 零外部依赖(内联系统字体栈)

二、 为什么“禁止 IP 直接访问”在 2026 年的核心目标是「防源站 IP 泄露与防恶意域名恶意解析」?

很多初学运维的同学以为“禁止 IP 访问”只是为了满足甲方的表面需求。实际上,在现代生产架构中,这项配置承担着两项核心安全使命:

+-------------------------------------------------------------------------+
| 攻击场景 1:黑客扫描器全网遍历 IP:443 寻找你的 CDN 背后真实源站 IP        |
+-------------------------------------------------------------------------+
| 扫描器发送: ClientHello (无 SNI 或 SNI=1.2.4.8)                          |
|   ├── ❌ 2020 原稿配法: 服务器乖乖递上 www.example.com 的 server.crt 证书 |
|   │      ➔ 扫描器瞬间记录: "抓到了!1.2.4.8 就是 www.example.com 的源站!" |
|   └── ✅ 2026 标准配法: TLS 握手层直接回 Alert (unrecognized_name) 掐断   |
|          ➔ 扫描器什么证书都拿不到,源站完美隐身!                          |
+-------------------------------------------------------------------------+
  1. 防止他人将未备案或违规域名恶意 A 记录解析到你的公网 IP:
    • 如果你的 Web 服务器默认虚拟主机没有拦截未知 Host 头,别人把一个赌博或未备案域名解析到你的 1.2.4.8,云厂商信安系统一扫发现能打开你的网站内容,就会直接封停你的公网 IP!
  2. 隐藏源站身份:
    • 不论是 http://1.2.4.8 还是拿着别的野域名访问,甚至直接对 1.2.4.8:443 发起 TLS 握手,服务器都必须做到**“非我白名单域名,连一个字节的业务信息和证书都不吐”**。

三、 2026 生产级双栈标准配置(Apache 2.4 & Nginx 1.26)

方案 A:Apache 2.4 标准配置(修正 2020 原稿的 httpd.conf)

在 Apache 2.4 中,我们通过第一个默认 <VirtualHost> 兜底所有 IP 访问与未知域名访问,用 RedirectMatch 404 替代错误的 RewriteRule,并通过 SSLStrictSNIVHostCheck on 拒绝任何不带合法域名 SNI 的 HTTPS 握手:

# ==============================================================================
# 1. 第一个 VirtualHost(默认兜底黑洞:拦截所有 IP 直接访问与未知域名恶意解析)
# ==============================================================================
<VirtualHost *:80>
    ServerName default-blackhole.invalid
    DocumentRoot /var/www/empty

    # 无需开启 RewriteEngine,直接返回真实的 HTTP 404 状态码并展示零外部依赖的 404.html
    ErrorDocument 404 /404.html
    RedirectMatch 404 ^/(?!404\.html$)
</VirtualHost>

<VirtualHost *:443>
    ServerName default-blackhole.invalid
    DocumentRoot /var/www/empty

    SSLEngine on
    # ⚠️ 关键安全铁律:此处仅放一张 CN=invalid.local 的无意义自签名假证书占位,
    # 绝对禁止挂载 www.example.com 的真实业务证书!
    SSLCertificateFile    /etc/apache2/ssl/dummy-selfsigned.crt
    SSLCertificateKeyFile /etc/apache2/ssl/dummy-selfsigned.key

    # 强制严格校验 SNI:若客户端用 IP 访问 https://1.2.4.8,直接返回 403 拒绝!
    SSLStrictSNIVHostCheck on

    ErrorDocument 404 /404.html
    RedirectMatch 404 ^/(?!404\.html$)
</VirtualHost>

# ==============================================================================
# 2. 第二个 VirtualHost(真正的业务域名虚拟主机:仅匹配 www.example.com)
# ==============================================================================
<VirtualHost *:80>
    ServerName www.example.com
    # 将 HTTP 域名访问 301 永久重定向至 HTTPS
    Redirect permanent / https://www.example.com/
</VirtualHost>

<VirtualHost *:443>
    ServerName www.example.com
    DocumentRoot /home/example

    SSLEngine on
    SSLCertificateFile    /home/example/server.crt
    SSLCertificateKeyFile /home/example/server.key
</VirtualHost>

方案 B:Nginx 1.26+ 最简零泄露标准配置(推荐)

自 Nginx 1.19.4+ 起,官方提供了极其优雅的 ssl_reject_handshake on; 指令——连假的自签名占位证书都不需要生成,直接在 TLS 握手第一个包就将 IP 访问踢下线;而在 HTTP 层则使用 Nginx 专属的 return 444;(直接发送 TCP FIN/RST 关闭套接字,连 HTTP 响应头都不回,零带宽消耗):

# 1. 默认兜底虚拟主机(default_server):拦截一切 IP 直接访问与未知 Host 头
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;
    server_name _;

    # HTTPS 层:遇到 IP 访问或未知 SNI 域名,在 TLS 握手阶段直接拒绝(零证书信息泄露!)
    ssl_reject_handshake on;

    # HTTP 层:直接掐断底层 TCP 连接(或者按需改为 return 404;)
    return 444;
}

# 2. 正常业务域名虚拟主机
server {
    listen 443 ssl;
    server_name www.example.com;

    ssl_certificate     /etc/nginx/ssl/www.example.com/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/www.example.com/privkey.pem;

    root /home/example;
    index index.html;
}

附:移除 fonts.googleapis.com 外部阻塞后的极速内联 404.html

如果业务方要求用 IP 访问 HTTP 80 端口时必须看到与原稿一致的友好 404 页面,只需删掉原稿第 73 行那句拖慢国内访问的 Google Fonts 外链,改用现代系统原生无衬线字体栈即可毫秒级渲染:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>404 Not Found</title>
  <style>
    html, body {
      margin: 0; padding: 0; width: 100%; height: 100%;
      color: #B0BEC5; display: table; font-weight: 300;
      font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", sans-serif;
    }
    .container { text-align: center; display: table-cell; vertical-align: middle; }
    .content { text-align: center; display: inline-block; }
    .title { font-size: 42px; margin-bottom: 40px; }
  </style>
</head>
<body>
  <div class="container">
    <div class="content">
      <div class="title">404 很抱歉,您查看的页面找不到了!</div>
    </div>
  </div>
</body>
</html>
🛸 安缇 (Anti Gravi) · 云端伴读舱 微重力巡航中

*(小水母 Gravi-Jelly 在半空轻轻闪烁着荧光青触角,帮你盯死每一行配置与 1C512M 内存水位 🪼✨)*

前哨站内存: -- MB | 系统已用: -- / -- MB
守望灯塔: Zero-G Anchor · 在线值守
微重力前哨站 · 内存: --MB · 负载: --