Lewati ke konten

CodeIgniter 4 Shieldv1.2.x

Instalasi

Panduan ini mengantar Anda dari aplikasi CodeIgniter 4 yang masih polos sampai CodeIgniter 4 Shield aktif sebelum router dan mencatat kejadian, dalam sekitar 15 menit.

  • PHP ^8.2 atau lebih baru
  • Composer
  • CodeIgniter 4 4.7.5 (baseline yang didokumentasikan)
  • Database yang sudah terhubung ke aplikasi Anda
Terminal window
composer require ganadev/codeigniter4-shield

codeigniter4-shield menarik ganadev/shield-core secara otomatis, jadi Anda tidak perlu memasang core sendiri.

CodeIgniter 4 tidak menemukan service provider secara otomatis seperti Laravel, jadi satu baris kecil perlu ditambahkan. Buka app/Config/Events.php dan tambahkan:

Events::on('pre_system', static function (): void {
\Ganadev\Shield\Codeigniter\ShieldServiceProvider::register();
});

Satu baris ini mendaftarkan tiga hal:

  1. Service Shield — engine, resolver, cache, dan driver challenge.
  2. Alias filter shield.firewall.
  3. Filter firewall — ditempatkan di globals['before'] secara default.

Penting: globals['before'] berjalan setelah router. Artinya request ke path yang tidak punya route (mis. /.env, /wp-login.php, atau path acak) tidak diperiksa oleh filter default. Langkah 3 dan 4 memindahkan Shield ke required['before'] agar request 404/scanner tetap diperiksa sebelum router — itu setup default yang dipakai dokumentasi ini. Detail urutan filternya ada di Registrasi & Urutan Filter.

Kalau Anda sengaja ingin memakai filter global saja, Langkah 4 boleh dilewati. Konsekuensinya: path tanpa route tidak akan diperiksa Shield.

Panggilan berulang aman — provider membangun ulang service dari konfigurasi terkini setiap kali.

Perintah php spark shield:* tidak perlu didaftarkan manual. Kalau aplikasi punya app/Config/Commands.php, provider mendaftarkan command ke sana. Kalau tidak (appstarter CI4 umumnya tidak punya file itu), CodeIgniter menemukannya otomatis dengan memindai namespace PSR-4 package.

Langkah 3 — Siapkan konfigurasi dan path publik

Section titled “Langkah 3 — Siapkan konfigurasi dan path publik”

Shield sudah punya nilai default yang aman. Namun gateSkipPaths adalah array dan tidak bisa diatur lewat .env, jadi buat app/Config/Shield.php minimal seperti ini:

<?php
namespace Config;
class Shield extends \Ganadev\Shield\Codeigniter\Config\Shield
{
public string $appId = 'my-app';
/**
* Path publik yang tetap diperiksa Shield, tetapi tidak menambah behavior
* counter saat diakses normal dengan GET/HEAD.
*
* Ini bukan daftar bypass. Ban, challenge, dan rule enforcement tetap
* berlaku.
*
* @var list<string>
*/
public array $gateSkipPaths = [
'/',
'/health',
'/robots.txt',
'/sitemap.xml',
'/favicon.ico',
];
}

Sesuaikan daftar path dengan halaman publik aplikasi Anda. Jangan masukkan endpoint yang menangani data sensitif atau submit form.

Untuk nilai scalar, cukup tambahkan ke .env dengan prefix huruf kecil. CodeIgniter 4 memetakannya otomatis lewat BaseConfig:

shield_mode = observe
shield_appId = my-app
shield_challengeDriver = null

Jangan memakai SHIELD_MODE atau SHIELD_CHALLENGE; nama uppercase itu tidak dibaca otomatis untuk properti config. Penjelasan lengkap ada di Environment & .env.

Langkah 4 — Jalankan Shield sebelum router

Section titled “Langkah 4 — Jalankan Shield sebelum router”

