
Baru-baru ini, GraphQL semakin populer, dan dengan itu semakin menarik minat para pakar keamanan informasi. Teknologi ini digunakan oleh perusahaan-perusahaan seperti: Facebook, Twitter, PayPal, Github, dan lainnya, yang berarti sudah saatnya mencari cara untuk menguji API semacam itu. Pada artikel ini, kita akan berbicara tentang prinsip-prinsip bahasa permintaan ini dan arah untuk menguji penetrasi aplikasi dengan GraphQL.
Mengapa Anda perlu tahu GraphQL? Bahasa permintaan ini secara aktif berkembang dan semakin banyak perusahaan yang menemukan penggunaan praktis untuk itu. Dalam kerangka program Bug Bounty, popularitas bahasa ini juga berkembang, contoh menarik dapat dilihat di
sini , di
sini dan di
sini .
PersiapanSitus uji tempat Anda akan menemukan sebagian besar contoh dalam artikel ini.
Daftar dengan aplikasi yang juga dapat Anda gunakan untuk belajar.
Untuk berinteraksi dengan berbagai API, lebih baik menggunakan GraphQL IDE:
Kami merekomendasikan IDE terakhir: Insomnia memiliki antarmuka yang mudah dan sederhana, ada banyak pengaturan dan pelengkapan otomatis bidang permintaan.
Sebelum melanjutkan langsung ke metode umum analisis keamanan aplikasi dengan GraphQL, kami mengingat konsep dasar.
Apa itu GraphQL?
GraphQL adalah bahasa permintaan API yang dirancang untuk memberikan alternatif REST yang lebih efisien, kuat, dan fleksibel. Ini didasarkan pada pengambilan sampel data deklaratif, yaitu, klien dapat menentukan dengan tepat data apa yang dibutuhkan dari API. Alih-alih beberapa titik akhir API (REST), GraphQL menyediakan titik akhir tunggal yang menyediakan klien dengan data yang diminta.
Perbedaan utama antara REST dan GraphQL
Biasanya di REST API Anda perlu mendapatkan informasi dari titik akhir yang berbeda. Di GraphQL, untuk mendapatkan data yang sama, Anda harus membuat satu kueri yang menunjukkan data yang ingin Anda terima.

