Bagaimana cara mengamankan panggilan REST API?

92

Saya sedang mengembangkan aplikasi web tenang yang menggunakan beberapa kerangka kerja web populer di backend, katakanlah (rails, sinatra, flask, express.js). Idealnya, saya ingin mengembangkan sisi klien dengan Backbone.js. Bagaimana cara mengizinkan hanya sisi klien javascript saya yang berinteraksi dengan panggilan API tersebut? Saya tidak ingin panggilan API tersebut menjadi publik dan dipanggil dengan curlatau hanya dengan memasukkan tautan di browser.

knd
sumber
Apakah semua panggilan API Anda memerlukan token yang diteruskan ke klien saat halaman Anda disajikan?
haji
Amazon AWS javascript SDK menggunakan URL objek yang telah ditandatangani sebelumnya: - docs.aws.amazon.com/AmazonS3/latest/dev/…
rjha94

Jawaban:

91

Sebagai prinsip pertama, jika API Anda dikonsumsi oleh klien JS Anda, Anda harus berasumsi, bahwa itu publik: Debugger JS sederhana menempatkan penyerang ke posisi, di mana dia dapat mengirim permintaan identik byte-untuk-byte dari alat pilihannya.

Yang mengatakan, jika saya membaca pertanyaan Anda dengan benar, ini bukan, yang ingin Anda hindari: Apa yang sebenarnya tidak Anda inginkan terjadi adalah, bahwa API Anda dikonsumsi (secara teratur) tanpa melibatkan klien JS Anda. Berikut adalah beberapa ide tentang bagaimana jika tidak menegakkan, maka setidaknya mendorong penggunaan klien Anda:

  • Saya yakin, API Anda memiliki semacam bidang otentikasi (mis. Hash dihitung pada klien). Jika tidak, lihat pertanyaan SO ini . Pastikan Anda menggunakan salt (atau bahkan kunci API) yang diberikan ke klien JS Anda pada basis sesi (aot hardcode). Dengan cara ini, konsumen API Anda yang tidak sah dipaksa untuk bekerja lebih banyak.

  • Saat memuat klien JS, ingat beberapa header HTTP (yang dipikirkan oleh agen pengguna) dan alamat IP, lalu minta autentikasi ulang jika berubah, menggunakan daftar hitam untuk tersangka biasa. Hal ini memaksa penyerang untuk melakukan pekerjaan rumahnya dengan lebih teliti lagi.

  • Di sisi server, ingat beberapa panggilan API terakhir, dan sebelum mengizinkan panggilan API lainnya, periksa apakah logika bisnis memungkinkan untuk yang baru sekarang: Ini menyangkal kemampuan penyerang untuk memusatkan banyak sesinya ke dalam satu sesi dengan server Anda: Dalam kombinasi dengan tindakan lain, ini akan membuat pelaku kekerasan mudah terdeteksi.

Saya mungkin tidak mengatakannya dengan kejelasan yang diperlukan: Saya menganggap tidak mungkin membuat mustahil bagi seorang pelaku untuk menggunakan layanan Anda, tetapi Anda dapat membuatnya begitu sulit, mungkin tidak sepadan dengan kerumitannya.

Eugen Rieck
sumber
ini adalah info yang berguna, tetapi bagaimana jika saya ingin membuat beberapa auth dari api backend saya ke aplikasi api lain seperti server terpisah, untuk menyederhanakan pertanyaan saya, saya ingin back-end aka node.js mengirim permintaan pengambilan ke back- lain- server akhir yang saya miliki, untuk beberapa alasan ini diperlukan, tetapi saya ingin mengamankan panggilan api, karena dapat mengakses data sensitif, dan saya tidak dapat menggunakan sesions atau jwt karena saya tidak dapat menyimpannya sebenarnya di browser.
Piramida
@ Thepyramid Tidak masalah, apa yang dilakukan panggilan API di sisi server, terutama jika sisi server melakukan panggilan API tingkat ke-2 lainnya. Bagian yang penting adalah memperlakukan server Anda bukan sebagai proxy, tetapi sebagai aplikasi.
Eugen Rieck
dapatkah Anda menjelaskan lebih lanjut bagaimana menjadikannya sebagai aplikasi bukan sebagai proxy
Piramida
1
Yang saya maksud adalah: Untuk mendapatkan jumlah keamanan yang layak, Anda perlu menggunakan semua alat, yang dimiliki aplikasi web: Sesi, database autentikasi, logika bisnis. Jika tidak melakukan itu dan hanya memperlakukan server Anda sebagai cara untuk meneruskan permintaan ke server lain, Anda hanya menggunakannya sebagai proxy untuk server lain itu dan dibatasi oleh keamanan apa pun yang ditawarkan server lain.
Eugen Rieck
1
@PirateApp Penyerang dapat dengan mudah mengabaikan header CSRF. Mereka hanya bekerja, jika perangkat akhir adalah browser yang belum ditambal
Eugen Rieck
12

