← LeisureLinux 文章索引
LeisureLinux · 微信公众号文章

内网 PAC 也上 HTTPS 了——一场防 MITM 的"内网藏匿术"

安全/漏洞 阅读原文(微信)↗
信任一个明文传输的      [流量决策文件]{b="b" solid="solid"}      ,本身就是信任链上最脆弱的一环

```——LeisureLinux

公司/家里的终端要上网,几乎都绕不开一个叫 [PAC]{b="b" solid="solid"} 的文件。它替浏览器和系统决定"哪些直连、哪些走代理"。但这个文件默认裸奔在 HTTP 上------被劫持、被篡改,就是一次教科书级的中间人攻击。

今天我把 [wpad PAC 服务器搬上了 HTTPS]{b="b" solid="solid"} ,用 Let\'s Encrypt 自动续期,还做到全程不把内网拓扑暴露给公网。这里有内网 DNS 和没有内网 DNS(家用路由器兜底)两条路都能落地,全过程复盘给你。

本文看点

01

内网域名 + 公信 CA 证书的两全解法

02

DNS-01 验证为何是纯内网域名的利器

03

acme.sh 自动续期实现永久无人值守



01

WHAT IS PAC

###          PAC 是什么?为什么它必须安全?

[PAC(Proxy Auto-Config)]{b="b" solid="solid"} 是一段 JavaScript,浏览器通过 [FindProxyForURL(url, host)]{mono="mono" px="px"} 返回 DIRECT 或 PROXY 决定流量走向。它通常由内网一台超轻量 nginx 提供,域名就叫 [wpad]{b="b" solid="solid"} (配合自动发现协议,见第五章)。

风险点: PAC 是流量路径的"总开关" 。如果它被 MITM 篡改成 [PROXY attacker:8080]{mono="mono" px="px"} ,整个内网流量都会被导进攻击者的隧道------密码、cookie、内网页面全裸奔。更阴险的是,篡改可以只针对特定目标(比如把某域名改成 DIRECT 再抓包)。

「信任一个明文传输的信任决策文件,本身就是信任链上最脆弱的一环。」



02

THE DILEMMA

###          经典困境:内网要安全,但又不想暴露内网

给 PAC 上 TLS 并不难,难在两件事:

1

[证书从哪来?]{b="b" solid="solid"} 内网没有合法 CA,自签证书会让每台终端弹警告、加例外------运维噩梦,等于没上。

2

要不要把 wpad 绑到公网?完全不用。 [wpad.mydomain.com 是纯内网域名]{b="b" solid="solid"} :公网权威 DNS 上根本没有这条记录,只有内网 DNS 能解析到 192.168.x.x。

于是我的解法很干脆:      **内网域名 + 公信 CA 证书,两全其美。**

[
域名只在内网解析]{px="px"}

公网看不到,天然"藏匿"。

[
DNS-01 签发公信证书]{px="px"}

绑定这个内网域名,终端验证通过、零警告。

[
PAC 文件只在内网可达]{px="px"}

文件确实明写着内网代理地址/IP/端口——"不暴露"靠的不是文件里没写,而是公网拿不到这份文件。

证明给 CA 看的是"域名控制权",喂给终端的是"内网地址"。两者并不冲突。



03

CERTIFICATE

###          证书怎么申请:acme.sh + aliyun DNS 插件

先装 [acme.sh]{b="b" solid="solid"} (会同时注册自动续签的 cron,见第六节):

```bash

curl https://get.acme.sh | sh -s email=you@example.com

     接着准备 DNS 验证需要的认证信息。acme.sh 用云厂商的凭证来操作 DNS、自动写 TXT 记录。以阿里云为例:把 AccessKey ID  AccessKey Secret 填进去(      [用只给 DNS 权限的最小化子账号更稳妥]{b="b" solid="solid"}      ):

                     .        .        .        bash

export Ali_Key=\"你的AccessKeyID\"

