← Portal SIPASI R&D

Audit SIPASI (CI4) — 26 Agustus 2026

Dokumen ini merupakan laporan audit teknis dan keamanan independen menyeluruh untuk aplikasi SIPASI (Sistem Informasi Pengelolaan Air dan Skema Irigasi) berbasis CodeIgniter 4, dengan struktur aplikasi di `app_sipasi/` dan direktori web root di `public_html/`.

1. Ringkasan Eksekutif

Aplikasi SIPASI dibangun di atas CodeIgniter 4.4.3, namun secara arsitektur dan pola penulisan kode masih mengadopsi paradigma *legacy* (pola procedural PHP era CodeIgniter 2/3). Terdapat celah keamanan kritikal tingkat tinggi (*Remote Data Wipe*, *Arbitrary SQL Execution*, *Plaintext Credentials*, dan *Unauthenticated Sensitive Endpoints*) yang sangat berisiko terhadap kerahasiaan, integritas, dan ketersediaan data irigasi nasional.

5 Temuan Terpenting

2. Profil Teknis

| Parameter | Spesifikasi / Temuan | Keterangan | | :--- | :--- | :--- | | Framework Version | CodeIgniter v4.4.3 | Dikonfirmasi dari `system/CodeIgniter.php:26` (`CI_VERSION = '4.4.3'`) | | PHP Min Requirement | PHP ^7.4 || ^8.0 | Didefinisikan di `composer.json:11` dan `public_html/index.php:3` | | Database Driver | MySQLi (`MySQLiHandler`) | Koneksi MariaDB/MySQL (`Config/Database.php`) | | Ekstensi Wajib | `intl`, `json`, `mbstring`, `mysqli`, `curl`, `gd` | Kebutuhan CI4 core, telemetri, manipulasi gambar, dan kalkulasi | | Library / Dependency | `laminas/laminas-escaper: ^2.9`
`psr/log: ^1.1`
`kint-php/kint: ^5.0.4` | Dependensi standar framework CodeIgniter 4 | | Arsitektur Aplikasi | Hybrid MVC / Procedural Custom Routing | Modifikasi routing dengan helper `urinext()`, model monolitik multi-tujuan |

Analisis Arsitektur & Pola Desain

3. Audit Keamanan (Prioritas Tinggi)

a) SQL Injection (Kritis)

Ditemukan lebih dari 270 titik eksekusi SQL mentah (`$this->db->query`) yang menggabungkan variabel input langsung tanpa sanitasi atau parameter binding. #### Bukti Temuan Kode:
php
   // Mdl_db_ajax.php: L37-43
   $tabel = $_POST['table'];
   $list_fieldname = !empty($_POST['fl']) ? $_POST['fl'] : ' * ';
   $WH  = !empty($_POST['wh']) ? ' WHERE '. $_POST['wh'] : '';
   $OPT = !empty($_POST['opt']) ? $_POST['opt'] : '';
   $query = $this->db->query("SELECT $list_fieldname FROM $tabel $WH $OPT ");
   
php
   // CmsContent.php: L30-33
   foreach($arrSearchField AS $fnm){
       if(!empty($fnm)){
           $search .= $dan. "$fnm LIKE '%".$_POST[$fnm]."%'";
           $dan = ' AND ';
       }
   }
   // CmsListing.php: L318
   $querytab = $this->db->query("SELECT $idkey AS id, $listSelect FROM $tabel $WHERE ORDER BY $ORDER_BY $ASC LIMIT $LIMIT");
   
php
   // Mdl_perencanaan.php: L156
   $RPT = $this->db->query("SELECT * FROM dd_pt_profil WHERE id = '$idRPT' AND kode_di = '$this->id_di' ORDER BY id DESC LIMIT 1")->getRowArray();
   // Mdl_perencanaan.php: L380
   $tersierData = $this->db->query("SELECT * FROM dts_petak_tersier WHERE id = '$idPetak'")->getRowArray();
   
php
   // Scadapost.php: L145
   $groupBB = $this->db->query("SELECT * FROM dts_device_node WHERE device_type = 'AWLMS' AND nama_bb = '".$row['id_stasiun']."'")->getResultArray();
   // Scadapost.php: L154
   $query = "SELECT id_ruas,nama_ruas,last_update,debit_sensor,tma_sensor,bukaan_pintu,id_admin FROM dd_debit_real_ruas WHERE DATE(last_update) = CURRENT_DATE() AND id_ruas = '".$bb['id_ruas']."' ORDER BY last_update DESC LIMIT 1";
   
php
   // Io.php: L57
   $querydata = $this->db->query('SHOW TABLES LIKE "dts_'.$dataPost['data'].'"');
   

b) Cross-Site Scripting / XSS (Tinggi)

