Checklist Review Keamanan GraphQL
Kebijakan resolver dan kontrol permintaan query
Telusuri field GraphQL dari schema ke resolver serta sumber datanya. viewer dapat mengambil subjek dari context, sedangkan node(id:), edge connection, event subscription, dan mutation bulk masing-masing memerlukan keputusan objek sendiri. Buat fixture dua tenant dan minta global ID melalui tiap field yang dapat mencapai data terlindungi. Resolver yang mengembalikan null juga tidak boleh membocorkan jumlah, detail error, atau cache loader yang telah memuat objek asing.
Hitung demand sebelum eksekusi. Pagination membatasi output list; depth limit menangani traversal bersarang; batas alias dan batch menghentikan dokumen dangkal yang lebar; complexity berbobot membedakan nama cached dari agregasi laporan. Uji query relasi lima tingkat dan query satu tingkat dengan banyak alias. Untuk klien first-party, hash trusted document dapat menolak operasi asing, tetapi tidak menggantikan otorisasi resolver atau perlindungan klien publik.
Dokumen gagal harus mengembalikan error tersamarkan tanpa fan-out downstream. Bukti meliputi hash query atau dokumen tersamarkan, biaya terhitung, alasan penolakan, keputusan resolver, jumlah query database, dan respons. Perbaiki dengan kebijakan field, pagination, bobot complexity, atau allowlist operasi. Uji penutup menjalankan kembali dokumen yang sama serta dokumen sah dekat limit, dan memastikan penolakan terjadi sebelum resolver mahal berjalan.
Subscription memerlukan pemeriksaan tersendiri karena otorisasi saat koneksi dibuat dapat menjadi usang. Tetapkan apakah setiap event memeriksa ulang akses penerima dan bagaimana keanggotaan yang dicabut menghentikan pengiriman. Batching DataLoader tidak boleh menggabungkan konteks tenant dalam satu cache key. Untuk input mutation, tipe schema membantu parsing tetapi tidak mengotorisasi perubahan field; allowlist properti yang dapat ditulis di business logic. Simpan subscription atau node lookup yang ditolak bersama trace database untuk membuktikan hasil resolver lintas tenant tidak di-cache.
Otorisasi pada batas resolver
Otorisasi GraphQL dimulai dari execution context tetapi berakhir di dalam resolver. Telusuri viewer, node(id:), list connection, field bertingkat, mutation bulk, dan subscription sampai sumber data serta keputusan policy. Buat fixture dua tenant dengan role setara. Minta global ID asing melalui setiap resolver yang dapat mencapainya. viewer aman tidak membuat node aman, dan hasil otorisasi parent tidak otomatis mengotorisasi lampiran atau child connection.
Output penolakan yang diharapkan sengaja kecil: error tersamarkan atau null menurut kebijakan schema, tanpa nilai field asing, tanpa stack diagnostik, dan tanpa fetch data downstream yang menanam cache bersama. Periksa key DataLoader; dimensi tenant atau subjek yang relevan harus mencegah resolver diizinkan mengisi cache untuk pemanggil lain. Pada mutation, gunakan allowlist properti dapat ditulis dalam business logic. Tipe input memvalidasi bentuk, bukan otoritas mengubah role, tenantId, atau status approval.
Kasus demand control
Depth saja tidak cukup. Kirim query relasi siklik lima tingkat, lalu query dangkal dengan ratusan alias, kemudian batch berisi banyak operasi yang masing-masing valid. Pagination memerlukan maksimum first serta last; bobot complexity harus membebankan agregasi mahal lebih besar daripada nama scalar. Hash trusted document first-party dapat menolak operasi belum direview, tetapi klien publik tetap memerlukan limit. Sebelum eksekusi, dokumen melebihi budget harus memberi error stabil dan tidak menjalankan resolver atau provider mahal.
Uji variabel selain teks query literal: ukuran halaman berlebihan, ID asing, array ID, dan identifier operasi tersimpan dengan variabel diubah. Otorisasi subscription perlu diperiksa ulang setelah keanggotaan dicabut, bukan hanya ketika WebSocket dibuka. Simpan hash query atau dokumen tersamarkan, depth serta cost terhitung, keputusan resolver, jumlah query database, hasil cache, dan ID korelasi respons.
Bukti penutupan
Perbaiki melalui policy resolver, aturan properti per field, pagination, ceiling depth dan alias, batas batch, cost berbobot, atau allowlist operasi. Jalankan kembali dokumen ditolak dan dokumen sah dekat limit. Status lulus membuktikan dokumen pertama berhenti sebelum pekerjaan terlindungi, sementara dokumen kedua selesai dengan jumlah terbatas. Bila introspection produksi dibatasi, pertahankan proses rilis schema yang direview; menyembunyikan schema bukan pengganti otorisasi. Pengecualian integrasi menyebut hash operasi, pemanggil, cost maksimum, expiry, dan review audit.
Pemeriksaan transport dan error
Terapkan kontrol API biasa pada transport GraphQL: HTTPS, maksimum body request, autentikasi, kebijakan origin saat credential browser berlaku, timeout, dan tidak ada cache bersama untuk data sensitif. Perhitungan complexity tidak dapat menyelamatkan endpoint yang menerima body terlalu besar atau mutation tanpa autentikasi. Uji dokumen rusak dan tipe variabel tidak valid; error publik perlu cukup untuk koreksi klien tanpa menerbitkan stack trace, nama datasource, atau saran field di luar kebijakan.
Untuk subscription, catat principal koneksi, keputusan otorisasi, filter event, dan perilaku pencabutan. Hapus keanggotaan tenant ketika subscription aktif lalu pastikan event berikutnya ditekan. Pada schema federasi, telusuri resolusi entity lintas subgraph; satu subgraph tidak boleh mengembalikan entity asing hanya karena gateway memeriksa query masuk. Bukti penutupan memasangkan test resolver dengan test transport agar kebijakan field benar tidak tertutup oleh kanal pengiriman tidak aman.
Artefak review resolver GraphQL
| Kontrol resolver | Penanggung jawab GraphQL | Status review | Bukti query | Hasil resolver yang diharapkan | Hasil resolver teramati | Pengecualian kebijakan | Penutupan resolver |
|---|---|---|---|---|---|---|---|
GQL-AUTH-08 node(id:) asing | owner API akun | Gagal | hash query tersamarkan, trace resolver, jumlah query DB, ID respons | penolakan tersamarkan sebelum row asing diambil; key loader dibatasi tenant | resolver menolak output setelah row asing mengisi loader bersama | tidak ada; cache lintas tenant tidak boleh dirilis | batasi key loader per tenant, ulang kedua fixture tenant, pastikan nol fetch asing |