export Ali_Secret=\"你的AccessKeySecret\"

       我本机是直接复用已配置好的 aliyun CLI 凭证,从 \~/.aliyun/config.json 里把 AK/Secret 提取出来喂给 acme.sh  dns_ali 插件------一个凭证两处用,不用再手工拷一遍密钥。存凭证推荐放 \~/.acme.sh/ali.env  chmod 600,别写死在脚本里。

     然后申请,      [关键是用 --dns dns_ali]{f97316="f97316" solid="solid"}      (走 DNS-01 验证,不是 HTTP-01):

                     .        .        .        bash

acme.sh --issue --dns dns_ali -d wpad.mydomain.com

     dns_ali 插件会自动调阿里云 DNS API,在权威区加一条      [_acme-challenge.wpad.mydomain.com]{mono="mono" px="px"}        TXT 记录,等认证服务器验证通过后清理掉。全程不需要在公网放任何 A 记录,也不需要开 80/443 端口------      **这正是给纯内网域名签证书的关键。**

     签发结果:ZeroSSL ECC DV 证书,      [CN=wpad.mydomain.com]{b="b" solid="solid"}      ,有效期 90 天,由 ARIACME Renewal Information,续期信息扩展,见文末名词解释)自动安排续签窗口。

为什么必须是 DNS-01?

[ HTTP-01]{px="px"}

需要 80 端口放验证文件、且要求该域名可从公网访问——内网域名根本做不到,直接用不了。

[ DNS-01]{px="px"}

只需在持有该域名的权威 DNS(公共权威区,如云厂商)加一条 TXT 记录——不需要 wpad 在公网有 A 记录,也不需要开任何端口。

一句话,      [签证书只需要域名的 DNS 控制权]{b="b" solid="solid"}      ,跟它是不是内网域名毫无冲突------这就是 DNS-01 的核心威力:能凭空为一条只在内网解析的域名签出合法公信证书。

04

NGINX CONFIG

Nginx 双面配置:http 兼容 + https 主服务

nginx 这里的"双面"      [不是公网/内网两套域名,而是内网主域名的 http  https 两个入口]{b="b" solid="solid"}      。核心原则:内网主域名走 HTTPS 强制,内网短名 wpad / wpad.lan  HTTP 豁免------短名没证书,挂到 443 会因证书不匹配直接  握手失败      

. . . nginx · 80

