middleware cors

CORS es un middleware de Node.js para Express/Connect que establece los encabezados de respuesta CORS. Estos encabezados indican a los navegadores qué orígenes pueden leer las respuestas de tu servidor.

Nota

Cómo funciona CORS: Este paquete establece encabezados de respuesta, no bloquea peticiones. CORS es aplicado por los navegadores: revisan los encabezados y deciden si JavaScript puede leer la respuesta. Los clientes que no son navegadores (curl, Postman, otros servidores) ignoran CORS por completo. Consulta la guía de CORS de MDN para más detalles.

Instalación

Este es un módulo de Node.js disponible a través del registro npm. La instalación se hace usando el comando npm install:

Ventana de terminal
npm install cors

Uso

Uso simple (Habilitar todas las peticiones CORS)

var express = require('express');
var cors = require('cors');
var app = express();
// Adds headers: Access-Control-Allow-Origin: *
app.use(cors());
app.get('/products/:id', function (req, res, next) {
res.json({ msg: 'Hello' });
});
app.listen(80, function () {
console.log('web server listening on port 80');
});

Habilitar CORS para una sola ruta

var express = require('express');
var cors = require('cors');
var app = express();
// Adds headers: Access-Control-Allow-Origin: *
app.get('/products/:id', cors(), function (req, res, next) {
res.json({ msg: 'Hello' });
});
app.listen(80, function () {
console.log('web server listening on port 80');
});

Configurar CORS

Consulta las opciones de configuración para más detalles.

var express = require('express');
var cors = require('cors');
var app = express();
var corsOptions = {
origin: 'http://example.com',
optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204
};
// Adds headers: Access-Control-Allow-Origin: http://example.com, Vary: Origin
app.get('/products/:id', cors(corsOptions), function (req, res, next) {
res.json({ msg: 'Hello' });
});
app.listen(80, function () {
console.log('web server listening on port 80');
});

Configurar CORS con origen dinámico

Este módulo soporta la validación del origen dinámicamente usando una función proporcionada a la opción origin. A esta función se le pasará una cadena que es el origen (o undefined si la petición no tiene origen), y un callback con la firma callback(error, origin).

El argumento origin del callback puede ser cualquier valor permitido para la opción origin del middleware, excepto una función. Consulta la sección de opciones de configuración para más información sobre todos los tipos de valores posibles.

Esta función está diseñada para permitir la carga dinámica de los orígenes permitidos desde una fuente de datos de respaldo, como una base de datos.

var express = require('express');
var cors = require('cors');
var app = express();
var corsOptions = {
origin: function (origin, callback) {
// db.loadOrigins is an example call to load
// a list of origins from a backing database
db.loadOrigins(function (error, origins) {
callback(error, origins);
});
},
};
// Adds headers: Access-Control-Allow-Origin: <matched origin>, Vary: Origin
app.get('/products/:id', cors(corsOptions), function (req, res, next) {
res.json({ msg: 'Hello' });
});
app.listen(80, function () {
console.log('web server listening on port 80');
});

Habilitar pre-flight de CORS

Ciertas peticiones CORS se consideran ‘complejas’ y requieren una petición inicial OPTIONS (llamada “petición pre-flight”). Un ejemplo de una petición CORS ‘compleja’ es una que usa un verbo HTTP distinto a GET/HEAD/POST (como DELETE) o que usa encabezados personalizados. Para habilitar el pre-flight, debes añadir un nuevo manejador OPTIONS para la ruta que quieres soportar:

var express = require('express');
var cors = require('cors');
var app = express();
app.options('/products/:id', cors()); // preflight for DELETE
app.delete('/products/:id', cors(), function (req, res, next) {
res.json({ msg: 'Hello' });
});
app.listen(80, function () {
console.log('web server listening on port 80');
});

También puedes habilitar el pre-flight de forma global así:

app.options('*', cors()); // include before other routes

NOTA: Cuando se usa este middleware como middleware a nivel de aplicación (por ejemplo, app.use(cors())), las peticiones pre-flight ya se manejan para todas las rutas.

Personalizar la configuración CORS dinámicamente por petición

Para APIs que requieren diferentes configuraciones CORS para rutas o peticiones específicas, puedes generar dinámicamente las opciones CORS basándote en la petición entrante. El middleware cors te permite lograr esto pasando una función en lugar de opciones estáticas. Esta función se llama para cada petición entrante y debe usar el patrón callback para devolver las opciones CORS apropiadas.