Anda harus menerapkan semacam sistem otentikasi. Salah satu cara yang baik untuk menanganinya adalah dengan menentukan beberapa variabel header yang diharapkan. Misalnya, Anda dapat memiliki panggilan API auth / login yang mengembalikan token sesi. Panggilan berikutnya ke API Anda akan mengharapkan token sesi disetel dalam variabel header HTTP dengan nama spesifik seperti 'your-api-token'.

Sebagai alternatif, banyak sistem membuat token atau kunci akses yang diharapkan (seperti youtube, facebook atau twitter) menggunakan semacam sistem akun api. Dalam kasus tersebut, klien Anda harus menyimpannya dengan cara tertentu di klien.

Maka itu hanya masalah menambahkan pemeriksaan untuk sesi ke dalam kerangka REST Anda dan melemparkan pengecualian. Jika memungkinkan, kode status (menjadi tenang) akan menjadi kesalahan 401.

gview
sumber
8
Meskipun tidak ada yang menghentikan mereka untuk melihat header dan mereproduksinya.
cdmckay
1
@cdmckay - Token harus cocok dengan token yang disimpan dalam sebuah sesi. Hanya mereproduksi tajuk akan menghasilkan tanggapan "Tidak sah" jika berasal dari sesi yang berbeda.
Andrei Volgin
3
Mereka masih dapat menggunakan sesi yang sama dan mengubah permintaan sebelum dikirim ke API meskipun ... atau bahkan menggunakan konsol saat runtime menghasilkan panggilan dengan header / field yang cocok hanya memodifikasi bagian yang Anda butuhkan ...
Potter Rafed
2
@PotterRafed: Jika pengguna mengakses sesi validnya sendiri, yang dipanggil menggunakan aplikasi, bukan menyerangnya. Tujuan otentikasi adalah untuk mencegah akses ke sesi / data pengguna lain .
Andrei Volgin
@AndreiVolgin ya cukup adil, tapi masih rentan
Potter Rafed
9

Ada standar terbuka yang sekarang disebut "JSON Web Token",

lihat https://jwt.io/ & https://en.wikipedia.org/wiki/JSON_Web_Token

JSON Web Token (JWT) adalah standar terbuka berbasis JSON (RFC 7519) untuk membuat token yang menegaskan sejumlah klaim. Misalnya, server dapat membuat token yang memiliki klaim "masuk sebagai admin" dan memberikannya kepada klien. Klien kemudian dapat menggunakan token itu untuk membuktikan bahwa mereka masuk sebagai admin. Token ditandatangani oleh kunci server, sehingga server dapat memverifikasi bahwa token itu sah. Token dirancang agar ringkas, aman URL, dan dapat digunakan terutama dalam konteks sistem masuk tunggal (SSO) browser web. Klaim JWT biasanya dapat digunakan untuk menyampaikan identitas pengguna yang diautentikasi antara penyedia identitas dan penyedia layanan, atau jenis klaim lain seperti yang diwajibkan oleh proses bisnis. [1] [2] Token juga dapat diautentikasi dan dienkripsi. [3] [4]

bbozo.dll
sumber
Apa yang akan mencegah pengguna menyalin token mereka dan menggunakannya dalam respons lain?
Ulad Kasach
1
@UladKasach sejujurnya saya tidak pernah benar-benar membahasnya, tetapi afaik mereka dapat kedaluwarsa, unik untuk pengguna Anda, dan dienkripsi oleh SSL (yang tentu saja Anda praktikkan), itu ide yang sama persis di balik oauth afaik
bbozo
3

Permisi @MarkAmery dan Eugene, tapi itu tidak benar.