server {

listen 80;

server_name wpad wpad.lan wpad.mydomain.com;

location = /wpad.dat {

default_type application/x-ns-proxy-autoconfig;

charset utf-8; expires 30m;

}

location / { return 301 https://\$host\$request_uri; }

}

. . . nginx · 443

server {

listen 443 ssl;

server_name wpad.mydomain.com;

ssl_certificate /etc/nginx/ssl/wpad.crt;

ssl_certificate_key /etc/nginx/ssl/wpad.key;

location = /wpad.dat {

default_type application/x-ns-proxy-autoconfig;

}

}

那些 application/x-ns-proxy-autoconfig 是 PAC 的关键 MIME——类型不对很多客户端直接拒绝解析,这是最容易踩的坑。

05

AUTO DISCOVERY

wpad 是怎么被自动发现的?

终端拿到 PAC 有两种方式:

1

[显式配置]{b="b" solid="solid"}          :在浏览器/系统代理设置里填 wpad.lan/wpad.dat 或 wpad.mydomain.com/wpad.dat。最可控。

2

[自动发现(WPAD 协议)]{b="b" solid="solid"}          :终端按 DNS 后缀或 DHCP 选项自动去猜 PAC 地址。这也是为什么服务器名必须叫 wpad、文件必须叫 wpad.dat------协议是硬编码的,改名就失灵。

要让自动发现生效,还必须满足两个前提:

[ DHCP 下发搜索后缀]{px="px"}

下发默认 DNS 搜索后缀 mydomain.com,终端才会去猜 wpad.mydomain.com 这个完整域名。

[ 内网能解析 wpad 域名]{px="px"}

有自建 Unbound 加一条本地记录;没内网 DNS 时,在家用路由器的 DHCP 设置里写静态 DNS/Hosts 条目即可,路由器对内网统一下发。

三者咬合成一条链路:      [DHCP 给搜索域 → 终端拼出 wpad 域名 → 内网解析到 192.168.x.x → 就近加密取 PAC]{b="b" solid="solid"}      。少一环,自动发现就断。

自动发现的具体握手细节可另开一篇。记住结论:名字、MIME、搜索域是 WPAD 的生命线,内网解析是它的地基。

06

AUTO RENEW

证书自动续期:装一次,永久自愈

acme.sh 安装时自动注册 cron,定时调用      [acme.sh --cron]{mono="mono" px="px"}      。它      [不是每次都申请]{b="b" solid="solid"}      ,而是先检查距到期还剩多少天(默认提前 30 天,靠 ARI 定位精确窗口),没到就静默退出;到点才真正发起 DNS-01 申请,成功后自动安装:
acme.sh --install-cert -d wpad.mydomain.com \\

  --key-file       /etc/nginx/ssl/wpad.key \\

  --fullchain-file /etc/nginx/ssl/wpad.crt \\

  --reloadcmd      \"systemctl reload nginx\"

     --reloadcmd 是关键------      [续签成功那一刻自动 reload nginx]{b="b" solid="solid"}      ,证书无缝切换,全程无人值守。cron 设成一天两次、工作日即可;以 90 天有效期算,一天一次都绰绰有余。别照抄"每 6 小时申请"的教程------那只是空跑检查,纯属浪费。

07

GLOSSARY

名词解释

[ PAC / wpad]{px="px"}

Proxy Auto-Config,一段 JavaScript,浏览器通过 FindProxyForURL(url, host) 决定每个域名是直连还是走代理。wpad 是这套协议约定俗成的服务器主机名。

[ MITM 中间人攻击]{px="px"}

攻击者插入在客户端与服务器之间,截获甚至篡改双向流量。明文传输的 PAC 一旦被 MITM,等于把整个代理路径交给攻击者。

[ DNS-01 验证]{px="px"}

ACME 的域名所有权验证方式,在权威 DNS 加一条 _acme-challenge.\<域名> 的 TXT 记录。不需要公网 A 记录,也不需开端口——给纯内网域名签证书的利器。

[ ARI 续期信息]{px="px"}

ACME Renewal Information,CA 通过它主动告知客户端精确的续期窗口。简单说:不用自己数日子,服务器会"喊"你回来续。

[ DNS 分离 / Split-Horizon]{px="px"}

同一域名在不同 DNS 视角下解析到不同地址。wpad.mydomain.com 只在内网解析到 192.168.x.x,公网权威区没有这条记录——既拿得到证书,又不暴露内网。

EPILOGUE

写在最后

内网安全不是非黑即白:      [既要可信,又不想暴露]{b="b" solid="solid"}      。HTTPS PAC 这套思路------纯内网域名 + DNS-01 公信证书 + PAC 敏感清单只在内网可达------在"信任"与"藏匿"之间找到了平衡。

「安全的内网,是被信任但读不穿的。」

END

我是 LeisureLinux,热衷于分享 Linux 底层架构与内网安全的实战观察。

如果你觉得今天这篇有收获,欢迎 点赞、在看、转发 三连,我们下篇见。

从动态挑战到声明式授权:ACME 协议的零信任演进与 DNS-PERSIST-01 实践 告别"不安全"警告!3分钟读懂 ACME 协议,让你的网站免费自动续期 Let\'s Encrypt 在交叉签名根证书事件后暂停证书签发 从 SNI 泄露到 ECH 全链路加密:OpenSSL 4.0 强制驱动的 DNS 架构演进 全球统一执行!2029年TLS证书有效期锁死47天 【首发】Cloudflare 高危 0-day 曝出:一个"隐形"路径,竟能让全球 WAF 防护瞬间失效!

本文整理自微信公众号 LeisureLinux 的原创内容(Linux / AI / 安全 硬核技术)。

· 阅读原文(微信公众号)

· 关注公众号 LeisureLinux,第一时间获取技术深度内容。

LeisureLinux 公众号二维码(微信扫一扫关注)