CORS 和网络扩展
CORS and web extensions
我在 http://localhost:8080 where http://example.com 上设置了一个服务器,可以执行 POST 个请求:
'use strict';
const express = require('express');
const app = express();
const port = 8080;
// allowing CORS for example.com
app.use('/', function (req, res, next) {
res.header('Access-Control-Allow-Origin', 'http://example.com');
if (req.method === 'OPTIONS') {
res.header('Access-Control-Allow-Methods', 'OPTIONS, POST');
res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length');
res.status(200).send();
} else {
next();
}
});
// handling POST requests
app.use('/', function (req, res) {
console.log('a client did a POST request');
res.status(200);
});
app.listen(port, () => console.log ('server started on port ' + port));
工作正常:由于同源策略,我无法向 http://localhost:8080 from http://localhost:8081 发出 POST 请求。
然后我为 Firefox 编写了一个 Web 扩展,它将尝试从任何域向 http://localhost:8080 发出 POST 请求。
这是它的清单:
{
"manifest_version" : 2,
"name" : "aBasicExtension",
"version" : "0.0.0",
"content_scripts" : [
{
"matches" : ["<all_urls>"],
"js" : ["content-script.js"]
}
],
"permissions" : ["*://*.localhost/*"]
}
及其content-script.js
代码:
(() => {
'use strict';
const xhr = new XMLHttpRequest();
xhr.open('POST', 'http://localhost:8080');
xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
xhr.addEventListener('readystatechange', () => {
if (xhr.readyState === XMLHttpRequest.DONE){
if (xhr.status === 200) console.log('OK');
else console.error('an error has occured : ' + xhr.status);
}
});
xhr.send(JSON.stringify({dataName: 'some data here'}));
})();
我不明白的是它有效。扩展程序向 http://localhost:8080 发出请求并且 Firefox 没有阻止它,因为清单允许它,但是服务器 (http://locahost:8080) 没有同意。
简短版本:CORS 是一种用于控制浏览器而非服务器行为的协议。并且您使用插件 permissions
设置绕过了同源策略和对 CORS 的需求。
如果您查看 CORS 代码,您会发现它不会执行任何拒绝请求的操作;它只是在响应中设置 headers 。那些 headers 将指示浏览器客户端是否可以读取响应,但无论如何都会发送响应。
这一事实可能会被某些强制执行 CORS 预检的请求所掩盖。在那种情况下,浏览器首先发送一个特殊的 OPTIONS
请求,并且附加到该响应的 headers 可以阻止浏览器发送真正的请求。这是一种 backwards-compatibility 机制,并不适用于所有请求。 (有关详细说明,请参阅 this answer。)
这就是您的示例中发生的情况。您的 POST
属于需要在 CORS 下进行预检的类型。所以在常规版本中,浏览器发送预检,看到响应headers,而不会发送真正的请求。但如果它是另一种 POST 它会直接发送请求,服务器会执行它。
在插件版本中,您在 permissions
设置中明确允许该域。这个bypasses the Same Origin Policy:
The extra privileges include: XMLHttpRequest and fetch access to those origins without cross-origin restrictions (even for requests made from content scripts).
所以在这种情况下不需要预检,直接发送请求。
如果你想拒绝服务器上来自特定域的请求(或更普遍地防止 CSRF),还有其他设置。它们是什么取决于您的网络框架。
我在 http://localhost:8080 where http://example.com 上设置了一个服务器,可以执行 POST 个请求:
'use strict';
const express = require('express');
const app = express();
const port = 8080;
// allowing CORS for example.com
app.use('/', function (req, res, next) {
res.header('Access-Control-Allow-Origin', 'http://example.com');
if (req.method === 'OPTIONS') {
res.header('Access-Control-Allow-Methods', 'OPTIONS, POST');
res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length');
res.status(200).send();
} else {
next();
}
});
// handling POST requests
app.use('/', function (req, res) {
console.log('a client did a POST request');
res.status(200);
});
app.listen(port, () => console.log ('server started on port ' + port));
工作正常:由于同源策略,我无法向 http://localhost:8080 from http://localhost:8081 发出 POST 请求。
然后我为 Firefox 编写了一个 Web 扩展,它将尝试从任何域向 http://localhost:8080 发出 POST 请求。
这是它的清单:
{
"manifest_version" : 2,
"name" : "aBasicExtension",
"version" : "0.0.0",
"content_scripts" : [
{
"matches" : ["<all_urls>"],
"js" : ["content-script.js"]
}
],
"permissions" : ["*://*.localhost/*"]
}
及其content-script.js
代码:
(() => {
'use strict';
const xhr = new XMLHttpRequest();
xhr.open('POST', 'http://localhost:8080');
xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
xhr.addEventListener('readystatechange', () => {
if (xhr.readyState === XMLHttpRequest.DONE){
if (xhr.status === 200) console.log('OK');
else console.error('an error has occured : ' + xhr.status);
}
});
xhr.send(JSON.stringify({dataName: 'some data here'}));
})();
我不明白的是它有效。扩展程序向 http://localhost:8080 发出请求并且 Firefox 没有阻止它,因为清单允许它,但是服务器 (http://locahost:8080) 没有同意。
简短版本:CORS 是一种用于控制浏览器而非服务器行为的协议。并且您使用插件 permissions
设置绕过了同源策略和对 CORS 的需求。
如果您查看 CORS 代码,您会发现它不会执行任何拒绝请求的操作;它只是在响应中设置 headers 。那些 headers 将指示浏览器客户端是否可以读取响应,但无论如何都会发送响应。
这一事实可能会被某些强制执行 CORS 预检的请求所掩盖。在那种情况下,浏览器首先发送一个特殊的 OPTIONS
请求,并且附加到该响应的 headers 可以阻止浏览器发送真正的请求。这是一种 backwards-compatibility 机制,并不适用于所有请求。 (有关详细说明,请参阅 this answer。)
这就是您的示例中发生的情况。您的 POST
属于需要在 CORS 下进行预检的类型。所以在常规版本中,浏览器发送预检,看到响应headers,而不会发送真正的请求。但如果它是另一种 POST 它会直接发送请求,服务器会执行它。
在插件版本中,您在 permissions
设置中明确允许该域。这个bypasses the Same Origin Policy:
The extra privileges include: XMLHttpRequest and fetch access to those origins without cross-origin restrictions (even for requests made from content scripts).
所以在这种情况下不需要预检,直接发送请求。
如果你想拒绝服务器上来自特定域的请求(或更普遍地防止 CSRF),还有其他设置。它们是什么取决于您的网络框架。