Implementing CORS Securely

Implementing CORS Securely

Node.js/Express Implementation

// Basic CORS implementation
const cors = require('cors');

// Simple CORS for all origins (NOT recommended for production)
app.use(cors());

// Secure CORS configuration
const corsOptions = {
    origin: function (origin, callback) {
        const allowedOrigins = [
            'https://app.example.com',
            'https://dashboard.example.com',
            'https://mobile.example.com'
        ];
        
        // Allow requests with no origin (like mobile apps)
        if (!origin) return callback(null, true);
        
        if (allowedOrigins.indexOf(origin) !== -1) {
            callback(null, true);
        } else {
            callback(new Error('Not allowed by CORS'));
        }
    },
    credentials: true,
    methods: ['GET', 'POST', 'PUT', 'DELETE'],
    allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'],
    exposedHeaders: ['X-Total-Count', 'X-Page-Number'],
    maxAge: 86400 // 24 hours
};

app.use(cors(corsOptions));

// Dynamic CORS based on environment
const dynamicCors = {
    origin: (origin, callback) => {
        // Different rules for different environments
        if (process.env.NODE_ENV === 'development') {
            // More permissive in development
            const devOrigins = [
                'http://localhost:3000',
                'http://localhost:3001',
                'http://127.0.0.1:3000'
            ];
            callback(null, devOrigins.includes(origin));
        } else {
            // Strict in production
            const productionOrigins = [
                'https://app.example.com',
                'https://www.example.com'
            ];
            callback(null, productionOrigins.includes(origin));
        }
    },
    credentials: true
};

// Route-specific CORS
app.get('/api/public', cors({ origin: '*' }), (req, res) => {
    res.json({ message: 'Public API endpoint' });
});

app.get('/api/private', cors(corsOptions), (req, res) => {
    res.json({ message: 'Private API endpoint' });
});

Manual CORS Implementation

// Understanding CORS by implementing it manually
function setCORSHeaders(req, res, next) {
    const origin = req.headers.origin;
    const allowedOrigins = new Set([
        'https://app.example.com',
        'https://trusted-partner.com'
    ]);
    
    // Check if origin is allowed
    if (allowedOrigins.has(origin)) {
        res.setHeader('Access-Control-Allow-Origin', origin);
        res.setHeader('Access-Control-Allow-Credentials', 'true');
    }
    
    // Handle preflight requests
    if (req.method === 'OPTIONS') {
        res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
        res.setHeader('Access-Control-Allow-Headers', 
            'Content-Type, Authorization, X-Requested-With, X-CSRF-Token');
        res.setHeader('Access-Control-Max-Age', '86400');
        res.status(204).end();
        return;
    }
    
    // Expose custom headers
    res.setHeader('Access-Control-Expose-Headers', 
        'X-Total-Count, X-Page-Number, X-RateLimit-Remaining');
    
    next();
}

app.use(setCORSHeaders);