Skip to content

跨域考——论浏览器的城门与狗洞

一、引子:这画地为牢的盛世

未庄的城门寅时开,戌时闭,守城的兵丁举着同源策略的令箭,将HTTP请求当细作盘查。这浏览器里的规矩,倒比赵太爷家的门禁还要森严三分。本是同根生的脚本,偏要分出三六九等——协议、域名、端口差上半分,便成异端。

二、同源礼教吃人录

1. XMLHttpRequest 的镣铐

const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://邻村账房/api');
xhr.send(); // 触发城门卫兵的呵斥

这ajax的马车分明载的是正经货物,却因路引不全被拦在城门外。控制台的报错红字,倒像是衙门口张贴的缉拿告示。

2. Fetch API 的新枷锁

fetch('https://当铺/v1/典当')
.then(res => res.json())
.catch(err => console.error('吃了闭门羹'));

虽换了新式的马车,守城的规矩仍是光绪年间的旧制。CORS错误如同未庄茶馆的茶钱——躲不过,绕不开。

三、越狱者的十八般武艺

1. JSONP 的狗洞

function 收赃(赃物) { console.log(赃物); }
const script = document.createElement('script');
script.src = 'https://黑市?callback=收赃';
document.body.appendChild(script); // 钻过城墙排水沟

这旁门左道的手段,活脱脱是阿Q翻墙偷萝卜的做派。虽解得一时之急,却把身家性命全系在回调函数上,比赵家的借据还要危险。

2. CORS 的通行令

// 邻村账房的响应头
Access-Control-Allow-Origin: https://未庄钱庄
Access-Control-Allow-Methods: GET,PUT
Access-Control-Allow-Headers: Content-Type

像是衙门颁发的通关文牒,盖着大红印章。预检请求(Preflight)的流程,比七品知县升堂还要繁琐:

OPTIONS /api HTTP/1.1
Origin: https://未庄钱庄
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Secret-Key

3. 代理服务器的掮客

// 自家后院搭桥
app.use('/proxy', createProxyMiddleware({
target: 'https://禁地',
changeOrigin: true, // 偷梁换柱
pathRewrite: {'^/proxy': ''}
}));

这等中间人勾当,像极了未庄的说合人。表面是帮两家牵线,背地里可能把消息篡改得面目全非,比单四嫂子遇到的庸医还可恨。

四、江湖偏方现形记

1. document.domain 的旧桥

// 主站:https://未庄.gov
document.domain = '未庄.gov';
// 子站:https://茶馆.未庄.gov
document.domain = '未庄.gov'; // 强认亲戚

这自欺欺人的把戏,活似赵白眼硬攀赵太爷做本家。且不说只限同主域名,单是这设置后的安全隐患,就比阿Q睡的土谷祠还要漏风。

2. postMessage 的飞鸽传书

// 钱庄窗口
iframe.contentWindow.postMessage(密信, 'https://当铺');
// 当铺窗口
window.addEventListener('message', (e) => {
if (e.origin !== 'https://钱庄') return;
console.log(e.data);
});

虽比鸿雁传书可靠,却要双方对暗号。稍有不慎便成孔乙己分茴香豆——消息被各路闲汉劫了去。

3. WebSocket 的暗道

const ws = new WebSocket('wss://黑市通道');
ws.onmessage = (e) => console.log(e.data); // 绕过城门守卫

这长连接的密道,倒像是革命党用的电报。虽不受同源所限,却要另开线路,维护成本比维持赵家的祠堂还要费银钱。

五、安全与便利的浮世绘

1. CSRF 的借刀杀人

<img src="https://钱庄/转账?to=假洋鬼子&amount=1000">

同源策略防住了明枪,却躲不过暗箭。这CSRF的攻击,活脱是未庄茶馆里的蒙汗药——借你的手,办他的事。

2. CORS 配置的七出之条

Access-Control-Allow-Origin: * // 如同敞开城门迎流寇

为图省事设了星号,好比把赵太爷家的库房钥匙挂在城门上。等到被XSS攻破时,倒比小D偷了宁式床还要狼狈。

六、结语:这破不了的轮回

跨域之争,恰似未庄的改良运动。旧派要守城门,新派要开民智,中间派忙着搭桥钻洞。TypeScript 的类型守卫防得了明处的错,却拦不住暗处的劫。

今人用 GraphQL 扮作新式学堂,用 BFF 充当前哨驿站,终不过是给旧城墙刷层新漆。待到 WebAssembly 大军压境时,这同源的城墙怕是要比未庄的土墙崩塌得更快。

月光照在控制台的报错上,我仿佛看见无数 404 在跳舞。这浏览器的城门啊,既护不住周全,又拦不住人心。呜呼!我说不出话,只听得夜风里传来 fetch 的悲鸣,一声声喊着:

“预检请求… 预检请求…”