22 KiB
Audit & Rencana Deployment: SIG UAS WebGIS
Dokumen ini berisi hasil audit teknis, analisis keamanan, dan rencana implementasi deployment untuk tugas akhir Sistem Informasi Geografis (SIG) yang terdiri dari dua project: Poverty Mapping (tugas utama) dan Tugas SPBU (tugas penunjang).
1. Analisis Struktur Project
Kedua project memiliki karakteristik teknologi yang hampir sama tetapi memiliki tingkat kematangan arsitektur yang berbeda.
A. Folder poverty-mapping (Project Utama)
- Teknologi & Framework: PHP Native untuk backend, HTML/CSS/JS native dengan Leaflet.js dan Leaflet Draw untuk frontend.
- Dependencies:
phpmailer/phpmailer(pengiriman email verifikasi).vlucas/phpdotenv(manajemen environment variables).
- Struktur Folder:
poverty-mapping/ ├── src/ │ ├── api/ # Rest API (tambah_lokasi, get_lokasi, dll.) │ │ ├── admin/ # Manajemen persetujuan manager oleh admin │ │ └── auth/ # Register, login, email verification │ └── config/ # auth.php, config.php, koneksi.php ├── sql/migrations/ # 001_init_schema.sql (skema DB) ├── uploads/ # Folder penyimpanan foto lokasi ├── index.html # Frontend SPA utama └── composer.json # Deklarasi dependencies composer - Konfigurasi Database: Menggunakan file
src/config/koneksi.phpyang membacagetenv()dari environment system dengan fallback ke kredensial default (localhost,root,ilham,webgis). - Konfigurasi Environment: Membaca
.envdari root directory project menggunakan parser kustom disrc/config/config.phpserta autoloading library dotenv. - Potensi Masalah: Nama database default adalah
webgisyang berpotensi konflik dengan project kedua.
B. Folder tugas-spbu (Tugas Penunjang)
- Teknologi & Framework: PHP Native untuk backend, HTML/CSS/JS native dengan Leaflet.js, Leaflet Draw, dan Leaflet GeometryUtil.
- Dependencies: Tidak menggunakan Composer (pure PHP + JavaScript CDN).
- Struktur Folder:
tugas-spbu/ ├── src/ │ ├── api/ # Rest API (get_lokasi, tambah_jalan, dll.) │ └── config/ # auth.php, config.php, koneksi.php ├── sql/ # webgis.sql (dump skema dan data awal) └── index.html # Frontend SPA utama - Konfigurasi Database: KREDENSIAL HARDCODED di
src/config/koneksi.php:Ini adalah masalah kritis karena server tujuan deployment pasti menggunakan host, user, password, atau nama database yang berbeda.$conn = new mysqli("localhost", "root", "ilham", "webgis2"); - Konfigurasi Environment: Hanya memiliki variabel
API_KEYdi.env.example. - Potensi Masalah:
- Koneksi database yang di-hardcode.
- Frontend (
index.html) tidak memiliki antarmuka atau logika untuk memuat/menyimpanAPI_KEY, sehingga seluruh operasi write (tambah, edit, hapus) di server akan menghasilkan401 Unauthorizedkarena headerX-API-KEYbernilaiundefined.
2. Landing Page Utama
Untuk menyatukan pintu masuk ke kedua project, opsi terbaik adalah menggunakan Reverse Proxy (Nginx) yang melayani Landing Page di root path (/) dan membelokkan traffic subpath ke container masing-masing aplikasi.
Keuntungan Pendekatan Reverse Proxy:
- Isolasi Kode: Project
poverty-mappingdantugas-spbutetap terpisah secara logika dan runtime di container-nya masing-masing. - Kemudahan Jalur URL: Memungkinkan konfigurasi domain tunggal (misal:
sig.domain.com) tanpa memerlukan subdomain terpisah untuk setiap aplikasi. - Bebas Konflik Cookie/Session: Cookie PHP (
PHPSESSID) dapat dipisah lingkup path-nya dengan aman. - Tanpa Mengubah Path Relatif Code: Karena proxy Nginx melakukan rewrite prefix path, relative requests di browser (seperti
src/api/...) tetap berjalan dengan aman.
Rekomendasi Struktur Folder Root (Monorepo):
sig-uas/ # Workspace Root
├── docker-compose.yml # Orkestrasi seluruh service (Nginx, App 1, App 2, MySQL)
├── init-db.sql # Inisialisasi awal database
├── nginx.conf # Konfigurasi reverse proxy dan landing page
├── landing-page/ # Folder Landing Page utama
│ ├── index.html # File HTML Landing Page premium
│ └── style.css # Styling Landing Page
├── poverty-mapping/ # Project 1
│ ├── Dockerfile
│ └── ...
└── tugas-spbu/ # Project 2
├── Dockerfile
└── ...
3. Persiapan Deployment (Readiness Audit)
Berikut adalah daftar temuan kritis yang wajib diperbaiki sebelum melakukan deployment:
| Temuan Masalah | Lokasi File | Tingkat Risiko | Dampak & Rekomendasi Perbaikan |
|---|---|---|---|
| Kredensial Gmail Riil | poverty-mapping/.env |
CRITICAL | Terungkap SMTP_USER dan SMTP_PASS (App Password Gmail) secara tertulis di workspace. Hapus file .env dari upload repositori Git (masukkan ke .gitignore) dan masukkan password sebagai secrets di Coolify. |
| Database Kredensial Hardcoded | tugas-spbu/src/config/koneksi.php |
HIGH | Koneksi menggunakan parameter string statik. Ubah agar membaca dari environment variables (getenv()) dengan fallback ke konfigurasi lokal. |
| API Key Hilang di Frontend | tugas-spbu/index.html |
HIGH | JavaScript mencoba membaca variabel API_KEY global yang tidak pernah di-declare di script. Seluruh request mutasi akan ditolak API backend. Tambahkan pop-up input API Key di halaman untuk admin atau simpan di localStorage. |
| Penyimpanan Foto Gagal | poverty-mapping/src/api/upload_photo.php |
MEDIUM | Folder uploads/ di server produksi harus dapat ditulisi oleh user web server (www-data). Perlu dipastikan folder di-mount dengan volume Docker yang memiliki hak akses 775. |
Expose File Dotfiles (.env, .git) |
Root / Project folders | HIGH | Jika server web salah konfigurasi, file .env dapat diunduh publik. Konfigurasikan Nginx/Apache untuk memblokir akses ke berkas tersembunyi (~ /\.(?!well-known)). |
4. Analisis Keamanan (Security Audit)
Kami melakukan audit mendalam terhadap API dan frontend dari kedua aplikasi:
A. SQL Injection (Risiko: LOW)
- Temuan: Baik
poverty-mappingmaupuntugas-spbutelah menggunakan prepared statement ($conn->preparedan$stmt->bind_param) untuk semua endpoint yang memproses data masukan pengguna. - Rekomendasi: Pertahankan standar ini. Hindari interpolasi string langsung (seperti
"$user_input") dalam query SQL.
B. Stored XSS - Cross-Site Scripting (Risiko: HIGH)
- Temuan: Di
tugas-spbu/index.html, data lokasi yang diambil dari database dirender langsung ke dalam popups Leaflet tanpa escaping:Jika penyerang menyisipkan nama lokasi sepertimarker.bindPopup(`<b>${item.nama}</b><br>...<div ...>${alamatEsc}</div>`);<img src=x onerror=alert(document.cookie)>, script tersebut akan tereksekusi pada browser setiap pengunjung yang mengklik marker tersebut. - Rekomendasi: Buat fungsi pembantu
escapeHtml()ditugas-spbu/index.htmlseperti yang sudah ada dipoverty-mapping/index.html:Bungkus seluruh output variabel pengguna (function escapeHtml(str) { return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'"); }item.nama,item.alamat) dengan fungsi tersebut saat melakukanbindPopup.
C. CSRF - Cross-Site Request Forgery (Risiko: MEDIUM)
- Temuan: Endpoint API di
poverty-mappingdapat membaca autentikasi dari$_SESSION['jwt'](cookie-based). Karena tidak ada token anti-CSRF pada request mutasi, situs pihak ketiga yang dibuka di tab browser yang sama dapat memaksa browser mengirimkan request mutasi berotentikasi. - Rekomendasi: Ubah API untuk hanya menerima otentikasi melalui header HTTP
Authorization: Bearer <token>(tidak membaca session cookie untuk API sensitif), karena header Authorization tidak akan ditransmisikan secara otomatis oleh browser pada request lintas situs (cross-site).
D. File Upload Security (Risiko: MEDIUM)
- Temuan: Di
poverty-mapping/src/api/upload_photo.php, tipe file diverifikasi menggunakan MIME detection (finfo_file). Namun, sanitation filename:Akan mengganti karakter titik ($safeName = preg_replace('/[^a-zA-Z0-9_-]/','_',basename($file['name']));.) dengan underscore (_), sehingga ekstensi file akan hilang (misalgambar.jpgmenjadigambar_jpg). Hal ini aman dari eksekusi script PHP liar, tetapi dapat mengganggu pembacaan file gambar oleh browser jika web server tidak mengirimkan header Content-Type yang tepat. - Rekomendasi: Pisahkan proses sanitasi nama berkas dengan tetap mempertahankan ekstensi aslinya secara terpisah di bagian akhir nama berkas:
$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)); if (!in_array($ext, ['jpg', 'jpeg', 'png', 'gif', 'webp'])) { /* reject */ } $safeName = preg_replace('/[^a-zA-Z0-9_-]/', '_', pathinfo($file['name'], PATHINFO_FILENAME)) . '.' . $ext;
5. Analisis Database
Kedua project menggunakan database dengan nama default webgis pada repositori asal mereka. Namun, keduanya memiliki struktur tabel lokasi yang berbeda:
poverty-mapping.lokasi: Menggunakan primary keyid INT AUTO_INCREMENTdan menyimpan data KK, status kemiskinan, jumlah anggota keluarga, pendapatan, serta status bantuan sosial.tugas-spbu.lokasi: Menggunakan primary keyid VARCHAR(8)(UUID pendek) dan dirancang untuk memetakan koordinat SPBU, Masjid, dan Rumah.
Rekomendasi Solusi:
- Pemisahan Database: Wajib dipisahkan menjadi dua database berbeda di server database MySQL yang sama:
- Database 1:
poverty_db(untuk Poverty Mapping) - Database 2:
spbu_db(untuk Tugas SPBU)
- Database 1:
- Struktur Environment:
- Di server produksi, buat satu container MySQL yang menampung kedua database tersebut.
- Konfigurasikan masing-masing aplikasi melalui environment variable
DB_NAMEuntuk menunjuk ke database yang bersesuaian.
6. Analisis Docker
Sangat direkomendasikan untuk menggunakan Docker demi portabilitas dan kemudahan deployment di Coolify.
Kelebihan Menggunakan Docker:
- Konsistensi: Menjamin PHP 8.x dan modul
mysqliterinstal dengan tepat di server tanpa perlu konfigurasi OS manual. - Isolasi Dependensi: Folder
uploadsdan file konfigurasi terisolasi penuh. - Kemudahan Coolify: Coolify secara native mendukung deployment berbasis Docker Compose. Kita hanya perlu mengarahkan Coolify ke repositori Git kita, dan Coolify akan membangun lingkungan lengkap secara otomatis.
Rencana File Docker & Compose:
A. Dockerfile untuk poverty-mapping (poverty-mapping/Dockerfile)
FROM php:8.2-apache
# Install ekstensi mysqli untuk PHP
RUN docker-php-ext-install mysqli && docker-php-ext-enable mysqli
# Aktifkan mod_rewrite Apache untuk menangani routing .htaccess jika ada
RUN a2enmod rewrite
# Salin source code project ke dalam container
COPY . /var/www/html/
# Atur hak akses direktori uploads agar web server bisa menulis file foto
RUN chown -R www-data:www-data /var/www/html && chmod -R 775 /var/www/html/uploads
# Expose port 80
EXPOSE 80
B. Dockerfile untuk tugas-spbu (tugas-spbu/Dockerfile)
FROM php:8.2-apache
# Install ekstensi mysqli
RUN docker-php-ext-install mysqli && docker-php-ext-enable mysqli
# Salin source code
COPY . /var/www/html/
# Atur hak akses
RUN chown -R www-data:www-data /var/www/html
EXPOSE 80
C. Root docker-compose.yml
version: '3.8'
services:
# 1. Reverse Proxy & Landing Page
landing-page:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./landing-page:/usr/share/nginx/html:ro
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- poverty-mapping
- tugas-spbu
restart: always
# 2. Poverty Mapping Application
poverty-mapping:
build:
context: ./poverty-mapping
dockerfile: Dockerfile
environment:
- DB_HOST=db
- DB_PORT=3306
- DB_USER=webgis_user
- DB_PASS=${DB_PASSWORD}
- DB_NAME=poverty_db
- API_KEY=${POVERTY_API_KEY}
- JWT_SECRET=${JWT_SECRET}
- INTERNAL_AUTH_KEY=${INTERNAL_AUTH_KEY}
- BASIC_API_USER=webgis-api
- BASIC_API_PASS=${BASIC_API_PASS}
- SMTP_HOST=smtp.gmail.com
- SMTP_PORT=587
- SMTP_USER=${SMTP_USER}
- SMTP_PASS=${SMTP_PASS}
- SMTP_ENCRYPTION=tls
- MAIL_FROM=${SMTP_USER}
- MAIL_FROM_NAME=PovertyMapping
volumes:
- poverty_uploads:/var/www/html/uploads
depends_on:
- db
restart: always
# 3. Tugas SPBU Application
tugas-spbu:
build:
context: ./tugas-spbu
dockerfile: Dockerfile
environment:
- DB_HOST=db
- DB_PORT=3306
- DB_USER=webgis_user
- DB_PASS=${DB_PASSWORD}
- DB_NAME=spbu_db
- API_KEY=${SPBU_API_KEY}
depends_on:
- db
restart: always
# 4. Database MySQL
db:
image: mysql:8.0
command: --default-authentication-plugin=mysql_native_password
environment:
- MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
- MYSQL_DATABASE=poverty_db
- MYSQL_USER=webgis_user
- MYSQL_PASSWORD=${DB_PASSWORD}
volumes:
- mysql_data:/var/lib/mysql
- ./init-db.sql:/docker-entrypoint-initdb.d/init-db.sql
restart: always
volumes:
mysql_data:
poverty_uploads:
D. Nginx Config (nginx.conf)
server {
listen 80;
server_name localhost;
# 1. Landing Page Utama
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ =404;
}
# 2. Route ke Poverty Mapping App
location /poverty-mapping/ {
proxy_pass http://poverty-mapping:80/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Scope cookies ke subpath agar tidak tabrakan session PHP-nya
proxy_cookie_path / /poverty-mapping/;
}
# 3. Route ke Tugas SPBU App
location /tugas-spbu/ {
proxy_pass http://tugas-spbu:80/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cookie_path / /tugas-spbu/;
}
# Blokir akses ke file .env / .git secara global di level proxy
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
}
7. Identifikasi Role dan Akun Demo
Untuk memudahkan proses penilaian oleh Dosen, berikut adalah daftar peran (role) yang teridentifikasi beserta rancangan akun demonya.
Daftar Peran (Roles):
- Admin (Poverty Mapping): Memiliki akses penuh terhadap visualisasi peta kemiskinan, serta persetujuan pembuatan akun manager baru.
- Manager (Poverty Mapping): Memiliki akses untuk menambah lokasi keluarga miskin, mengubah data kemiskinan, serta mengunggah foto bukti penyerahan bantuan sosial.
- Guest / Publik (Poverty Mapping): Hanya bisa melihat data peta dengan pembatasan/masking pada kolom sensitif (seperti Nama Kepala Keluarga, No Telepon, Catatan internal bantuan).
- Admin SPBU (Tugas SPBU): Menggunakan token
API_KEYuntuk menambah, mengedit, atau menghapus data spasial jalan, tanah, dan lokasi SPBU.
Daftar Akun Demo (Password: password):
| Aplikasi | Role | Email / Akun | Password | Catatan Kredensial |
|---|---|---|---|---|
| Poverty Mapping | Admin | admin@example.com |
password |
Akun administrator utama untuk persetujuan akun Manager. |
| Poverty Mapping | Manager | manager@example.com |
password |
Perwakilan role Manager untuk penambahan/pengeditan data kemiskinan. |
| Tugas SPBU | Admin | Token/Key | 8f3b7e6a9c4d2f1a6b8c9d0e4f7a1b2c |
Berupa token API_KEY yang di-input ke panel admin SPBU. |
Mekanisme Seed SQL (init-db.sql):
Ketika container MySQL dibangun pertama kali, script ini akan secara otomatis membuat kedua database, mengatur tabel awal, dan menaruh data akun demo dengan hash password yang valid untuk kata sandi "password" (yaitu $2y$10$7YbX4D/QUo1OFJw.ZxyDl.plX03wY/7POuPNx3/ZfyX0vWwaKPNR.):
-- Buat database jika belum ada
CREATE DATABASE IF NOT EXISTS poverty_db;
CREATE DATABASE IF NOT EXISTS spbu_db;
-- Pindah ke database poverty_db untuk inisialisasi tabel users dan admin default
USE poverty_db;
CREATE TABLE IF NOT EXISTS users (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
email VARCHAR(255) NOT NULL,
password_hash VARCHAR(255) NOT NULL,
name VARCHAR(255) DEFAULT NULL,
organization VARCHAR(255) DEFAULT NULL,
org_address TEXT DEFAULT NULL,
org_phone VARCHAR(32) DEFAULT NULL,
org_proof_path VARCHAR(255) DEFAULT NULL,
role ENUM('manager','admin') NOT NULL DEFAULT 'manager',
status ENUM('pending','active','rejected','pending_verification') NOT NULL DEFAULT 'pending',
email_verified TINYINT(1) NOT NULL DEFAULT 0,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY uq_users_email (email)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Insert akun demo Admin & Manager (Password: password)
INSERT INTO users (email, password_hash, name, organization, role, status, email_verified)
VALUES
('admin@example.com', '$2y$10$7YbX4D/QUo1OFJw.ZxyDl.plX03wY/7POuPNx3/ZfyX0vWwaKPNR.', 'Admin Demo', 'SIG WebGIS', 'admin', 'active', 1),
('manager@example.com', '$2y$10$7YbX4D/QUo1OFJw.ZxyDl.plX03wY/7POuPNx3/ZfyX0vWwaKPNR.', 'Manager Demo', 'Pemberdayaan Masyarakat', 'manager', 'active', 1)
ON DUPLICATE KEY UPDATE password_hash = VALUES(password_hash), status = 'active';
8. Langkah Rencana Deployment Lengkap
Berikut adalah workflow deployment lengkap dari repositori lokal ke server Coolify:
Langkah 1: Persiapan Repositori Git & Gitea
- Inisialisasi Git Lokal:
Di root folder
/media/ilham/data/Code/sig-uas/, jalankan:git init - Konfigurasi
.gitignore: Buat file.gitignoredi root folder untuk mencegah data rahasia masuk repositori:# Mengabaikan file environment lokal **/.env **/vendor/ **/node_modules/ .idea/ .vscode/ - Commit Code:
git add . git commit -m "Initial commit for SIG UAS unified project" - Buat Repositori Baru di Gitea:
- Login ke akun Gitea Anda.
- Pilih New Repository, beri nama
sig-uas. - Salin URL remote git (contoh:
http://gitea.domain.com/user/sig-uas.git).
- Push ke Gitea:
git remote add origin <URL_GITEA> git branch -M main git push -u origin main
Langkah 2: Setup Database & Environment Variables di Coolify
- Login ke dashboard Coolify Anda.
- Pilih / buat Project baru untuk SIG UAS.
- Sebelum meluncurkan container aplikasi, definisikan variabel environment (Secrets) yang dibutuhkan dalam menu konfigurasi environment di Coolify:
DB_ROOT_PASSWORD: Password root MySQL (bebas & aman).DB_PASSWORD: Password user database MySQL.POVERTY_API_KEY: API Key acak untuk Poverty Mapping.SPBU_API_KEY: API Key acak untuk SPBU (8f3b7e6a9c4d2f1a6b8c9d0e4f7a1b2cjika ingin mencocokkan default frontend).JWT_SECRET: Secret key JWT acak.INTERNAL_AUTH_KEY: Key autentikasi internal acak.SMTP_USER: Alamat Gmail pengirim notifikasi.SMTP_PASS: App password akun Gmail pengirim.
Langkah 3: Setup Project di Coolify (Deployment)
- Di dalam Project Coolify, klik Add Resource -> Docker Compose.
- Masukkan detail Git Gitea Anda (Coolify akan menggunakan SSH key atau Credentials untuk membaca repositori).
- Masukkan path ke
docker-compose.yml(secara default diisi./docker-compose.yml). - Coolify secara otomatis membaca file compose tersebut.
- Konfigurasikan Domains pada service
landing-pagedi panel Coolify (misal:https://sig.domain.com). Coolify akan secara otomatis membuatkan sertifikat SSL gratis menggunakan Let's Encrypt dan merutekannya ke port 80 milik servicelanding-page. - Klik Deploy. Coolify akan:
- Melakukan pull source code dari Gitea.
- Membangun gambar Docker untuk Poverty Mapping dan Tugas SPBU.
- Menyalakan database MySQL dan menjalankan inisialisasi SQL dari
init-db.sql. - Menghidupkan proxy Nginx dan Landing Page.
Langkah 4: Pengujian Pasca Deployment (Testing)
- Akses Domain: Buka
https://sig.domain.comuntuk memastikan landing page premium tampil. - Navigasi Poverty Mapping:
- Buka
https://sig.domain.com/poverty-mapping/. - Klik Masuk dan login dengan akun demo
admin@example.com(password:password). - Uji penambahan pin peta kemiskinan dan unggah foto.
- Buka
- Navigasi SPBU:
- Buka
https://sig.domain.com/tugas-spbu/. - Uji kelancaran data spasial jalan, tanah, dan titik lokasi SPBU yang dimuat secara otomatis dari database.
- Buka
Langkah 5: Skema Backup dan Rollback
- Backup Database & Data Volume:
- Coolify menyediakan fitur backup database MySQL bawaan yang berjalan secara periodik. Pastikan fitur ini diaktifkan dengan tujuan ke S3 storage atau direktori lokal server.
- Volume
poverty_uploadsyang menyimpan gambar-gambar bukti foto kemiskinan disimpan di/var/lib/docker/volumes/pada host. Folder ini harus dimasukkan ke daftar rutin backup server.
- Rollback Cepat:
- Jika terjadi masalah saat rilis pembaruan baru, buka tab Deployments di Coolify untuk service tersebut, lalu klik tombol Redeploy pada versi commit stabil sebelumnya.
- Coolify akan langsung mematikan container yang bermasalah dan menghidupkan kembali container berbasis image stabil sebelumnya dalam waktu kurang dari 10 detik.