Langkah ini membuat Shield berjalan sebelum router, termasuk untuk request yang tidak punya route. Lakukan ketiga bagian berikut sebelum menyalakan ulang aplikasi.

Buat app/Filters/ShieldGateFilter.php. Kode lengkapnya ada di Registrasi & Urutan Filter — Buat ShieldGateFilter. Salin seluruh kelas, bukan hanya method before().

Filter ini bertugas:

  • menjalankan SecurityFirewallFilter sebelum router,
  • mengembalikan behavior counter untuk halaman publik yang diizinkan,
  • tetap menegakkan ban/challenge yang sudah ada,
  • menghitung 404 sebelum router lewat after().

Di app/Config/Filters.php, tambahkan alias dan tempatkan shield.gate di required:

use App\Filters\ShieldGateFilter;
public array $aliases = [
// ...
'shield.gate' => ShieldGateFilter::class,
];
public array $required = [
'before' => [
'forcehttps', // hapus kalau aplikasi tidak memakai ForceHTTPS
'shield.gate', // Shield sebelum router
'pagecache', // hapus kalau aplikasi tidak memakai PageCache
],
'after' => [
'pagecache',
'performance',
'toolbar',
'shield.gate', // hitung 404 sebelum router
],
];

Pertahankan filter lain yang sudah ada di aplikasi Anda. Urutan forcehttps → shield.gate → pagecache penting: PageCache tidak boleh berjalan sebelum Shield.

4.3 Hapus shield.firewall dari global filter

Section titled “4.3 Hapus shield.firewall dari global filter”

Provider menambahkan shield.firewall ke globals['before']. Karena sekarang Shield dipanggil lewat shield.gate, hapus penempatan global itu agar request tidak diperiksa dua kali. Edit app/Config/Events.php:

Events::on('pre_system', static function (): void {
\Ganadev\Shield\Codeigniter\ShieldServiceProvider::register();
/*
* Provider memasang Shield sebagai filter global, yang berjalan setelah
* routing. Kita memakai App\Filters\ShieldGateFilter di required filter
* agar path tanpa route juga diperiksa. Hapus yang global supaya request
* tidak diperiksa dua kali.
*/
$filters = config('Filters');
$filters->globals['before'] = array_values(array_filter(
$filters->globals['before'] ?? [],
static fn ($alias): bool => $alias !== 'shield.firewall',
));
});

Kalau app/Config/Events.php Anda sudah berisi kode lain, gabungkan potongan di atas dengan isi yang sudah ada; jangan menimpa seluruh file.

Terminal window
php spark migrate --all

Perintah ini membuat dua tabel:

Tabel Isi
security_ip_bans Ban aktif dan riwayat durasi.
security_events Catatan setiap peristiwa keamanan.

Ini bagian penting: semua penghitung dan ban berbasis IP klien. Kalau aplikasi di belakang proxy/load balancer (termasuk Cloudflare), isi proxyIPs di app/Config/App.php dengan format asosiatif (IP/Subnet → Header).

Format yang benar sejak CI4 4.3 adalah array asosiatif (CIDR => header):

public array $proxyIPs = [
// Cloudflare IPv4
'173.245.48.0/20' => 'CF-Connecting-IP',
'103.21.244.0/22' => 'CF-Connecting-IP',
'103.22.200.0/22' => 'CF-Connecting-IP',
'103.31.4.0/22' => 'CF-Connecting-IP',
'141.101.64.0/18' => 'CF-Connecting-IP',
'108.162.192.0/18' => 'CF-Connecting-IP',
'190.93.240.0/20' => 'CF-Connecting-IP',
'188.114.96.0/20' => 'CF-Connecting-IP',
'197.234.240.0/22' => 'CF-Connecting-IP',
'198.41.128.0/17' => 'CF-Connecting-IP',
'162.158.0.0/15' => 'CF-Connecting-IP',
'104.16.0.0/13' => 'CF-Connecting-IP',
'104.24.0/14' => 'CF-Connecting-IP',
'172.64.0.0/13' => 'CF-Connecting-IP',
'131.0.72.0/22' => 'CF-Connecting-IP',
// Cloudflare IPv6
'2400:cb00::/32' => 'CF-Connecting-IP',
'2606:4700::/32' => 'CF-Connecting-IP',
'2803:f800::/32' => 'CF-Connecting-IP',
'2405:b500::/32' => 'CF-Connecting-IP',
'2405:8100::/32' => 'CF-Connecting-IP',
'2a06:98c0::/29' => 'CF-Connecting-IP',
'2c0f:f248::/32' => 'CF-Connecting-IP',
];

