Memahami CORS Secara Mendalam
CORS (Cross-Origin Resource Sharing) adalah mekanisme browser yang mengontrol akses resource dari origin yang berbeda. Salah konfigurasi CORS adalah sumber vulnerability yang umum.
Apa itu Origin?
// Origin = scheme + host + port
https://example.com:443 // Origin 1
http://example.com:80 // Origin 2 (beda scheme)
https://api.example.com // Origin 3 (beda subdomain)
https://example.com:8080 // Origin 4 (beda port)
Same-Origin Policy
Browser secara default memblokir request JavaScript ke origin yang berbeda. CORS adalah cara untuk melonggarkan aturan ini secara terkontrol.
Preflight Request
Untuk request yang "kompleks" (non-GET, custom headers, dll.), browser mengirim OPTIONS request terlebih dahulu:
// 1. Browser kirim preflight
OPTIONS /api/data HTTP/1.1
Origin: https://frontend.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type, Authorization
// 2. Server merespons
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://frontend.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400 // Cache preflight 24 jam
// 3. Jika diizinkan, browser mengirim request asli
Konfigurasi CORS yang Aman
// Express.js
const cors = require("cors");
app.use(cors({
origin: ["https://myapp.com", "https://admin.myapp.com"],
methods: ["GET", "POST", "PUT", "DELETE"],
allowedHeaders: ["Content-Type", "Authorization"],
credentials: true, // Izinkan cookie cross-origin
maxAge: 86400
}));
// Laravel (config/cors.php)
return [
"paths" => ["api/*"],
"allowed_origins" => ["https://myapp.com"],
"allowed_methods" => ["GET", "POST", "PUT", "DELETE"],
"allowed_headers" => ["Content-Type", "Authorization"],
"supports_credentials" => true,
"max_age" => 86400,
];
Kesalahan CORS yang Berbahaya
1. Wildcard dengan Credentials
// TIDAK VALID: browser akan menolak
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
// Tidak bisa menggabungkan wildcard dengan credentials!
2. Reflect Origin Tanpa Validasi
// BURUK: merefleksikan origin apa pun
res.setHeader("Access-Control-Allow-Origin", req.headers.origin);
// Ini sama saja dengan wildcard, tapi bypass restricsi credentials!
// BAIK: validasi terhadap whitelist
const allowed = ["https://myapp.com"];
if (allowed.includes(req.headers.origin)) {
res.setHeader("Access-Control-Allow-Origin", req.headers.origin);
}
Best Practices
- Gunakan whitelist origin yang spesifik, bukan wildcard
- Batasi methods hanya yang diperlukan
- Batasi headers hanya yang diperlukan
- Set Max-Age untuk mengurangi preflight requests
- Hati-hati dengan credentials: true — pastikan origin divalidasi