Aplikasi js + html (klien) Anda yang berjalan di browser DAPAT disiapkan untuk mengecualikan panggilan langsung yang tidak sah ke API sebagai berikut:

  1. Langkah pertama: Siapkan API untuk meminta autentikasi. The klien pertama harus mengotentikasi sendiri melalui server (atau beberapa server yang keamanan lainnya) misalnya meminta pengguna manusia untuk memberikan password yang benar.

Sebelum otentikasi, panggilan ke API tidak diterima.

Selama otentikasi, sebuah "token" dikembalikan.

Setelah otentikasi, hanya panggilan API dengan otentikasi "token" yang akan diterima.

Tentu saja pada tahap ini hanya pengguna resmi yang memiliki kata sandi yang dapat mengakses API, meskipun jika mereka adalah pemrogram yang men-debug aplikasi, mereka dapat mengaksesnya secara langsung untuk tujuan pengujian.

  1. Langkah kedua: Sekarang siapkan API keamanan tambahan, yang akan dipanggil dalam waktu singkat setelah aplikasi klien js + html awalnya diminta dari server. "Callback" ini akan memberi tahu server bahwa klien berhasil diunduh. Batasi panggilan REST API Anda untuk bekerja hanya jika klien diminta baru-baru ini dan berhasil.

Sekarang untuk menggunakan API Anda, mereka harus mengunduh klien terlebih dahulu dan benar-benar menjalankannya di browser. Hanya setelah berhasil menerima panggilan balik, dan kemudian entri pengguna dalam waktu singkat, API akan menerima panggilan.

Jadi Anda tidak perlu khawatir bahwa ini mungkin pengguna yang tidak sah tanpa kredensial.

(Judul pertanyaan, 'Bagaimana cara mengamankan panggilan REST API', dan dari sebagian besar yang Anda katakan, itu adalah perhatian utama Anda, dan bukan pertanyaan literal tentang BAGAIMANA API Anda dipanggil, melainkan OLEH SIAPA, yang benar? )

pashute
sumber
5
Poin kedua tidak masuk akal. Jika penyerang perlu memuat aplikasi Anda, dia akan melakukannya (panggilan balik Anda terlihat). Dan kemudian serang.
Andrei Volgin
Poin 2 selain poin 1. Penyerang masih membutuhkan otentikasi. Butir 2 hanya menambahkan bahwa kebutuhan untuk benar-benar mengunduh aplikasi html untuk mendapatkan otorisasi. Jadi panggilan langsung ke API tanpa aplikasi (mungkin diakses dan diunduh hanya setelah otentikasi) tidak mungkin. Yang merupakan sesuatu yang diminta dalam pertanyaan ini.
pashute
Anda hanya dapat mengizinkan permintaan dari domain Anda.
Andrei Volgin
Itu hanya membatasi panggilan ke dalam domain, jadi sekarang pengguna aplikasi browser javascript harus berada di dalam domain (mungkin bukan sesuatu yang diinginkan knd) dan pengguna tersebut masih dapat memanggil API secara langsung melalui curl.
pashute
2
Apa yang tampaknya Anda abaikan adalah, bahwa APA PUN yang Anda minta browser pengguna Anda lakukan, dapat direplikasi oleh penyerang - untuk membuat browser melakukannya, itu harus dapat dibaca.
Eugen Rieck
1
  1. Tetapkan var SESSION di server ketika klien pertama kali memuat Anda index.html(atau backbone.jsdll.)

  2. Periksa var ini di sisi server pada setiap panggilan API.

PS ini bukan solusi "keamanan" !!! Ini hanya untuk meringankan beban di server Anda sehingga orang tidak menyalahgunakannya atau "menautkan" API Anda dari situs web dan aplikasi lain.

Alex
sumber
0

Inilah yang saya lakukan:

  1. Amankan API dengan HTTP Header dengan panggilan seperti X-APITOKEN:

  2. Gunakan variabel sesi di PHP. Memiliki sistem login dan menyimpan token pengguna di variabel sesi.

  3. Panggil kode JS dengan Ajax ke PHP dan gunakan variabel sesi dengan curl untuk memanggil API. Dengan begitu, jika variabel sesi tidak disetel, itu tidak akan memanggil dan kode PHP berisi Token Akses ke API.

Pavneet Singh
sumber