[P0][Security] Perbaiki Kebocoran PII dan Pengamanan Endpoint Datatables Pengguna OpenSID - #714
Merged
Conversation
|
🔄 AI PR Review sedang antri di server...
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
issue # https://github.com/OpenSID/wiki-keamanan/issues/51
🎯 Deskripsi
Pull request ini menangani masalah keamanan kritis (P0 / Critical Security Issue) terkait kebocoran data pribadi (PII) dan informasi infrastruktur desa pada endpoint publik
GET /datatables/pengguna-opensiddanGET /datatables/semua-desa.Sebelumnya, endpoint tersebut dapat diakses secara terbuka tanpa login hanya dengan header
X-Requested-With: XMLHttpRequestdan menjalankan querySELECT *viaDesa::semuaDesa(). Hal ini menyebabkan bocornya data sensitif sepertiemail_desa,telepon, nomor HP/nama/jabatan operator padakontak, IP internal/hosting (ip_lokal,ip_hosting), alamat kantor, koordinat presisi (lat,lng), dan URL internal/hosting.Melalui PR ini, diterapkan pendekatan Option C (Conditional Data per Auth Status) yang tetap menjaga fungsi tampilan halaman web publik (
/web/opensid-datadan modal di/web/opensid) namun dengan pembatasan ketat:nama_desa, wilayah, versi, status TTE,updated_at) tanpa data PII maupun infrastruktur.url_hostingdankode_desa) untuk verifikasi, namun data kontak pribadi operator tetap tidak diekspos sembarangan.lengthDataTables maksimal 25 baris untuk publik dan 100 baris untuk user login.throttle:60,1pada seluruh endpoint DataTables publik guna mencegah scraping massal otomatis.?excel=1) dengan403 Forbiddenjika pengguna belum login.kabupaten-kosongke grup middlewareauth.🛠️ Perubahan yang Dilakukan
1.
app/Models/Desa.phpSecurity Fix — Penambahan scope whitelist kolom aman:
scopeSemuaDesaPublik($query): Memilih hanya kolom-kolom non-sensitif untuk konsumsi publik. Kolom PII (email_desa,telepon,kontak,ip_lokal,ip_hosting,lat,lng,alamat_kantor, dll) secara eksplisit tidak disertakan.scopeSemuaDesaAuth($query): Memilih kolom untuk pengguna terautentikasi dengan menyertakanurl_hostingdankode_desa.2.
app/Http/Controllers/DashboardController.phpSecurity Fix — Implementasi conditional scope, length limiter, dan guard export:
datatablePenggunaOpensid:lengthmenjadi 25 baris untuk publik dan 100 baris untuk user login.semuaDesaAuth()jika login dansemuaDesaPublik()jika tidak login.datatableSemuaDesa:semuaDesaAuth()jika login dansemuaDesaPublik()jika tidak login.if (! auth()->check()) abort(403, 'Unauthorized');saat ada parameter requestexcel=1.public function datatableSemuaDesa(Request $request) { if ($request->excel) { + // Export Excel hanya untuk user yang sudah login + if (! auth()->check()) { + abort(403, 'Unauthorized'); + } $paramDatatable = json_decode($request->get('params'), 1); $request->merge($paramDatatable); } @@ -80,7 +84,12 @@ ]; if ($request->ajax() || $request->excel) { - $query = DataTables::of($this->desa->fillter($filters)->semuaDesa()); + // Pilih scope berdasarkan status autentikasi + // Auth: kolom lebih lengkap (+url_hosting), Publik: hanya kolom aman tanpa PII + $queryBuilder = auth()->check() + ? $this->desa->fillter($filters)->semuaDesaAuth() + : $this->desa->fillter($filters)->semuaDesaPublik(); + + $query = DataTables::of($queryBuilder);public function datatablePenggunaOpensid(Request $request) { + // Batasi jumlah baris per request untuk mencegah dump massal data + // Auth: max 100 baris, Publik: max 25 baris + $maxLength = auth()->check() ? 100 : 25; + if ($request->has('length') && (int) $request->length > $maxLength) { + $request->merge(['length' => $maxLength]); + } + $filters = [ @@ -420,7 +424,10 @@ ]; if ($request->ajax()) { - return DataTables::of($this->desa->fillter($filters)->semuaDesa()) + // Pilih scope berdasarkan status autentikasi + // Auth: kolom lebih lengkap (+url_hosting), Publik: hanya kolom aman tanpa PII + $query = auth()->check() + ? $this->desa->fillter($filters)->semuaDesaAuth() + : $this->desa->fillter($filters)->semuaDesaPublik(); + + return DataTables::of($query)3.
routes/web.phpSecurity Fix — Penambahan middleware throttle dan pemisahan grup route:
throttle:60,1pada grupdatatablespublik.datatables/kabupaten-kosongke grup baru dengan middleware['auth', 'throttle:60,1'].✅ Test Cases yang Diimplementasikan
/datatables/pengguna-opensidtanpa login tidak lagi mengembalikan data PII (email_desa,telepon,kontak,ip_lokal,ip_hosting,lat,lng,alamat_kantor)./datatables/semua-desatanpa login tidak lagi mengembalikan data PII maupun infrastruktur.lengthyang besar (misallength=9999ataulength=1000) pada request publik otomatis dibatasi menjadi maksimal 25 baris data./datatables/semua-desa?excel=1) tanpa login mengembalikan respon403 Forbidden./datatables/kabupaten-kosongtanpa login di-redirect (302) ke halaman login./web/opensid-datadan modal pengguna di/web/opensidtetap dapat menampilkan data agregat tanpa error.📸 Cara Menjalankan Uji Coba Manual
Uji Coba Respon Publik (Tanpa Login):
Jalankan perintah cURL berikut di terminal:
data. Pastikan kolom sepertiemail_desa,telepon,kontak,ip_lokal,ip_hosting,lat,lng, danalamat_kantortidak ada di dalam respon.Uji Coba Pembatasan Length (Anti-Dump):
datayang dikembalikan maksimal 25 baris data.Uji Coba Proteksi Export Excel Tanpa Login:
403.Uji Coba Proteksi Endpoint Admin (Kabupaten Kosong):
302(redirect ke login) atau401.Uji Coba UI Frontend:
/web/opensid-datadi browser. Tabel tetap terisi dan filter wilayah berfungsi dengan baik./web/opensid, buka modal tabel selengkapnya. Data tetap tampil dengan normal tanpa mengekspos PII.🤖 Cara Menjalankan Uji Coba Otomatis (Automated Test)
Jalankan test suite untuk memastikan tidak ada regresi pada sistem:
php artisan test --testsuite=Unit📸 Screenshot atau Video
[Isi dengan tangkapan layar respon JSON yang telah dibersihkan dari PII atau rekaman browser]