#### Bukti Temuan Kode:
php
  <main class="content"><?= $BODY_CONTENT ?></main>
  
php
  <h4 class="mb-0 text-white"><?= $namaDI ?></h4>
  <p class="mb-0 text-muted">Luas: <?= $luas_layanan ?> Ha | Wilayah: <?= $kabupaten ?></p>
  
php
  $data = $parser->setData($arrParser)->renderString($template);
  
Template form dibangun dengan merangkai HTML mentah langsung dari field database (`cms_listing_field`) dan di-render menggunakan parser tanpa escaping otomatis.

c) CSRF (Cross-Site Request Forgery) (Tinggi)

php
  public array $globals = [
      'before' => [
          // 'honeypot',
          // 'csrf',
          // 'invalidchars',
      ],
      'after' => [
          'toolbar',
          // 'honeypot',
          // 'secureheaders',
      ],
  ];
  

d) Autentikasi & Otorisasi (Kritis)

e) Penanganan File Upload & Path Traversal (Kritis)

#### Bukti Temuan Kode:
php
   // Apk.php: L505-520
   $folder_name = 'upload/'.$ruas_id.'/';
   if (!is_dir($folder_name)) {
       mkdir($folder_name, 0777, true);
   }
   $img_name = $img_id.'.jpg';
   $image_parts = explode(";base64,", $image);
   $image_base64 = base64_decode($image_parts[1]);
   $file_path = $folder_name . $img_name;
   file_put_contents($file_path, $image_base64);
   
php
   // Iopost.php: L285-292
   $uploadDir = 'device/'.$idKey.'/'; 
   if (!file_exists($uploadDir)) {
       mkdir($uploadDir, 0755, true);
   }
   $uploadFile = $uploadDir. $file_name;
   move_uploaded_file($_FILES['file_contents']['tmp_name'], $uploadFile);
   

f) Konfigurasi Berisiko & Kebocoran Informasi (Tinggi)

| File & Baris | Konfigurasi Aktif | Risiko / Dampak | | :--- | :--- | :--- | | `sipasi_oransbari/.env:19-21` | `CI_ENVIRONMENT = production`
`error_reporting = E_ALL`
`display_errors = 1` | Menampilkan pesan error PHP lengkap, file path absolut, dan query SQL langsung ke browser pengguna saat runtime exception terjadi. | | `sipasi_oransbari/.env:27-29` | `database.default.username = sipasi`
`database.default.password = SipasiRiset2026!` | Kredensial database tersimpan di environment file dengan permission standar (`644`). | | `app_sipasi/Config/Encryption.php:22` | `public string $key = '';` | Kunci enkripsi default kosong, menyebabkan kegagalan keamanan pada enkripsi cookie/session atau token. | | `app_sipasi/Config/App.php:178` | `public bool $CSPEnabled = false;` | Content Security Policy nonaktif, memudahkan serangan XSS dan inject script eksternal. | | `app_sipasi/Controllers/Scadapost.php:218-230` | `readfile/file_get_contents(WRITEPATH . 'logs/log-...')` | Method `Scadapost::debug()` mem-print 10 baris terakhir log aplikasi langsung ke browser tanpa otentikasi. | | `app_sipasi/Controllers/Iopost.php:1044-1065` | `curl_init("http://{$ipAddress}/api/command")` | Method `command()` menerima parameter `ip` dari JSON request tanpa validasi whitelist, membuka celah SSRF (*Server-Side Request Forgery*) ke internal server / port localhost (e.g. 127.0.0.1, AWS metadata 169.254.169.254). |

4. Analisis Teknik Lama & Technical Debt

a) MyISAM vs InnoDB & Kekacauan Charset

b) Mindset PHP Legacy & Anti-Patterns

php
     $data_argbn = str_replace(':','=>',$argbn[1]);
     eval('$'.trim($argbn[0]).'= array'.$data_argbn.';');
     
Konstruksi array PHP dijalankan menggunakan `eval()` dari string kustom alih-alih menggunakan serialisasi standar `json_decode()` / `json_encode()`.
php
     ${'debitHarian'.$vTgl} = $this->db->query("SELECT * FROM dd_debit_ruas_harian WHERE DATE(last_update) = '$tahun-$bulan-$vTgl' ...")->getResultArray();
     

c) Duplikasi Kode Masif & Artefak Sampah

Daftar File Duplikat Ekstrem (Kloning View Rencana PT):
├── app_sipasi/Views/Sipasi/xxx_RencanaPT_admin.php        (3.237 baris)
├── app_sipasi/Views/Sipasi/RencanaPT_admin.php            (3.165 baris)
├── app_sipasi/Views/Sipasi/RencanaPT_admin_copy.php       (3.126 baris)
├── app_sipasi/Views/Sipasi/Rencana_PT.php                 (3.122 baris)
└── app_sipasi/Views/Sipasi/Rencana_PTX.php                (3.104 baris)
Total: >15.750 baris kode hasil copy-paste manual
#### Artefak & File yang Berada di Tempat yang Salah:

