Kami mengungkap API yang hanya dapat digunakan mitra di domain yang mereka daftarkan dengan kami. Isinya sebagian untuk publik (tetapi sebaiknya hanya ditampilkan di domain yang kami ketahui), tetapi sebagian besar bersifat pribadi bagi pengguna kami. Begitu:
Untuk menentukan apa yang ditampilkan, pengguna kami harus masuk dengan kami, tetapi ini ditangani secara terpisah.
Untuk menentukan di mana data ditampilkan, kunci API publik digunakan untuk membatasi akses ke domain yang kita ketahui, dan yang terpenting untuk memastikan data pengguna pribadi tidak rentan terhadap CSRF .
Kunci API ini memang terlihat oleh siapa pun, kami tidak mengautentikasi mitra kami dengan cara lain, dan kami tidak memerlukan REFERER . Tetap saja, ini aman:
Saat kami get-csrf-token.js?apiKey=abc123
diminta:
Cari kunci abc123
di database dan dapatkan daftar domain yang valid untuk kunci itu.
Cari cookie validasi CSRF. Jika tidak ada, buat nilai acak yang aman dan masukkan ke dalam cookie sesi khusus HTTP . Jika cookie memang ada, dapatkan nilai acak yang ada.
Buat token CSRF dari kunci API dan nilai acak dari cookie, dan tanda tangani . (Daripada menyimpan daftar token di server, kami menandatangani nilainya. Kedua nilai akan dapat dibaca dalam token yang ditandatangani, itu bagus.)
Setel tanggapan agar tidak di-cache, tambahkan cookie, dan kembalikan skrip seperti:
var apiConfig = apiConfig || {};
if(document.domain === 'expected-domain.com'
|| document.domain === 'www.expected-domain.com') {
apiConfig.csrfToken = 'API key, random value, signature';
// Invoke a callback if the partner wants us to
if(typeof apiConfig.fnInit !== 'undefined') {
apiConfig.fnInit();
}
} else {
alert('This site is not authorised for this API key.');
}
Catatan:
Hal di atas tidak mencegah skrip sisi server memalsukan permintaan, tetapi hanya memastikan bahwa domain tersebut cocok jika diminta oleh browser.
The kebijakan asal yang sama untuk JavaScript memastikan bahwa browser tidak dapat menggunakan XHR (Ajax) untuk memuat dan kemudian memeriksa sumber JavaScript. Sebaliknya, browser biasa hanya dapat memuatnya menggunakan <script src="https://our-api.com/get-csrf-token.js?apiKey=abc123">
(atau yang setara dinamis), dan kemudian akan menjalankan kode tersebut. Tentu saja, server Anda tidak boleh mendukung Cross-Origin Resource Sharing atau JSONP untuk JavaScript yang dihasilkan.
Sebuah skrip browser dapat mengubah nilai document.domain
sebelum memuat skrip di atas. Tetapi kebijakan asal yang sama hanya memungkinkan untuk memperpendek domain dengan menghapus prefiks, seperti menulis ulang subdomain.example.com
ke hanya example.com
, atau myblog.wordpress.com
ke wordpress.com
, atau di beberapa browser bahkan bbc.co.uk
ke co.uk
.
Jika file JavaScript diambil menggunakan beberapa skrip sisi server maka server juga akan mendapatkan cookie. Namun, server pihak ketiga tidak dapat membuat browser pengguna mengaitkan cookie itu ke domain kami. Karenanya, token CSRF dan cookie validasi yang telah diambil menggunakan skrip sisi server, hanya dapat digunakan oleh panggilan sisi server berikutnya, bukan di browser. Namun, panggilan sisi server tersebut tidak akan pernah menyertakan cookie pengguna, dan karenanya hanya dapat mengambil data publik. Ini adalah data yang sama yang dapat dikikis oleh skrip sisi server dari situs web mitra secara langsung.
Saat pengguna masuk, setel beberapa cookie pengguna dengan cara apa pun yang Anda suka. (Pengguna mungkin sudah masuk sebelum JavaScript diminta.)
Semua permintaan API berikutnya ke server (termasuk permintaan GET dan JSONP) harus menyertakan token CSRF, cookie validasi CSRF, dan (jika masuk) cookie pengguna. Server sekarang dapat menentukan apakah permintaan tersebut dapat dipercaya:
Kehadiran token CSRF yang valid memastikan JavaScript dimuat dari domain yang diharapkan, jika dimuat oleh browser.
Kehadiran token CSRF tanpa cookie validasi menunjukkan adanya pemalsuan.
Kehadiran token CSRF dan cookie validasi CSRF tidak memastikan apa pun: ini bisa berupa permintaan sisi server palsu, atau permintaan valid dari browser. (Tidak boleh merupakan permintaan dari browser yang dibuat dari domain yang tidak didukung.)
Kehadiran cookie pengguna memastikan pengguna masuk, tetapi tidak memastikan pengguna adalah anggota dari mitra yang diberikan, atau bahwa pengguna melihat situs web yang benar.
Kehadiran cookie pengguna tanpa cookie validasi CSRF menunjukkan adanya pemalsuan.
Kehadiran cookie pengguna memastikan permintaan saat ini dibuat melalui browser. (Dengan asumsi pengguna tidak akan memasukkan kredensial mereka di situs web yang tidak dikenal, dan dengan asumsi kami tidak peduli tentang pengguna yang menggunakan kredensial mereka sendiri untuk membuat beberapa permintaan sisi server.) Jika kami juga memiliki cookie validasi CSRF, maka cookie validasi CSRF itu adalah juga diterima menggunakan browser. Selanjutnya, jika kita juga memiliki token CSRF dengan tanda tangan yang valid, dannomor acak dalam cookie validasi CSRF cocok dengan yang ada di token CSRF itu, kemudian JavaScript untuk token itu juga diterima selama permintaan yang sama sebelumnya saat cookie CSRF ditetapkan, karenanya juga menggunakan browser. Ini kemudian juga menyiratkan kode JavaScript di atas dijalankan sebelum token disetel, dan pada saat itu domain tersebut valid untuk kunci API yang diberikan.
Jadi: server sekarang dapat dengan aman menggunakan kunci API dari token yang ditandatangani.
Jika suatu saat server tidak mempercayai permintaan tersebut, maka 403 Forbidden akan dikembalikan. Widget dapat meresponsnya dengan menampilkan peringatan kepada pengguna.
Tidak perlu menandatangani cookie validasi CSRF, karena kami membandingkannya dengan token CSRF yang ditandatangani. Tidak menandatangani cookie membuat setiap permintaan HTTP lebih pendek, dan validasi server sedikit lebih cepat.
Token CSRF yang dihasilkan berlaku tanpa batas waktu, tetapi hanya dalam kombinasi dengan cookie validasi, sangat efektif hingga browser ditutup.
Kami dapat membatasi masa tanda tangan token. Kami dapat menghapus cookie validasi CSRF saat pengguna logout, untuk memenuhi rekomendasi OWASP . Dan untuk tidak membagikan nomor acak per pengguna di antara beberapa mitra, seseorang dapat menambahkan kunci API ke nama cookie. Tetapi meskipun demikian seseorang tidak dapat dengan mudah menyegarkan cookie validasi CSRF ketika token baru diminta, karena pengguna mungkin menjelajahi situs yang sama di beberapa jendela, berbagi satu cookie (yang, saat menyegarkan, akan diperbarui di semua jendela, setelah itu Token JavaScript di jendela lain tidak lagi cocok dengan cookie tunggal itu).
Bagi mereka yang menggunakan OAuth, lihat juga OAuth dan Widget Sisi Klien , dari mana saya mendapatkan ide JavaScript. Untuk penggunaan API di sisi server , di mana kami tidak dapat mengandalkan kode JavaScript untuk membatasi domain, kami menggunakan kunci rahasia alih-alih kunci API publik.