Kalau Anda tidak memakai Cloudflare, ganti dengan CIDR proxy Anda sendiri. Daftar resmi Cloudflare ada di https://www.cloudflare.com/ips/.

Saat mengembangkan config, nonaktifkan cache di app/Config/Optimize.php agar perubahan tidak tertahan cache:

public bool $configCacheEnabled = false;
public bool $locatorCacheEnabled = false;

Ini tidak menghapus kebutuhan restart php spark serve; server built-in adalah satu proses panjang dan .env sudah dimuat saat proses mulai.

Route shield/challenge dan shield/challenge/verify dimuat dari Config/Routes.php paket. Jangan menambahkan route manual dengan nama controller yang berbeda; route bawaan memakai method GET dan POST serta nama controller yang benar.

Cookie trusted pada ChallengeController selalu memakai secure: true. Di HTTP murni, CodeIgniter dapat melempar SecurityException saat response dikirim. Gunakan HTTPS untuk challenge, atau driver null selama development lokal.

Terminal window
php spark serve

Periksa urutan filter terlebih dahulu:

Terminal window
php spark filter:check GET /

Yang diharapkan: forcehttps → shield.gate → pagecache (sesuaikan dengan filter yang benar-benar dipakai aplikasi Anda). Kalau shield.gate tidak muncul, periksa kembali Langkah 4.

Lalu periksa apakah semua komponen sehat:

Terminal window
php spark shield:health

Perintah ini memeriksa koneksi database, cache, mesin Shield, konfigurasi trusted proxy, dan resolusi DNS untuk verifikasi crawler.

shield:prune menghapus event lama, ban berstatus released yang sudah lewat expiry, dan semua baris berstatus expired. Ban active yang sudah melewati expires_at tidak diubah oleh perintah ini. Tidak ada scheduler bawaan di CodeIgniter, jadi host Anda yang menjalankan. Tambahkan cron berikut:

Terminal window
* * * * * cd /path/ke/aplikasi && php spark shield:prune >> /dev/null 2>&1

Tanpa cron itu, tabel security_events akan tumbuh tanpa batas.

Jangan langsung masuk ke mode enforce. Urutan yang aman:

  1. Mode observe selama 1–3 hari. Shield mencatat, tidak memblokir.
  2. Baca shield:report. Cari rule yang sering memicu tanpa alasan, atau IP asli yang ikut tercatat.
  3. Naikkan mode ke challenge. Pantau apakah pengunjung bisa lolos.
  4. Naikkan mode ke enforce. Lakukan setelah false positive terkendali.
  5. Atur durasi ban. banDurations dibaca sesuai urutan offense; escalationStep menambah skor risiko, bukan memperpanjang durasi ban.

Setiap tahap, periksa event blokir/ban dan lakukan manual release bila ada pengunjung asli yang ikut kena. Tidak ada metrik “challenge pass rate” di shield:report; gunakan laporan event dan log aplikasi.

Filter Shield bekerja apa adanya, tanpa bergantung pada paket auth apa pun. Paket auth resmi (codeigniter4/shield) hanya diperlukan kalau Anda ingin memakai panel admin dengan pembatasan izin.

Powered by PT Ganadev Multi Solusi