Panduan komprehensif tentang Cross-Origin Resource Sharing (CORS), mencakup konfigurasi, implikasi keamanan, dan praktik terbaik untuk pengembang.
Cross-Origin Resource Sharing (CORS): Konfigurasi dan Praktik Terbaik Keamanan
Dalam dunia pengembangan web, keamanan adalah hal yang terpenting. Salah satu aspek krusial dari keamanan web adalah mengelola bagaimana halaman web dari satu origin dapat mengakses sumber daya dari origin yang berbeda. Di sinilah Cross-Origin Resource Sharing (CORS) berperan. CORS adalah fitur keamanan browser yang membatasi halaman web untuk membuat permintaan ke domain yang berbeda dari domain yang menyajikan halaman web tersebut. Mekanisme ini ada untuk mencegah situs web jahat mengakses data sensitif. Artikel ini menyediakan panduan komprehensif tentang CORS, yang mencakup konfigurasi, implikasi keamanan, dan praktik terbaiknya.
Memahami Kebijakan Same-Origin
CORS dibangun di atas fondasi Kebijakan Same-Origin, sebuah mekanisme keamanan fundamental yang diimplementasikan oleh browser web. Kebijakan same-origin membatasi halaman web untuk membuat permintaan ke domain yang berbeda dari domain yang menyajikan halaman web tersebut. Dua URL dianggap memiliki origin yang sama jika mereka memiliki protokol (misalnya, HTTP atau HTTPS), host (misalnya, example.com), dan port (misalnya, 80 atau 443) yang sama. Sebagai contoh:
http://example.comdanhttp://example.com/pathadalah origin yang sama.http://example.comdanhttps://example.comadalah origin yang berbeda (protokol berbeda).http://example.comdanhttp://www.example.comadalah origin yang berbeda (host berbeda).http://example.com:80danhttp://example.com:8080adalah origin yang berbeda (port berbeda).
Kebijakan same-origin dirancang untuk mencegah serangan Cross-Site Scripting (XSS), di mana situs web jahat menyuntikkan skrip ke situs web tepercaya untuk mencuri data pengguna atau melakukan tindakan yang tidak sah. Tanpa kebijakan same-origin, situs web jahat berpotensi mengakses informasi rekening bank Anda jika Anda sedang masuk ke portal perbankan online Anda di tab lain.
Apa itu Cross-Origin Resource Sharing (CORS)?
Meskipun kebijakan same-origin sangat penting untuk keamanan, kebijakan ini juga bisa menjadi penghalang dalam skenario yang sah di mana situs web perlu mengakses sumber daya dari origin yang berbeda. Misalnya, aplikasi web yang di-hosting di example.com mungkin perlu mengambil data dari API yang di-hosting di api.example.net. CORS menyediakan mekanisme untuk melewati kebijakan same-origin dengan cara yang terkontrol, memungkinkan halaman web membuat permintaan cross-origin ketika diizinkan secara eksplisit oleh server.
CORS bekerja dengan menambahkan header HTTP ke respons dari server, yang menunjukkan origin mana yang diizinkan untuk mengakses sumber daya. Browser kemudian memeriksa header ini dan memblokir permintaan jika origin halaman web yang membuat permintaan tidak diizinkan.
Cara Kerja CORS: Header HTTP
CORS mengandalkan header HTTP tertentu untuk memfasilitasi permintaan cross-origin. Berikut adalah header-header kunci yang terlibat:
1. Origin (Header Permintaan)
Header Origin dikirim oleh browser dalam permintaan cross-origin. Header ini menunjukkan origin (protokol, host, dan port) dari halaman web yang membuat permintaan. Contohnya:
Origin: http://example.com
2. Access-Control-Allow-Origin (Header Respons)
Header Access-Control-Allow-Origin adalah header terpenting dalam CORS. Header ini menentukan origin mana yang diizinkan untuk mengakses sumber daya. Header ini dapat memiliki salah satu dari nilai berikut:
- Origin spesifik: Misalnya,
Access-Control-Allow-Origin: http://example.comhanya mengizinkan permintaan darihttp://example.com. *(wildcard):Access-Control-Allow-Origin: *mengizinkan permintaan dari origin mana pun. Ini harus digunakan dengan hati-hati, karena secara efektif menonaktifkan kebijakan same-origin untuk sumber daya tersebut.
Contoh:
Access-Control-Allow-Origin: https://www.example.com
3. Access-Control-Allow-Methods (Header Respons)
Header Access-Control-Allow-Methods menentukan metode HTTP (misalnya, GET, POST, PUT, DELETE) yang diizinkan dalam permintaan cross-origin. Ini diperlukan untuk permintaan preflight (dijelaskan di bawah).
Contoh:
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
4. Access-Control-Allow-Headers (Header Respons)
Header Access-Control-Allow-Headers menentukan header HTTP yang diizinkan dalam permintaan cross-origin. Ini juga diperlukan untuk permintaan preflight.
Contoh:
Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With
5. Access-Control-Allow-Credentials (Header Respons)
Header Access-Control-Allow-Credentials menentukan apakah browser harus menyertakan kredensial (misalnya, cookie, header otorisasi) dalam permintaan cross-origin. Header ini dapat memiliki salah satu dari dua nilai: true atau false. Jika true diatur, header Access-Control-Allow-Origin tidak dapat diatur ke *. Itu harus berupa origin spesifik.
Contoh:
Access-Control-Allow-Credentials: true
6. Access-Control-Max-Age (Header Respons)
Header Access-Control-Max-Age menentukan jumlah detik browser dapat menyimpan hasil permintaan preflight dalam cache. Ini dapat meningkatkan kinerja dengan mengurangi jumlah permintaan preflight.
Contoh:
Access-Control-Max-Age: 3600
Permintaan Sederhana vs. Permintaan Preflight
CORS membedakan antara dua jenis permintaan cross-origin: permintaan sederhana dan permintaan preflight.
Permintaan Sederhana
Permintaan sederhana adalah permintaan yang memenuhi kriteria berikut:
- Metodenya adalah
GET,HEAD, atauPOST. - Jika metodenya
POST, headerContent-Typeadalah salah satu dari berikut ini:application/x-www-form-urlencoded,multipart/form-data, atautext/plain. - Permintaan tidak mengatur header kustom apa pun (selain yang diatur secara otomatis oleh browser).
Untuk permintaan sederhana, browser mengirimkan permintaan langsung ke server. Server kemudian merespons dengan header CORS yang sesuai. Jika origin diizinkan, browser memproses respons. Jika tidak, browser memblokir respons dan melemparkan kesalahan.
Permintaan Preflight
Permintaan preflight dikirim oleh browser sebelum membuat permintaan cross-origin yang sebenarnya jika permintaan tersebut tidak memenuhi kriteria permintaan sederhana. Ini biasanya terjadi ketika permintaan menggunakan metode selain GET, HEAD, atau POST, atau ketika permintaan mengatur header kustom.
Permintaan preflight adalah permintaan OPTIONS yang mencakup header-header berikut:
Origin: Origin dari halaman web yang membuat permintaan.Access-Control-Request-Method: Metode HTTP yang akan digunakan dalam permintaan sebenarnya.Access-Control-Request-Headers: Daftar header kustom yang dipisahkan koma yang akan digunakan dalam permintaan sebenarnya.
Server kemudian merespons dengan header-header berikut:
Access-Control-Allow-Origin: Origin yang diizinkan untuk mengakses sumber daya.Access-Control-Allow-Methods: Metode HTTP yang diizinkan dalam permintaan cross-origin.Access-Control-Allow-Headers: Header HTTP yang diizinkan dalam permintaan cross-origin.Access-Control-Max-Age: Jumlah detik browser dapat menyimpan hasil permintaan preflight dalam cache.
Jika server merespons dengan header CORS yang sesuai, browser melanjutkan dengan permintaan cross-origin yang sebenarnya. Jika tidak, browser memblokir permintaan dan melemparkan kesalahan.
Contoh Konfigurasi CORS
Implementasi CORS bervariasi tergantung pada teknologi sisi server yang Anda gunakan. Berikut adalah beberapa contoh untuk bahasa dan kerangka kerja sisi server yang umum:
Node.js dengan Express
Menggunakan middleware cors adalah pendekatan umum untuk mengonfigurasi CORS di Node.js dengan Express:
const express = require('express');
const cors = require('cors');
const app = express();
// Aktifkan CORS untuk semua origin
app.use(cors());
// Aktifkan CORS untuk origin tertentu
// app.use(cors({ origin: 'http://example.com' }));
// Aktifkan CORS dengan opsi
// app.use(cors({
// origin: ['http://example.com', 'http://localhost:3000'],
// methods: ['GET', 'POST', 'PUT', 'DELETE'],
// allowedHeaders: ['Content-Type', 'Authorization'],
// credentials: true
// }));
app.get('/api/data', (req, res) => {
res.json({ message: 'Hello from the API!' });
});
app.listen(3001, () => {
console.log('Server listening on port 3001');
});
Python dengan Flask
Anda dapat menggunakan ekstensi Flask-CORS untuk mengonfigurasi CORS di Flask:
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
# Aktifkan CORS untuk semua origin
CORS(app)
# Aktifkan CORS untuk origin tertentu
# CORS(app, origins=['http://example.com', 'http://localhost:3000'])
@app.route('/api/data')
def get_data():
return {'message': 'Hello from the API!'}
if __name__ == '__main__':
app.run(port=3001)
Java dengan Spring Boot
Spring Boot menyediakan beberapa cara untuk mengonfigurasi CORS. Salah satu pendekatannya adalah menggunakan anotasi @CrossOrigin:
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@CrossOrigin(origins = "http://example.com") // Origin spesifik
public class ApiController {
@GetMapping("/api/data")
public String getData() {
return "Hello from the API!";
}
}
// Konfigurasi CORS Global (menggunakan WebMvcConfigurer):
// @Configuration
// public class CorsConfig implements WebMvcConfigurer {
// @Override
// public void addCorsMappings(CorsRegistry registry) {
// registry.addMapping("/**")
// .allowedOrigins("http://example.com", "http://localhost:3000")
// .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
// .allowedHeaders("Content-Type", "Authorization")
// .allowCredentials(true)
// .maxAge(3600);
// }
// }
PHP
Di PHP, Anda dapat mengatur header CORS langsung di skrip Anda:
<?php
header("Access-Control-Allow-Origin: http://example.com");
header("Content-Type: application/json");
$data = array("message" => "Hello from the API!");
echo json_encode($data);
?>
Pertimbangan Keamanan CORS
Meskipun CORS memungkinkan permintaan cross-origin, sangat penting untuk memahami implikasi keamanan dan mengimplementasikannya dengan benar untuk menghindari kerentanan.
1. Hindari Menggunakan Access-Control-Allow-Origin: * di Produksi
Menggunakan wildcard * di header Access-Control-Allow-Origin memungkinkan permintaan dari origin mana pun, yang secara efektif menonaktifkan kebijakan same-origin untuk sumber daya tersebut. Ini dapat mengekspos API Anda ke situs web jahat yang berpotensi mencuri data pengguna atau melakukan tindakan yang tidak sah. Sebaliknya, tentukan origin yang tepat yang diizinkan untuk mengakses sumber daya. Misalnya, jika aplikasi web Anda di-hosting di example.com dan perlu mengakses API yang di-hosting di api.example.com, atur header ke Access-Control-Allow-Origin: http://example.com.
Contoh global: Bayangkan API layanan keuangan mengatur Access-Control-Allow-Origin: *. Situs web jahat kemudian dapat membuat permintaan ke API ini atas nama pengguna yang sedang masuk, berpotensi mentransfer dana tanpa sepengetahuan pengguna.
2. Validasi Header Origin di Server
Bahkan jika Anda menentukan daftar origin yang diizinkan, penting untuk memvalidasi header Origin di server untuk mencegah penyerang memalsukan origin. Penyerang berpotensi mengirim permintaan dengan header Origin palsu untuk melewati pemeriksaan CORS. Untuk memitigasi ini, bandingkan header Origin dengan daftar origin tepercaya di sisi server. Jika origin tidak ada dalam daftar, tolak permintaan.
Contoh global: Pertimbangkan platform e-commerce. Penyerang dapat mencoba meniru Origin etalase yang sah untuk mengakses data pelanggan sensitif dari API platform e-commerce.
3. Hati-hati dengan Access-Control-Allow-Credentials: true
Jika Anda mengatur Access-Control-Allow-Credentials: true, header Access-Control-Allow-Origin tidak dapat diatur ke *. Itu harus berupa origin spesifik. Ini karena mengizinkan kredensial dari origin mana pun dapat menciptakan risiko keamanan, karena dapat memungkinkan situs web jahat mengakses data pengguna jika mereka dapat menipu pengguna untuk mengunjungi situs mereka saat pengguna juga masuk ke situs web target. Pengaturan ini penting saat berhadapan dengan cookie atau header otorisasi.
Contoh global: Platform media sosial yang mengizinkan permintaan cross-origin dengan kredensial memerlukan manajemen yang cermat untuk mencegah akses tidak sah ke akun pengguna.
4. Konfigurasi Access-Control-Allow-Methods dan Access-Control-Allow-Headers dengan Benar
Hanya izinkan metode dan header HTTP yang diperlukan untuk permintaan cross-origin. Jika Anda hanya perlu mengizinkan permintaan GET dan POST, jangan izinkan PUT, DELETE, atau metode lain. Demikian pula, hanya izinkan header spesifik yang dibutuhkan aplikasi Anda. Konfigurasi yang terlalu permisif dapat meningkatkan risiko serangan.
Contoh Global: Sistem CRM hanya boleh mengekspos endpoint API dan header yang diperlukan untuk integrasi pihak ketiga yang berwenang, untuk meminimalkan permukaan serangan.
5. Gunakan HTTPS untuk Komunikasi Aman
Selalu gunakan HTTPS untuk komunikasi yang aman antara browser dan server. HTTPS mengenkripsi data yang ditransmisikan antara browser dan server, mencegah penyadapan dan serangan man-in-the-middle. Menggunakan HTTP dapat mengekspos data sensitif kepada penyerang, bahkan jika CORS dikonfigurasi dengan benar.
Contoh Global: Aplikasi perawatan kesehatan harus menggunakan HTTPS untuk melindungi data pasien yang dikirimkan ke berbagai origin.
6. Content Security Policy (CSP)
Meskipun tidak terkait langsung dengan CORS, Content Security Policy (CSP) adalah mekanisme keamanan penting lainnya yang dapat membantu mencegah serangan XSS. CSP memungkinkan Anda untuk menentukan daftar putih sumber dari mana browser diizinkan untuk memuat sumber daya. Ini dapat membantu mencegah penyerang menyuntikkan skrip jahat ke situs web Anda, bahkan jika mereka berhasil melewati langkah-langkah keamanan lainnya.
Contoh global: Lembaga keuangan sering menerapkan kebijakan CSP yang ketat untuk membatasi sumber konten yang dimuat ke portal perbankan online mereka, mengurangi risiko serangan XSS.
Masalah Umum CORS dan Pemecahan Masalah
Kesalahan CORS bisa membuat frustrasi saat melakukan debug. Berikut adalah beberapa masalah umum dan cara mengatasinya:
1. "No 'Access-Control-Allow-Origin' header is present on the requested resource."
Ini adalah kesalahan CORS yang paling umum. Ini menunjukkan bahwa server tidak mengembalikan header Access-Control-Allow-Origin dalam responsnya. Pastikan server dikonfigurasi untuk mengirim header CORS yang benar untuk origin halaman web yang membuat permintaan. Periksa kembali kode sisi server dan file konfigurasi Anda.
2. "Response to preflight request doesn't pass access control check: It does not have HTTP ok status."
Kesalahan ini menunjukkan bahwa permintaan preflight gagal. Ini bisa terjadi jika server tidak merespons permintaan OPTIONS atau jika server mengembalikan kode status kesalahan (misalnya, 404, 500) sebagai respons terhadap permintaan preflight. Pastikan server Anda dikonfigurasi untuk menangani permintaan OPTIONS dan mengembalikan kode status 200 OK.
3. "Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'."
Kesalahan ini terjadi ketika Anda mencoba mengirim kredensial (misalnya, cookie) dalam permintaan cross-origin dan header Access-Control-Allow-Origin diatur ke *. Seperti yang disebutkan sebelumnya, Anda tidak dapat menggunakan wildcard * saat mengirim kredensial. Anda harus menentukan origin yang tepat yang diizinkan untuk mengakses sumber daya.
4. Caching Browser
Browser dapat menyimpan respons CORS dalam cache, yang dapat menyebabkan perilaku tak terduga jika konfigurasi CORS berubah. Untuk mencegah masalah caching, atur header Cache-Control dalam respons ke no-cache, no-store, atau max-age=0. Anda juga dapat menggunakan header Access-Control-Max-Age untuk mengontrol berapa lama browser menyimpan hasil permintaan preflight dalam cache.
Alternatif untuk CORS
Meskipun CORS adalah cara standar untuk mengaktifkan permintaan cross-origin, ada beberapa alternatif yang dapat Anda pertimbangkan dalam skenario tertentu:
1. JSON with Padding (JSONP)
JSONP adalah teknik yang menggunakan tag <script> untuk melewati kebijakan same-origin. JSONP bekerja dengan membungkus data JSON dalam pemanggilan fungsi JavaScript. Browser kemudian mengeksekusi fungsi JavaScript, meneruskan data JSON sebagai argumen. JSONP lebih sederhana untuk diimplementasikan daripada CORS, tetapi memiliki beberapa keterbatasan. Ini hanya mendukung permintaan GET, dan kurang aman dibandingkan CORS.
2. Reverse Proxy
Reverse proxy adalah server yang berada di depan server API Anda dan meneruskan permintaan kepadanya. Reverse proxy dapat dikonfigurasi untuk menambahkan header CORS yang diperlukan ke respons, secara efektif menyembunyikan permintaan cross-origin dari browser. Pendekatan ini bisa berguna jika Anda tidak memiliki kendali atas server API atau jika Anda ingin menyederhanakan konfigurasi CORS.
Kesimpulan
Cross-Origin Resource Sharing (CORS) adalah mekanisme keamanan krusial yang memungkinkan halaman web mengakses sumber daya dari origin yang berbeda dengan cara yang terkontrol. Memahami cara kerja CORS dan mengimplementasikannya dengan benar sangat penting untuk membangun aplikasi web yang aman dan andal. Dengan mengikuti praktik terbaik yang diuraikan dalam artikel ini, Anda dapat mengelola CORS secara efektif dan melindungi API Anda dari akses yang tidak sah.
Ingatlah untuk selalu memprioritaskan keamanan saat mengonfigurasi CORS. Hindari menggunakan wildcard, validasi header Origin, dan gunakan HTTPS untuk komunikasi yang aman. Dengan mengambil tindakan pencegahan ini, Anda dapat memastikan bahwa aplikasi web Anda terlindungi dari serangan lintas situs.
Panduan komprehensif ini memberikan dasar yang kuat untuk memahami CORS. Selalu merujuk pada dokumentasi resmi untuk teknologi sisi server spesifik Anda untuk informasi terbaru dan praktik terbaik. Tetap terinformasi tentang ancaman keamanan yang muncul dan sesuaikan konfigurasi CORS Anda.