Avoid preflight request by relaxing header req

One of the following headers is required by default:
- Origin: This header is always sent with CORS requests.
- X-Requested-With: This header is automatically added by jQuery on
  same-origin requests.

These two headers effectively disable the ability to use the CORS
proxy for regular browsing.
This commit is contained in:
Rob Wu
2013-08-27 16:06:52 +02:00
parent 6d9b268ecc
commit 61d55ae41e
6 changed files with 31 additions and 13 deletions

View File

@@ -22,9 +22,9 @@ Heroku can be found at https://devcenter.heroku.com/articles/nodejs.
var host = process.env.PORT ? '0.0.0.0' : '127.0.0.1';
var port = process.env.PORT || 8080;
var cors_proxy = require("cors-anywhere");
var cors_proxy = require('cors-anywhere');
cors_proxy.createServer({
requireHeader: 'x-requested-with',
requireHeader: ['origin', 'x-requested-with'],
removeHeaders: ['cookie', 'cookie2']
}).listen(port, host, function() {
console.log('Running CORS Anywhere on ' + host + ':' + port);
@@ -60,8 +60,8 @@ The module exports two properties: `getHandler` and `createServer`.
* `createServer(options)` creates a server with the default handler.
The following options are recognized by both methods:
* string `requireHeader` - If set, the request must include this header or the API will refuse to proxy.
Recommended if you want to prevent users from using the proxy for browsing. Example: `X-Requested-With`
* array of strings `requireHeader` - If set, the request must include this header or the API will refuse to proxy.
Recommended if you want to prevent users from using the proxy for normal browsing. Example: `['Origin', 'X-Requested-With']`.
* array of lowercase strings `removeHeaders` - Exclude certain headers from being included in the request.
Example: `["cookie"]`

View File

@@ -69,7 +69,6 @@ textarea {
function doCORSRequest(options, redirectCount) {
var x = new XMLHttpRequest();
x.open(options.method, cors_api_url + options.url);
x.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
x.onload = function() {
if (x.status === 333) {

View File

@@ -2,7 +2,7 @@
// Released under the MIT license
'use strict';
/* jshint node:true, eqnull:true, sub:true */
/* jshint node:true, eqnull:true, sub:true, quotmark:single */
var httpProxy = require('http-proxy');
var net = require('net');
@@ -113,7 +113,7 @@ function proxyRequest(req, res, proxy, full_url, proxyOptions) {
}
// Called on every request
// Request handler factory
var getHandler = exports.getHandler = function(options) {
var corsAnywhere = {
requireHeader: null, // Require a header to be set?
@@ -126,6 +126,23 @@ var getHandler = exports.getHandler = function(options) {
}
});
}
// Convert corsAnywhere.requireHeader to an array of lowercase header names, or null.
if (corsAnywhere.requireHeader) {
if (typeof corsAnywhere.requireHeader === 'string') {
corsAnywhere.requireHeader = [corsAnywhere.requireHeader];
} else if (!Array.isArray(corsAnywhere.requireHeader) || corsAnywhere.requireHeader.length === 0) {
corsAnywhere.requireHeader = null;
} else {
corsAnywhere.requireHeader = corsAnywhere.requireHeader.map(function(headerName) {
return headerName.toLowerCase();
});
}
}
var hasRequiredHeaders = function(headers) {
return !corsAnywhere.requireHeader || corsAnywhere.requireHeader.some(function(headerName) {
return Object.hasOwnProperty.call(headers, headerName);
});
};
return function(req, res, proxy) {
var cors_headers = withCORS({}, req);
@@ -164,9 +181,9 @@ var getHandler = exports.getHandler = function(options) {
res.writeHead(404, 'Invalid host', cors_headers);
res.end();
return;
} else if (corsAnywhere.requireHeader != null && req.headers[corsAnywhere.requireHeader.toLowerCase()] == null) {
} else if (!hasRequiredHeaders(req.headers)) {
res.writeHead(400, 'Header required', cors_headers);
res.end('Missing ' + corsAnywhere.requireHeader + ' header!');
res.end('Missing required request header. Must specify one of: ' + corsAnywhere.requireHeader);
return;
} else {
full_url = match[0].substr(1);

View File

@@ -20,7 +20,9 @@ the information is available in the status text as "<HTTP STATUS CODE> <LOCATION
The requested URL is available in the X-Request-URL response header. Non-existence of this
header implies that the requested URL was not recognized.
This API has one requirement: The X-Requested-With header must be set.
To prevent the use of the proxy for casual browsing, the API requires either the Origin
or the X-Requested-With header to be set. To avoid unnecessary preflight (OPTIONS) requests,
it's recommended to not manually set these headers in your code.
Demo : https://robwu.nl/cors-anywhere.html

View File

@@ -1,6 +1,6 @@
{
"name": "cors-anywhere",
"version": "0.1.4",
"version": "0.1.5",
"description": "CORS Anywhere is a reverse proxy which adds CORS headers to the proxied request. Request URL is taken from the path",
"license": "MIT",
"author": "Rob Wu <gwnRob@gmail.com>",

View File

@@ -2,9 +2,9 @@
var host = process.env.PORT ? '0.0.0.0' : '127.0.0.1';
var port = process.env.PORT || 8080;
var cors_proxy = require("./lib/cors-anywhere");
var cors_proxy = require('./lib/cors-anywhere');
cors_proxy.createServer({
requireHeader: 'x-requested-with',
requireHeader: ['origin', 'x-requested-with'],
removeHeaders: [
'cookie',
'cookie2',