【笔记】浏览器 PNA/LNA 策略——记一次 iframe 中 CORS 报错的问题排查经历

【笔记】浏览器 PNA/LNA 策略——记一次 iframe 中 CORS 报错的问题排查经历

💡 原文中文,约11200字,阅读约需27分钟。
📝

内容提要

新版Chrome的LNA/PNA策略导致iframe中跨域脚本报CORS错误。当顶层页面通过iframe嵌入其他页面,且资源解析到内网或unknown地址空间时,Chrome会拦截请求,除非iframe声明`allow="local-network-access"`。解决方案包括:通过代理统一地址空间、为iframe添加权限、或配置站点权限。

🔎

延伸解读

为何报错像 CORS 却不是 CORS

错误信息虽以“blocked by CORS policy”开头,但关键在“unknown address space”提示。传统 CORS 问题源于响应头缺失或不匹配,而此处是 Chrome 的 LNA/PNA 策略在请求发出前拦截。该策略基于顶层站点与目标资源的地址空间关系,而非 iframe 自身的 origin,因此即使服务器 CORS 配置正确,仍可能被拦截。

iframe 权限与地址空间判断

LNA 策略与 Permissions Policy 集成,顶层页面需在 iframe 标签中显式声明 allow="local-network-access",且多层嵌套需层层透传。若未授权,iframe 内对 private/unknown 地址空间的请求会被拦截。实际环境中,公司 DNS、VPN 或 Zero Trust 可能将域名解析到内网 IP,导致地址空间被判定为 private 或 unknown,从而触发拦截。

排查与验证步骤

遇到此类报错,可先检查 Network 面板中失败请求解析到的 IP,判断是否落在内网段。若为 iframe 场景,临时添加 allow="local-network-access" 验证;查看站点设置中 LNA 权限是否被阻止;或切换 chrome://flags#local-network-access-check 为 Non-blocking 进行诊断。这些方法仅用于定位,非正式解决方案。

长期方案与短期 workaround

最稳妥的长期方案是通过 API 网关或反向代理将内网服务暴露为公网地址,使浏览器视角为 public→public,避免触发 LNA/PNA。短期可为企业站点配置 LocalNetworkAccessAllowedForUrls 策略,或为 iframe 添加权限。若目标在私网,需在响应头中补充 Access-Control-Allow-Private-Network: true 并确保预检正确。

Q&A

Chrome 中 iframe 加载页面时出现 CORS 错误,提示 'Permission was denied for this request to access the `unknown` address space',是什么原因?

这通常不是传统 CORS 配置问题,而是新版 Chrome 的 Local Network Access (LNA) / Private Network Access (PNA) 策略导致的。当顶层页面通过 iframe 嵌入其他页面,且 iframe 内的资源(如脚本)解析到内网或 unknown 地址空间时,Chrome 会拦截请求,除非 iframe 声明了 allow="local-network-access" 权限。

PNA 和 LNA 有什么区别?

PNA(Private Network Access)是第一阶段方案,基于 CORS 预检,要求从公网访问私网时,请求头带 Access-Control-Request-Private-Network: true,服务端需响应 Access-Control-Allow-Private-Network: true。LNA(Local Network Access)是第二阶段,基于用户权限和站点设置,会弹出权限提示,并支持 Permissions Policy 控制 iframe 权限。

如何解决 iframe 中因 LNA 策略导致的 CORS 错误?

解决方法包括:1) 为 iframe 添加 allow="local-network-access" 属性,多层 iframe 需层层透传;2) 在 Chrome 站点设置中允许该站点的 Local Network Access 权限;3) 通过代理将内网资源映射到公网域名,使浏览器视角为 public 到 public;4) 服务端补充 Access-Control-Allow-Private-Network: true 头(兼容旧实现)。

为什么同一个脚本在顶层页面加载正常,在 iframe 中却报 CORS 错误?

因为 Chrome 的 LNA 策略以顶层站点为身份进行地址空间检查。顶层页面访问时,可能不涉及跨地址空间;但在 iframe 场景下,顶层站点(public)试图通过 iframe 访问内网或 unknown 地址空间,且 iframe 未声明 local-network-access 权限,因此被拦截。

如何快速验证问题是否由 LNA/PNA 导致?

可以按以下步骤验证:1) 在 DevTools Network 中查看失败请求解析到的 IP,判断是否属于内网或 unknown;2) 临时给 iframe 添加 allow="local-network-access" 看是否消除报错;3) 检查站点设置中的 Local Network Access 权限;4) 临时将 chrome://flags#local-network-access-check 设为 Non-blocking 或 Disabled 进行测试。

Chrome 的 LNA 策略从哪个版本开始默认启用?

Chrome 138 引入了 LNA 权限提示的实验 flag,从 Chrome 141/142 开始逐步默认开启权限提示,并对连接本地网络的场景进行拦截。

LNA 策略对 iframe 的权限控制是如何实现的?

LNA 与 Permissions Policy 集成,顶层页面需要在 iframe 标签上声明 allow="local-network-access" 来授权 iframe 访问本地/内网资源。如果有多层嵌套 iframe,需要每一层都透传该权限,否则最内层无法获得权限,相关请求会被拦截。

有哪些长期有效的架构方案可以避免 LNA/PNA 问题?

长期方案是避免公网页面直接访问内网资源,通过 API 网关或反向代理将内网服务暴露为公网域名,使浏览器视角为 public 到 public,从而不触发 LNA/PNA。例如使用 Nginx 将内网 IP 代理到公网域名。

🏷️

标签

➡️

继续阅读