REST API memberikan informasi yang akan dimasukkan pengembang ke dalam API, yaitu, jika Anda perlu mendapatkan informasi lebih banyak atau lebih sedikit daripada yang disarankan oleh API, maka tindakan tambahan akan diperlukan. Sekali lagi, GraphQL menyediakan persis informasi yang diminta.
Tambahan yang bermanfaat adalah GraphQL memiliki skema yang menjelaskan bagaimana dan data apa yang dapat diterima klien.
Jenis-jenis Pertanyaan
Ada 3 jenis pertanyaan utama di GraphQL:
- Pertanyaan
- Mutasi
- Berlangganan
PertanyaanKueri kueri digunakan untuk mengambil / membaca data dalam suatu skema.
Contoh permintaan seperti itu:
query { allPersons { name } }
Dalam permintaan, kami menunjukkan bahwa kami ingin mendapatkan nama semua pengguna. Selain namanya, kita dapat menentukan bidang lain:
usia ,
id ,
posting , dll. Untuk mengetahui bidang mana yang bisa kita dapatkan, Anda perlu menekan Ctrl + Spasi. Dalam contoh ini, kami meneruskan parameter yang digunakan aplikasi untuk mengembalikan dua catatan pertama:
query { allPersons(first: 2) { name } }
MutasiJika jenis permintaan diperlukan untuk membaca data, jenis mutasi diperlukan untuk menulis, menghapus dan memodifikasi data dalam GraphQL.
Contoh permintaan seperti itu:
mutation { createPerson(name:"Bob", age: 37) { id name age } }
Dalam permintaan ini, kami membuat pengguna dengan nama Bob dan usia 37 (parameter ini diteruskan sebagai argumen), dalam lampiran (kurung keriting) kami menunjukkan data apa yang ingin kami terima dari server setelah membuat pengguna. Ini diperlukan untuk memahami bahwa permintaan itu berhasil, serta untuk mendapatkan data yang dihasilkan server secara independen, seperti
id .
BerlanggananJenis lain dari permintaan dalam GraphQL adalah berlangganan. Diperlukan untuk memberi tahu pengguna tentang segala perubahan yang terjadi dalam sistem. Ia bekerja seperti ini: klien berlangganan ke beberapa acara, setelah itu koneksi dibuat dengan server (biasanya melalui WebSocket), dan ketika acara ini terjadi, server mengirimkan pemberitahuan kepada klien tentang koneksi yang dibuat.
Contoh:
subscription { newPerson { name age id } }
Ketika Orang baru dibuat, server akan mengirim informasi ke klien. Kehadiran permintaan berlangganan di skema kurang umum daripada permintaan dan mutasi.
Perlu dicatat bahwa semua kemampuan untuk kueri, mutasi, dan berlangganan dibuat dan dikonfigurasikan oleh pengembang API tertentu.
Opsional
Dalam praktiknya, pengembang sering menggunakan alias dan OperationName dalam kueri untuk kejelasan.
AliasGraphQL untuk kueri menyediakan fitur alias, yang dapat membuatnya lebih mudah untuk memahami apa yang diminta klien.
Misalkan kita memiliki kueri formulir:
{ Person(id: 123) { age } }
yang akan menampilkan nama pengguna dengan
id 123. Biarkan nama pengguna ini menjadi Vasya.
Sehingga lain kali Anda tidak akan mengacaukan tampilan permintaan ini, Anda dapat melakukannya seperti ini:
{ Vasya: Person(id: 123) { age } }
Nama operasiSelain alias, GraphQL menggunakan OperationName:
query gettingAllPersons { allPersons { name age } }
OperationName diperlukan untuk menjelaskan apa yang dilakukan permintaan.
Pentest
Setelah kami menemukan dasar-dasarnya, kami langsung menuju ke pentest. Bagaimana memahami bahwa suatu aplikasi menggunakan GraphQL? Berikut adalah contoh permintaan yang memiliki permintaan GraphQL:
POST /simple/v1/cjp70ml3o9tpa0184rtqs8tmu/ HTTP/1.1 Host: api.graph.cool User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:65.0) Gecko/20100101 Firefox/65.0 Accept: */* Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Referer: https://api.graph.cool/simple/v1/cjp70ml3o9tpa0184rtqs8tmu/ content-type: application/json Origin: https://api.graph.cool Content-Length: 139 Connection: close {"operationName":null,"variables":{},"query":"{\n __schema {\n mutationType {\n fields {\n name\n }\n }\n }\n}\n"}
Beberapa parameter yang dapat Anda pahami bahwa ini adalah GraphQL, dan bukan sesuatu yang lain:
- di badan permintaan ada kata-kata: __schema, bidang, operationName, mutasi, dll;
- di badan permintaan ada banyak karakter "\ n". Seperti yang ditunjukkan oleh latihan, mereka dapat dihapus untuk membuatnya lebih mudah untuk membaca permintaan;
- sering kali cara mengirim permintaan ke server: βgraphql
Hebat, ditemukan dan diidentifikasi. Tetapi di
mana harus memasukkan tanda kutip bagaimana menemukan apa yang perlu kita kerjakan? Introspeksi akan datang untuk menyelamatkan.
Introspeksi diri
GraphQL menyediakan skema introspeksi, mis. sebuah skema yang menggambarkan data yang bisa kita dapatkan. Berkat ini, kami dapat mengetahui permintaan apa yang ada, argumen apa yang dapat / harus disampaikan kepada mereka, dan banyak lagi. Perhatikan bahwa dalam beberapa kasus, pengembang sengaja tidak mengizinkan kemungkinan introspeksi aplikasi mereka. Namun, sebagian besar masih menyisakan kemungkinan ini.
Pertimbangkan contoh dasar kueri.
Contoh 1. Mendapatkan semua jenis permintaan query { __schema { types { name fields { name } } } }
Kami membentuk kueri kueri, menunjukkan bahwa kami ingin menerima data pada __schema, dan di dalamnya ketik, nama dan bidangnya. Dalam GraphQL, ada nama-nama variabel layanan: __schema, __typename, __type.
Dalam jawabannya, kami akan menerima semua jenis permintaan, nama dan bidangnya yang ada dalam skema.
Contoh 2. Memperoleh bidang untuk jenis permintaan tertentu (kueri, mutasi, deskripsi) query { __schema { queryType { fields { name args { name } } } } }
Jawaban atas permintaan ini adalah semua kemungkinan permintaan yang dapat kami lakukan pada skema untuk menerima data (jenis kueri), dan kemungkinan / diperlukan argumen untuknya. Untuk beberapa pertanyaan, menentukan argumen diperlukan. Jika Anda menjalankan permintaan seperti itu tanpa menentukan argumen yang diperlukan, server harus menampilkan pesan kesalahan yang harus Anda tentukan. Alih-alih queryType, kita dapat mengganti mutationType dan berlanggananType untuk mendapatkan semua kemungkinan permintaan untuk mutasi dan langganan.
Contoh 3. Mendapatkan informasi tentang jenis permintaan tertentu query { __type(name: "Person") { fields { name } } }
Berkat kueri ini, kami mendapatkan semua bidang untuk tipe Orang. Sebagai argumen, alih-alih Orang, kami dapat memberikan nama permintaan lainnya.
Sekarang kita dapat mengetahui struktur umum aplikasi yang sedang diuji, mari kita tentukan apa yang kita cari.
Pengungkapan informasiPaling sering, aplikasi yang menggunakan GraphQL terdiri dari banyak bidang dan jenis kueri, dan, seperti banyak orang tahu, semakin kompleks dan semakin besar aplikasi, semakin sulit untuk mengkonfigurasi dan memantau keamanannya. Itulah sebabnya dengan introspeksi yang cermat Anda dapat menemukan sesuatu yang menarik, misalnya: nama lengkap pengguna, nomor telepon mereka, dan data penting lainnya. Oleh karena itu, jika Anda ingin menemukan sesuatu seperti ini, maka kami sarankan Anda memeriksa semua bidang dan argumen aplikasi yang mungkin. Jadi, sebagai bagian dari pentest di salah satu aplikasi, data pengguna ditemukan: nama, nomor telepon, tanggal lahir, beberapa data kartu, dll.
Contoh:
query { User(id: 1) { name birth phone email password } }
Melalui nilai-nilai id, kita dapat memperoleh informasi tentang pengguna lain (dan mungkin tidak, jika semuanya dikonfigurasi dengan benar).
SuntikanTak perlu dikatakan, hampir di mana-mana di mana ada pekerjaan dengan sejumlah besar data, ada database? Dan di mana ada database - mungkin ada injeksi SQL, injeksi NoSQL dan jenis injeksi lainnya.
Contoh:
mutation { createPerson(name:"Vasya'--+") { name } }
Berikut ini adalah injeksi SQL dasar dalam argumen kueri.
Bypass otorisasiKatakanlah kita dapat membuat pengguna:
mutation { createPerson(username:"Vasya", password: "Qwerty1") { } }
Dengan asumsi ada parameter tertentu isAdmin di handler di server, kami dapat mengirim permintaan formulir:
mutation { createPerson(username:"Vasya", password: "Qwerty1", isAdmin: True) { } }
Dan menjadikan Vasya pengguna sebagai administrator.
Dos
Selain kenyamanan yang dinyatakan, GraphQL memiliki kelemahan keamanannya sendiri.
Pertimbangkan sebuah contoh:
query { Person { posts { author { posts { author { posts { author ... } } } } } } }
Seperti yang Anda lihat, kami membuat subquery loop. Dengan sejumlah besar investasi semacam itu, misalnya, 50 ribu, kami dapat mengirim permintaan yang akan diproses oleh server untuk waktu yang sangat lama atau "menjatuhkan" semuanya. Alih-alih memproses permintaan yang valid, server akan sibuk membongkar sarang besar dari permintaan dummy.
Selain bersarang besar, kueri sendiri bisa "berat" - ini adalah saat kueri memiliki banyak bidang dan lampiran internal. Permintaan seperti itu juga dapat menyebabkan kesulitan dalam pemrosesan di server.
Kesimpulan
Jadi, kami memeriksa prinsip-prinsip dasar pengujian penetrasi aplikasi dengan GraphQL. Kami harap Anda telah mempelajari sesuatu yang baru dan bermanfaat untuk diri Anda sendiri. Jika Anda tertarik dengan topik ini, dan ingin mempelajarinya lebih dalam, kami merekomendasikan sumber daya berikut:
Dan jangan lupa: latihan menjadi sempurna. Semoga beruntung