

























最近在排查一个非常诡异的问题:
页面 A:正常业务页面,直接打开一切 OK。页面 B:通过 <iframe src="页面 A"> 把 A 嵌进来。页面A 里以<script>的方式引用了一个内部 CDN 脚本 https://xxxx/a.js,CDN 域名(代号xxxx)和页面A域名(代号yyyy)不同,页面A和页面B(代号zzzz)域名也不同。
在 Chrome(新版本)访问页面B时,控制台报错,页面无法正常访问:
1 | Access to script at 'https://xxxx/a.js' from origin 'https://yyyy' |
开发者工具Network面板中也显示这几个 js 文件请求都是CORS error
看到这个报错时整个人都懵了,因为<script>标签引用的脚本,怎么可能有 CORS 问题?像 JSONP 这种技巧不也是利用了<script>标签的特性嘛。
面对这种奇怪的现象,我做了一些实验。发现从现象上有以下奇怪的点:
页面A时一切正常,cdn 的 js 不会报 CORS 错误,只有在访问页面B时(以iframe形式访问页面A)才会报错;<script>标签引用的脚本请求会报 CORS 错误,页面A其他 ajax 跨域请求也会报错(这些请求都做了 CORS 设置);页面A可以正常访问;页面A可以正常访问;unknown address space 这种字样,相比其他 CORS 错误信息是很陌生的;结合这些信息,我基本断定是近期新版 Chrome 在网络策略上做了什么调整。在分析更新日志等信息后,最终排查下来,根因其实不是传统意义上的 CORS,而是 Chrome 最近上线的一套 Local Network Access / Private Network Access(LNA/PNA)安全策略 + iframe 权限机制 在背后搞事情。
回顾错误信息:
1 | Access to script at 'https://xxxx/a.js' from origin 'https://yyyy' |
几个关键信息:
https://xxxx/a.jshttps://yyyy —— 注意这是页面A的域,而不是页面B的域。blocked by CORS policy,但额外带了unknown address space的提示。结合几个“奇怪”的点,这已经在提示我们:真正做决策的是“顶层站点 + 地址空间”,而不是 iframe 自己的 origin——这正是 Local Network Access / Private Network Access 的行为特征。
经典的 CORS 问题一般长这样:
1 | No 'Access-Control-Allow-Origin' header is present on the requested resource. |
或者
1 | The 'Access-Control-Allow-Origin' header has a value 'xxx' that is not equal to the supplied origin. |
而这次的错误信息多了这样一句:
1 | Permission was denied for this request to access the `unknown` address space. |
这句话用在很多类似案例里(如StackOverflow 问题示例),几乎都是 Chrome 的 Private Network Access / Local Network Access 安全检查触发 的结果,而不是简单的 CORS 头缺失。
再结合现象:
页面A 正常;说明:
https://xxxx 这个 origin 的 CORS 配置本身是 OK 的;页面B 的域名(https://zzzz)时,Chrome 用的是另一套安全逻辑。用报错中的关键字去搜:
会发现大量类似提问或者官方说明,都指向这几个关键点:
进一步验证:
页面A(Origin 为 https://xxxx)时,CDN js 资源加载正常;这基本就把问题锁定在:
Chrome 把“顶层站点 + 目标资源”看作一次「跨地址空间访问」,并在 iframe 场景下启用了更严格的 LNA / PNA 检查。
要理解这个问题,需要先大致了解 Chrome 近几年在做的两件事:

规范里把目标地址按“私密程度”分了几档:
public:公网 IP / 域名;private / local:内网 IP(10.x / 192.168.x / 172.16–31.x 等);loopback:本机地址(127.0.0.1 / localhost 等);unknown:浏览器无法可靠判断所属空间的时候(某些 VPN / Zero Trust / 特殊代理场景经常掉进这里)。核心安全模型是:
从「更开放的地址空间」访问「更私密的地址空间」时,要么被禁止,要么需要额外的 CORS/PNA 头或用户授权。
PNA(以前叫 CORS-RFC1918)是第一阶段方案:
Access-Control-Request-Private-Network: trueAccess-Control-Allow-Private-Network: true2025 年开始,Chrome 推出了新的 LNA 规范:
Local Network Access 权限框,让用户决定 Allow/Block(https://support.esri.com/en-us/knowledge-base/what-to-know-about-new-permission-prompt-in-google-chro-000039171);allow="local-network-access"LNA 还跟 Permissions Policy(原 Feature Policy) 集成在一起,特别是 iframe 场景:
1 | <iframe src="https://xxxx/pageA" allow="local-network-access"></iframe> |
allow,否则最内层拿不到权限;fetch / <script> / WebSocket 等对本地/内网/unknown 地址空间的访问,就会被 Chrome 直接拦截,DevTools 里通常表现为你看到的这种 CORS+unknown address space 报错。unknown address space把前面的信息套进来,我们可以比较有把握地还原一下这次的问题链路:
页面B:https://zzzz(public 站点);页面A:https://xxxx;页面A 里引用脚本:<script src="https://xxxx/a.js"></script>;https://xxxx 很可能通过公司的 DNS / ZTNA / VPN 等解析到 内网或特殊网络(事实证明也确实解析到了192的网络),对 Chrome 来说 IP 所属地址空间是 private 或 unknown;xxxx 对应的(unknown / private)地址空间; allow="local-network-access"; 于是这条 script 请求在发出前就被 LNA 拦截,DevTools 以统一形式打印:
1 | Access to script at 'https://xxxx/a.js' from origin 'https://yyyy' |
从浏览器视角看,这是:一个 public 顶层站点在未经授权的情况下,试图从 iframe 中访问 unknown/local/private 网络资源。
从我们的视角看,就是:明明是同一个脚本 URL,顶层页面能加载,iframe 就报奇怪的 CORS。
实质上是 LNA + iframe 权限 + 地址空间判断 的组合拳。
在遇到 ...unknown/private/local address space 报错时,可以按下面的顺序快速确认是否为 LNA/PNA:
allow="local-network-access" 验证是否能消除报错;多层 iframe 需层层透传。Local Network Access 权限是否被 Block/Prompt,必要时手动 Allow(仅用于诊断)。chrome://flags#local-network-access-check 为 Non-blocking/Disabled 验证(只用于定位,不是正式解决方案)。Access-Control-Allow-Private-Network: true,并确保预检 OPTIONS 正确返回。从安全模型来看,Chrome 的判断并不是“反常”,而是架构上的风险被暴露出来了:
https://yyyy / https://xxxx);最根本、最长期稳妥的方案是:
这类改造成本会高一些,但可以一次性消掉大部分 LNA/PNA 类问题。
在没法马上改架构的情况下,可以考虑这些策略(主要适用于内网/企业环境):
allow="local-network-access"<iframe src="https://xxxx/pageA" allow="local-network-access"></iframe>Access-Control-Allow-Private-Network: trueOPTIONS 请求能正确返回这个头。chrome://flags#local-network-access-check 改为 Non-blocking / Disabled,看问题是否消失;以 Nginx 反代为例,把内网 10.1.2.3:8080 挂到外层域名 api.example.com,浏览器视角是 public→public:
1 | server { |
这样页面与 API 同为 public 地址空间,LNA/PNA 不再触发;同时保持 HTTPS,方便复用现有 CORS/缓存策略。
1 | ... has been blocked by CORS policy: |
可以按下面这条“套路”来排查:
unknown address space / private network / local network access 等关键词;PNA/LNA 的本质,是浏览器在给“网页能不能碰你本机/内网”这件事重新立规矩:过去网页默认可以直接访问内网 IP、localhost 等资源,容易被用来扫内网、攻击路由器、探测隐私环境,所以 Chrome 先通过 PNA 把“公网 → 内网/本机”的请求纳入 CORS,高危路径要额外 preflight 和新头;再演进到 LNA,用权限弹窗、站点设置、企业策略和 allow=”local-network-access” 这类 iframe 权限,把决策变为“用户/企业明确授权 + 细粒度控制”;发展趋势很清晰——未来从公网页面直连内网/本机会越来越难,iframe、第三方脚本会被限制得更死,推荐模式会转向“浏览器只连受控中间层或本地代理”,对我们做前端和架构的人来说,需要把“浏览器直连内网”当成过渡方案,长期用“网关/代理 + 明确权限”的架构来规避这类风险。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。