背景与价值PNA(Private Network Access)为访问私有网络资源引入预检与策略。合理治理可减少浏览器跨网段访问带来的风险。统一规范仅在来源白名单与安全协议下允许私网访问。预检响应按需设置 `Access-Control-Allow-Private-Network: true`。网段判定:阻断对不受控私网段的访问。核心实现CIDR判定与来源白名单function ipv4ToInt(ip: string): number { const m = ip.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/); if (!m) return -1; const n = m.slice(1).map(Number); for (const x of n) if (x<0||x>255) return -1; return ((n[0]<<24)>>>0)+(n[1]<<16)+(n[2]<<8)+n[3] } function inCidr(ip: string, cidr: string): boolean { const [b,p] = cidr.split('/'); const base = ipv4ToInt(b); const mask = (~0 << (32-Number(p)))>>>0; const v = ipv4ToInt(ip); if (base<0||v<0) return false; return (v & mask) === (base & mask) } const privateCidrs = ['10.0.0.0/8','172.16.0.0/12','192.168.0.0/16'] const allowOrigins = new Set(['https://app.example.com']) function originAllowed(o: string | undefined): boolean { if (!o) return false; try { const u = new URL(o); return allowOrigins.has(u.origin) } catch { return false } } PNA预检处理type Req = { method: string; headers: Record<string, string | undefined>; targetIp?: string } type Res = { setHeader: (k: string, v: string) => void; status: (n: number) => Res; end: (b?: string) => void } function isPrivate(ip: string | undefined): boolean { if (!ip) return false; for (const c of privateCidrs) if (inCidr(ip, c)) return true; return false } function handlePnaPreflight(req: Req, res: Res): boolean { const isOptions = req.method.toUpperCase() === 'OPTIONS' const wantPna = (req.headers['access-control-request-private-network'] || '').toLowerCase() === 'true' const origin = req.headers['origin'] if (!isOptions || !wantPna || !originAllowed(origin)) return false if (!isPrivate(req.targetIp)) return false res.setHeader('Access-Control-Allow-Origin', origin!) res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS') res.setHeader('Access-Control-Allow-Headers', 'Content-Type') res.setHeader('Access-Control-Allow-Private-Network', 'true') res.setHeader('Access-Control-Max-Age', '600') res.end() return true } 落地建议仅在来源白名单与私网目标场景下允许PNA预检,并设置最大600秒缓存。对目标IP进行网段判定,阻断不受控私网访问;审计所有PNA请求。验证清单预检是否命中 `Access-Control-Request-Private-Network: true`;是否按白名单与私网判定设置响应。

发表评论 取消回复