La función acepta:

  1. req:

    • El objeto de petición entrante.
  2. callback(error, corsOptions):

    • Una función usada para devolver las opciones CORS calculadas.
    • Arguments:
      • error: Pasa null si no hay error, o un objeto de error para indicar un fallo.
      • corsOptions: Un objeto que especifica la política CORS para la petición actual.

Aquí hay un ejemplo que maneja tanto rutas públicas como rutas restringidas sensibles a credenciales:

var dynamicCorsOptions = function (req, callback) {
var corsOptions;
if (req.path.startsWith('/auth/connect/')) {
// Access-Control-Allow-Origin: http://mydomain.com, Access-Control-Allow-Credentials: true, Vary: Origin
corsOptions = {
origin: 'http://mydomain.com',
credentials: true,
};
} else {
// Access-Control-Allow-Origin: *
corsOptions = { origin: '*' };
}
callback(null, corsOptions);
};
app.use(cors(dynamicCorsOptions));
app.get('/auth/connect/twitter', function (req, res) {
res.send('Hello');
});
app.get('/public', function (req, res) {
res.send('Hello');
});
app.listen(80, function () {
console.log('web server listening on port 80');
});

Opciones de configuración

  • origin: Configures the Access-Control-Allow-Origin CORS header. Possible values:
    • Boolean - establece origin como true para reflejar el origen de la petición, definido por req.header('Origin'), o establécelo como false para deshabilitar CORS.
    • String - set origin to a specific origin. For example, if you set it to
      • "http://example.com" solo se permitirán las peticiones de “http://example.com”.
      • "*" para permitir todos los dominios.
    • RegExp - establece origin como un patrón de expresión regular que se usará para probar el origen de la petición. Si coincide, se reflejará el origen de la petición. Por ejemplo, el patrón /example\.com$/ reflejará cualquier petición que venga de un origen que termine con “example.com”.
    • Array - establece origin como un array de orígenes válidos. Cada origen puede ser un String o un RegExp. Por ejemplo, ["http://example1.com", /\.example2\.com$/] aceptará cualquier petición de “http://example1.com” o de un subdominio de “example2.com”.
    • Function - establece origin como una función que implementa alguna lógica personalizada. La función toma el origen de la petición como primer parámetro y un callback (llamado como callback(err, origin), donde origin es un valor que no es función de la opción origin) como segundo.
  • methods: Configura el encabezado CORS Access-Control-Allow-Methods. Espera una cadena delimitada por comas (ej: ‘GET,PUT,POST’) o un array (ej: ['GET', 'PUT', 'POST']).
  • allowedHeaders: Configura el encabezado CORS Access-Control-Allow-Headers. Espera una cadena delimitada por comas (ej: ‘Content-Type,Authorization’) o un array (ej: ['Content-Type', 'Authorization']). Si no se especifica, por defecto refleja los encabezados especificados en el encabezado Access-Control-Request-Headers de la petición.
  • exposedHeaders: Configura el encabezado CORS Access-Control-Expose-Headers. Espera una cadena delimitada por comas (ej: ‘Content-Range,X-Content-Range’) o un array (ej: ['Content-Range', 'X-Content-Range']). Si no se especifica, no se exponen encabezados personalizados.
  • credentials: Configura el encabezado CORS Access-Control-Allow-Credentials. Establece como true para pasar el encabezado, de lo contrario se omite.
  • maxAge: Configura el encabezado CORS Access-Control-Max-Age. Establece como un entero para pasar el encabezado, de lo contrario se omite.
  • preflightContinue: Pasa la respuesta preflight de CORS al siguiente manejador.
  • optionsSuccessStatus: Proporciona un código de estado a usar para peticiones OPTIONS exitosas, ya que algunos navegadores antiguos (IE11, varios SmartTVs) tienen problemas con 204.

La configuración por defecto es equivalente a:

{
"origin": "*",
"methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
"preflightContinue": false,
"optionsSuccessStatus": 204
}

Conceptos erróneos comunes

”CORS bloquea las peticiones de orígenes no permitidos”

No. Tu servidor recibe y procesa cada petición. Los encabezados CORS le indican al navegador si JavaScript puede leer la respuesta, no si la petición está permitida.

”CORS protege mi API de accesos no autorizados”

No. CORS no es control de acceso. Cualquier cliente HTTP (curl, Postman, otro servidor) puede llamar a tu API independientemente de la configuración CORS. Usa autenticación y autorización para proteger tu API.

”Establecer origin: 'http://example.com' significa que solo ese dominio puede acceder a mi servidor”

No. Significa que los navegadores solo permitirán que JavaScript de ese origen lea las respuestas. El servidor sigue respondiendo a todas las peticiones.

Licencia

Licencia MIT

Autor original

Troy Goode (troygoode@gmail.com)