5. Kualitas Data & Analisis Database

a) Statistik Tabel Terbesar

Berdasarkan dump database operasional (`DB_SIPASI_Sapon.sql` & `DB_SIPASI_Oransbari.sql`): | Nama Tabel | Engine | Charset | Estimasi Baris Data | Primary Key | Secondary Index | | :--- | :--- | :--- | :--- | :--- | :--- | | `dd_debit_real_ruas` | InnoDB | `utf8` | 205.745 | `id` | TIDAK ADA | | `dd_petak_tersier_harian`| InnoDB | `latin1` | 32.030 | `id` | TIDAK ADA | | `dd_debit_ruas_panca` | InnoDB | `latin1` | 5.695 | `id` | TIDAK ADA | | `dd_debit_sumber_harian`| InnoDB | `latin1` | 5.655 | `id_debit` | TIDAK ADA | | `debit_intake_sapon` | InnoDB | `latin1` | 5.529 | `id` | Ada (1 index) | | `iklim` | InnoDB | `utf8mb4`| 5.449 | `id` | Ada (1 index) | | `dd_awlr_log` | InnoDB | `utf8` | 3.926 | `id` | TIDAK ADA | | `dd_debit_ruas_harian` | InnoDB | `latin1` | 1.534 | `id` | TIDAK ADA | | `dd_debit_sumber_panca` | InnoDB | `latin1` | 1.125 | `id_debit` | TIDAK ADA |

b) Masalah Index & Pola N+1 Query

sql
     WHERE DATE(last_update) = CURRENT_DATE() AND id_ruas = 'b1xb2' ORDER BY last_update DESC
     
Karena tidak ada index pada `(id_ruas, last_update)`, database melakukan Full Table Scan (205k baris) pada setiap request SCADA dan halaman publik.

c) Foreign Key & Integritas Relasional

6. Roadmap Modernisasi & Rencana Tindak Lanjut

Matriks Prioritas & Estimasi Effort

