惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cloudbric
Cloudbric
E
Exploit-DB.com RSS Feed
SecWiki News
SecWiki News
Forbes - Security
Forbes - Security
N
News | PayPal Newsroom
S
Security @ Cisco Blogs
Schneier on Security
Schneier on Security
V
V2EX - 技术
S
Secure Thoughts
W
WeLiveSecurity
Google DeepMind News
Google DeepMind News
C
CERT Recently Published Vulnerability Notes
NISL@THU
NISL@THU
S
Securelist
S
Security Archives - TechRepublic
Know Your Adversary
Know Your Adversary
V
Vulnerabilities – Threatpost
Security Latest
Security Latest
Recent Commits to openclaw:main
Recent Commits to openclaw:main
G
GRAHAM CLULEY
H
Hacker News: Front Page
Microsoft Azure Blog
Microsoft Azure Blog
I
Intezer
Google Online Security Blog
Google Online Security Blog
美团技术团队
阮一峰的网络日志
阮一峰的网络日志
T
The Exploit Database - CXSecurity.com
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Webroot Blog
Webroot Blog
Jina AI
Jina AI
Engineering at Meta
Engineering at Meta
P
Proofpoint News Feed
The Cloudflare Blog
I
InfoQ
L
LangChain Blog
U
Unit 42
P
Proofpoint News Feed
S
Schneier on Security
S
Security Affairs
Y
Y Combinator Blog
T
Tenable Blog
N
News and Events Feed by Topic
MyScale Blog
MyScale Blog
量子位
Google DeepMind News
Google DeepMind News
Cyberwarzone
Cyberwarzone
博客园 - 聂微东
D
Darknet – Hacking Tools, Hacker News & Cyber Security
GbyAI
GbyAI
AWS News Blog
AWS News Blog

Dallas Lu

OpenWRT 使用 udp2raw 对抗 WireGuard 阻断 博客程序架构的思考与展望 如何证明你是原创作者 WISeID S/MIME 证书 V2EX 刑满释放记 使用 Radicale 在 Ubuntu 24.04 中搭建 vCards CardDav 服务 邮件服务的域名成功从 SURBL 黑名单移除 网站多语言的设计细节 网站评论系统的目前进展和展望 在公网使用 iptables 转发端口时保留客户端 IP 邮件投递平台 Postal 的使用经验 自建 Postal 完美替代 SendGrid 互联网在崩塌吗,然后呢 在 SvelteKit 应用中使用 JSON-LD 网页的打印样式应该怎么写 “茴字的四种写法”之 IP 与域名 怎么伪造 Git 提交的时区 供大众交流的论坛和其它替代产品还是不好用 改编不是照搬 一次排查诡异的网络问题的经历 在 OpenWRT 23 中使用 nftset 配置 Shadowsocks 规则 使用自建 Tabby Web 来同步 Tabby 配置 手动建立自己的 IPv6 Tunnel 服务 在 PVE 手动配置网络及虚拟机 IPv6 公网 在 PVE 中缩小 Ubuntu 虚拟机的磁盘 Beancount 摊销与折旧的使用以及相关插件 Nginx 反代 Apache Subversion 添加 HTTPS 使用你的主域名作为 Mastodon 实例名 Firefox 和 Chrome 为何要革 EV 证书的命
Nginx 泛域名配置的隐患与对策
达拉斯・卢 · 2025-05-23 · via Dallas Lu

一个网站的程序支持多站点模式,于是为了方便,在 Nginx 中绑定了域名 *.example.com,但奇怪的是,访问记录中总是有一些奇怪的二级域名,让人隐约觉得不妥。本文记述使用 Nginx 的来规避类似的风险。

Wildcard 域名绑定

原本的 Nginx 大约如下:

server {
    listen 80;
    server_name *.example.com;

    // blabla
}

这样配置简单方便。不过如果你的网站并不是多站点模式,或者网站程序未能恰当地处理,会导致任意二级域名却都能正常访问网站内容,是有点奇怪的。也许有人故意构造并发布了一个链接,不幸又被爬虫抓取,想想一下,从这个流量来源过来的访客们,纷纷皱着眉头看着你的奇怪的二级域名。这是一个未预期的行为,会影响 SEO,且有一定的合规风险,应当采取一些措施。

如果二级站点数量有限,可以手动列出全部二级域名:

server {
    listen 80;
-    server_name *.example.com;
+    server_name
+        www.example.com
+        cdn.example.com
+        api.example.com;
}

倘若你有更复杂的需要,仍需要保留 *.example.com 以简化配置,那么就可以加一个白名单的校验。

在 Nginx 中 $server_name 代表的是 server_name 配置中的第一个值,因此将网站的主域名放在第一位就非常方便后续处理。

如果你曾经使用过 blog.example.com,如今回归到 www.example.com, 那么更合适的办法应该是重定向。而其他未预期的域名都可以使用 return 444; 来直接断开连接。

server {
    listen 80;
-    server_name *.example.com;
+    server_name www.example.com example.com *.example.com;
+
+    if ($host ~* ^((blog|feed|log)\.example\.com|example.com)$) {
+        return 307 $scheme://$server_name$request_uri;
+    }
+
+    if ($host !~* ^(cdn|api)\.example\.com$) {
+        return 444;
+    }
}

默认主机

除了泛域名绑定之外,默认主机也会有类似的问题。如果在中国大陆,有未备案的域名指向到你的服务器,也有监管的风险。直接让默认主机断开所有连接:

server {
    listen 80 default_server;
    server_name _;

    return 444;
}

在某些情况下,你可能需要在阻断未指定域名的同时,支持使用 IP 地址直接访问:

-return 444;
+if ($host !~* "^((?:\d{1,3}\.){3}\d{1,3}|(?:[a-fA-F0-9:]+))$") {
+    return 444;
+}

SNI 域名泄露

在尝试 HTTPS 访问时,即便 Nginx 断开了连接,但客户端仍能够从返回的证书中获取 SNI 域名列表。很多人使用 CDN 全站加速来隐藏真实 IP,被扫描 IP 时,可能就会泄漏服务器与域名的关联。

可以在 server 块中配置,拒绝 ssl 握手:

+ssl_reject_handshake on;

如果你还是希望能够支持使用 IP 地址直接访问……那么,要使用一个 IP 专用的 SSL 证书。IP 证书购买渠道有限,自签一个也是可以的。

生成一个 IPv4 地址的证书:

openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout ip.key -out ip.crt \
  -subj "/CN=1.2.3.4" \
  -addext "subjectAltName=IP:1.2.3.4"

如果你还希望支持 IPv6……建立自签证书的配置 openssl-san.conf

[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no

[req_distinguished_name]
CN = (ip or domain or keep bank)

[v3_req]
subjectAltName = @alt_names

[alt_names]
IP.1 = 1.2.3.4
IP.2 = 2001:db8::1

openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout ip-mixed.key -out ip-mixed.crt \
  -config openssl-san.conf

然后配置 Nginx:

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;

    server_name _;

    ssl_certificate /path/to/ip.crt;
    ssl_certificate_key /path/to/ip.key;

    if ($host !~* "^((?:\d{1,3}\.){3}\d{1,3}|(?:[a-fA-F0-9:]+))$") {
        return 444;
    }
}

避免 CDN 域名被收录

    root /path/to/webroot/www.example.com;

    location = /robots.txt {
        default_type text/plain;

        if ($host = 'cdn.example.com') {
            #return 200 "User-agent: *\nAllow: /*.png$\nDisallow: /\n";
            alias /path/to/webroot/www.example.com/robots-cdn.txt;
        }
    }