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

推荐订阅源

Google DeepMind News
Google DeepMind News
I
InfoQ
Engineering at Meta
Engineering at Meta
D
DataBreaches.Net
L
LangChain Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Recent Announcements
Recent Announcements
GbyAI
GbyAI
爱范儿
爱范儿
Microsoft Security Blog
Microsoft Security Blog
腾讯CDC
美团技术团队
罗磊的独立博客
Microsoft Azure Blog
Microsoft Azure Blog
WordPress大学
WordPress大学
T
The Blog of Author Tim Ferriss
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
雷峰网
雷峰网
M
MIT News - Artificial intelligence
D
Docker
MongoDB | Blog
MongoDB | Blog
F
Fortinet All Blogs
博客园 - 叶小钗

吹比💨

NFS 服务引发的一次“诡异”应急响应 银狐使用WDAC来对抗杀软 浏览器第三方Cookie保护导致无法使用Github.dev 使用pushState伪造浏览器地址栏 一次排查网站劫持过程流水账 手动导出 Microsoft Authenticator 中的2FA密钥 使用CloudFlare的IP Lists功能来做访问控制 FrontJS网站错误监控插件存在弹窗广告 宝塔面板可能存在未知漏洞的分析与处置方法 中文域名那些事 TLS握手指纹(JA3/JA3S)检测恶意软件流量 [A-Z]{2}\d{2}.cc 团伙的一些公开信息 Azure旗下奇怪的静态托管服务 Csrf与浏览器第三方Cookie策略的问题 Pppoe密码嗅探 Publicsuffix那些事 一次有意思的域名追踪 CobaltStrike通信中host字段的获取 XFF那些事 CORB那些事 Referrer Policy那些事 使用CloudFlare来为网站开启客户端证书验证 DNS那些事 用flask来在线管理你的iptables 屏蔽掉向日葵的有效方法 帝国cms在防止内容采集方面做的工作 身份验证器是如何验证我们的身份? 利用GoogleAppsScript自动回复短信实现保号 Nginx实用模块 有关跨域请求的一些记录
CDN厂商解决域前置问题
榆木 · 2022-12-03 · via 吹比💨

去年写了一篇 域前置 相关文章 原文 https://www.freebuf.com/articles/web/271046.html ,最后的 CDN厂商如何禁止域前置方面没有写清楚。最近又看了一下,补充一下nginx相关配置。

从一个例子入手

有如下nginx配置:

server {
    listen 443 default_server ssl;
    ssl_reject_handshake on;
    return 200 "ok$ssl_server_name$host$server_name" ;
}
server {
    listen 443 ssl;
    server_name www.* ;
    ssl_certificate     /etc/nginx/conf.d/a.cert;
    ssl_certificate_key /etc/nginx/conf.d/a.key;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    return 200 "not ok$ssl_server_name$host$server_name";
} 

有如下访问:

curl https://www.baidu.com:10443 --resolve www.baidu.com:10443:127.0.0.1 -k -H "host:baidu.com" -v

curl https://www.baidu.com:10443 --resolve www.baidu.com:10443:127.0.0.1 -k  -H "host:baidu.com" -v
* Added www.baidu.com:10443:127.0.0.1 to DNS cache
* About to connect() to www.baidu.com port 10443 (#0)
*   Trying 127.0.0.1...
* Connected to www.baidu.com (127.0.0.1) port 10443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* skipping SSL peer certificate verification
* SSL connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* Server certificate:
*       subject: CN=www.baidu.cn,O="BeiJing Baidu Netcom Science Technology Co., Ltd",postalCode=,ST=Beijing,C=CN
*       start date: Dec 03 10:10:33 2022 GMT
*       expire date: Nov 30 10:10:33 2032 GMT
*       common name: www.baidu.cn
*       issuer: CN=www.baidu.cn,O="BeiJing Baidu Netcom Science Technology Co., Ltd",postalCode=,ST=Beijing,C=CN
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Accept: */*
> host:baidu.com
> 
< HTTP/1.1 200 OK
< Server: nginx/1.22.0
< Date: Sat, 03 Dec 2022 11:34:51 GMT
< Content-Type: application/octet-stream
< Content-Length: 24
< Connection: keep-alive
< 
* Connection #0 to host www.baidu.com left intact
okwww.baidu.combaidu.com

tls握手阶段使用了第二个server的配置,但最后访问到的依然是default_server,因已经过了SSL握手阶段,也没有走到ssl_reject_handshake on

为什么会这样?

http://nginx.org/en/docs/http/server_names.html 中描述的相关匹配逻辑如下:

First, a connection is created in a default server context. Then, the server name can be determined in the following request processing stages, each involved in server configuration selection:

  • during SSL handshake, in advance, according to SNI
  • after processing the request line
  • after processing the Host header field
  • if the server name was not determined after processing the request line or from the Host header field, nginx will use the empty name as the server name.

在ssl握手过程中,server_name字段来自于sni,也就是www.baidu.com。在获取到header中的Host后,server_name又重新赋值为了baidu.com 。正因为这里server_name取值的重复性,所以导致了域前置的产生。

解决方案

nginx 1.7.0 引入的变量 可以获取到 sni 的值,

$ssl_server_name returns the server name requested through [SNI](http://en.wikipedia.org/wiki/Server_Name_Indication) (1.7.0);

所以需要在每个server block里面添加以下逻辑:

 if ($ssl_server_name != $host){
       return 444; #具体返回什么无所谓,看具体业务安排。
 }

完整配置如下:

server {
    listen 80 default_server;
    listen 443 default_server ssl;
    ssl_reject_handshake on;
    return 444;
}
server {
    listen 80;
    listen 443 ssl;
    server_name www.domain.com ;
    ssl_certificate     /etc/nginx/conf.d/a.cert;
    ssl_certificate_key /etc/nginx/conf.d/a.key;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    if ($ssl_server_name != $host){
        return 444;
    }
    #巴拉巴拉 
} 
server {
    listen 80;
    listen 443 ssl;
    server_name qqq.domain.com ;
    ssl_certificate     /etc/nginx/conf.d/a.cert;
    ssl_certificate_key /etc/nginx/conf.d/a.key;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    if ($ssl_server_name != $host){
        return 444;
    }
    #巴拉巴拉 
} 

设置default_server的同时也可以解决使用IP直接访问时导致的默认证书泄露问题。

设置以后有可能导致无sni的反向代理无法正常访问,需要为原有的proxy_pass设置sni:

proxy_pass https://backend;
proxy_ssl_name $host; 
proxy_ssl_server_name on;