┌────────────────────────────────────────────────────────────────────────┐
│ P0: Darurat Keamanan (Wajib segera sebelum deployment publik)          │
│ P1: Penting & Struktural (Stabilitas, Integritas Data & Performa)      │
│ P2: Nice-to-Have / Polish (Kualitas Kode Jangka Panjang & Arsitektur) │
└────────────────────────────────────────────────────────────────────────┘
| Kode | Kategori | Item Pekerjaan / Remediasi | Estimasi Effort | Bukti / Lokasi Target | | :---: | :---: | :--- | :---: | :--- | | P0-1 | Keamanan | Amankan / Hapus Wizard Instalasi Tanpa Auth
Beri proteksi filter autentikasi admin atau hapus endpoint `Install::auto_generate` agar database tidak dapat di-truncate publik. | Kecil *(1-2 jam)* | `Controllers/Install.php:21`
`Config/Routes.php:57-59` | | P0-2 | Keamanan | Tutup Backdoor Arbitrary Query di `Mdl_db_ajax`
Hapus method eksekusi query dinamis mentah atau gantikan dengan whitelist handler spesifik. | Kecil *(1-2 jam)* | `Models/Modul/Mdl_db_ajax.php:37` | | P0-3 | Keamanan | Terapkan Otentikasi Terpusat via CI4 Filter
Buat filter auth (`AuthFilter`) dan daftarkan di `Config/Filters.php` untuk memproteksi `/cms`, `/cmsm`, `/dev`, dan endpoint administratif. | Sedang *(1-2 hari)* | `Config/Filters.php`
`Controllers/Cmsm.php`
`Controllers/Dev.php` | | P0-4 | Keamanan | Migrasi Password ke `password_hash()` (Bcrypt / Argon2id)
Ubah tipe kolom password database (`varchar(255)`), terapkan `password_hash` dan `password_verify` pada proses login. | Sedang *(1-2 hari)* | `Models/Cms/CmsLogIn.php:28`
`db_dump/DB_SIPASI_Oransbari.sql:2689` | | P0-5 | Keamanan | Validasi Ketat Upload File & Pindahkan dari Docroot
Gunakan validasi CI4 File Validation (MIME type, ekstensi whitelist), cegah path traversal pada `ruas_id`, simpan di direktori non-executable. | Sedang *(1-2 hari)* | `Controllers/Apk.php:500`
`Controllers/Iopost.php:280` | | P0-6 | Keamanan | Perbaiki Konfigurasi Environment & Nonaktifkan Display Errors
Set `display_errors = 0` di production, generate `app.encryptionKey`, dan hapus endpoint `Scadapost::debug()` yang membocorkan log. | Kecil *(1-2 jam)* | `.env:21`
`Config/Encryption.php:22`
`Controllers/Scadapost.php:218` | | P0-7 | Keamanan | Eliminasi Penggunaan `eval()`
Gantikan parsing skema dan template berbasis `eval()` dengan `json_decode()` dan template builder aman. | Sedang *(2-3 hari)* | `Models/Cms/CmsListing.php:336`
`Models/Sipasi/Mdl_skema_jaringan.php:1048` | | P1-1 | Stabilitas | Parameterisasi Seluruh Query SQL (Query Binding)
Ganti seluruh konkatenasi string SQL mentah (>270 titik) dengan Query Binding CI4 (`$db->query($sql, [$param])`) atau Query Builder. | Besar *(1-2 minggu)* | Seluruh Model di `Models/Sipasi/`, `Models/Cms/` | | P1-2 | Database | Penambahan Composite Index pada Tabel Kritis
Tambahkan index pada `dd_debit_real_ruas (id_ruas, last_update)`, `dd_petak_tersier_harian (petak_id, tanggal)`, `dts_device_node (device_type, nama_bb)`. | Sedang *(1 hari)* | `db_dump/DB_SIPASI_Oransbari.sql` | | P1-3 | Database | Standarisasi Database Engine ke InnoDB & Charset UTF-8
Konversi tabel `cms_level_admin` ke InnoDB dan migrasikan seluruh tabel `latin1` ke `utf8mb4_unicode_ci`. | Sedang *(1-2 hari)* | Skema Database MariaDB | | P1-4 | Performa | Refactoring N+1 Query Loop Menjadi Batch Queries
Optimalkan controller `Scadapost`, `Scada`, dan `Mdl_blangko_o` agar mengambil data menggunakan single `IN (...)` atau `JOIN` query. | Besar *(3-5 hari)* | `Controllers/Scadapost.php:144`
`Models/Sipasi/Mdl_blangko_o.php:447` | | P1-5 | Keamanan | Aktifkan Proteksi CSRF Global
Aktifkan filter `'csrf'` di `Config/Filters.php` dan tambahkan CSRF token di AJAX headers / form input. | Sedang *(2-3 hari)* | `Config/Filters.php:36`
`public_html/assets/js/` | | P1-6 | Kebersihan | Pembersihan Kode Mati & File Artefak
Hapus duplikat view `xxx_RencanaPT`, file firmware `.cpp`, file `.pdf`, dan file `.code-workspace` dari direktori web. | Kecil *(2-4 jam)* | `Views/Sipasi/`, `Views/Scada/`, `Controllers/` | | P2-1 | Arsitektur | Restrukturisasi View Monolitik Menjadi Modular Components
Pecah view 3.000+ baris `RencanaPT` menjadi partial view terpisah (UI components, SVG canvas, data tables). | Besar *(1-2 minggu)* | `Views/Sipasi/Rencana_PT.php` | | P2-2 | Arsitektur | Refactoring `bassic_helper` Menjadi Service Classes
Bongkar fungsi procedural `bassic_helper.php` dan `kat_helper.php` menjadi *HydrologyCalculationService*, *DateHelper*, dan *ImageService* berstandar OOP PSR-4. | Sedang *(3-5 hari)* | `Helpers/bassic_helper.php`
`Helpers/kat_helper.php` | | P2-3 | Arsitektur | Penerapan CI4 Entities & Form Request Validation
Gunakan validasi CI4 otomatis (`$validation->setRules()`) dan Entity mapping pada model transaksi. | Besar *(1-2 minggu)* | `Models/`, `Controllers/` | | P2-4 | Kualitas | Implementasi Automated Unit Testing (PHPUnit)
Buat automated test suite untuk memvalidasi akurasi perhitungan rumus hidrologi (KAT, ETo, Alokasi Debit Irigasi). | Sedang *(3-5 hari)* | `tests/` |

Kesimpulan Auditor

Aplikasi SIPASI memiliki fungsionalitas inti yang sangat kaya dan spesifik untuk manajemen hidrologi dan otomasi irigasi (SCADA/IoT). Namun, kode saat ini berada dalam kondisi resiko keamanan dan performa yang sangat tinggi. Implementasi perbaikan pada kategori P0 (Darurat Keamanan) mutlak harus diselesaikan sebelum sistem diakses oleh publik atau dihubungkan dengan perangkat telemetri jaringan luas, disusul dengan perbaikan indeks database dan eliminasi duplikasi kode pada kategori P1.