Lewati ke konten

CodeIgniter 4 Shieldv1.2.x

Challenge & Cookie

Challenge adalah jaring pengaman kedua. Kalau Shield menduga sesuatu mencurigakan tetapi belum cukup yakin untuk memblokir, ia mengarahkan pengunjung ke halaman pembuktian. Kalau berhasil, pengunjung dibolehkan melanjutkan dan ditandai sebagai orang yang sudah terbukti.

Challenge muncul ketika skor request berada di antara thresholdChallenge dan thresholdBan di app/Config/Shield.php:

public int $thresholdChallenge = 10; // mulai minta challenge
public int $thresholdBan = 20; // mulai kena ban

Jadi request dengan skor 14 mendapat challenge, bukan ban.

shield.challengeDriver = turnstile
Nilai Driver Kapan dipakai
turnstile Cloudflare Turnstile Pilihan kami. Bagus, cepat, dan punya kuota gratis.
recaptcha / google_recaptcha Google reCAPTCHA v2 (checkbox) Kalau Anda sudah memakai reCAPTCHA di situs.
null / test / 0 / kosong NullTestDriver Development dan pengujian otomatis.

Driver reCAPTCHA memakai widget v2 checkbox (div.g-recaptcha), bukan v3 berbasis skor. Isi SHIELD_RECAPTCHA_SITE_KEY dan SHIELD_RECAPTCHA_SECRET_KEY; tidak ada opsi action/score v3.

Nama properti config adalah challengeDriver, jadi SHIELD_CHALLENGE tidak dibaca — pakai shield.challengeDriver (atau shield_challengeDriver). Nilai yang tidak dikenal tidak melempar error; Shield jatuh ke Turnstile.

Dengan NullTestDriver, verifikasi gagal kecuali token-nya persis test-token. Gunanya untuk development, bukan untuk produksi.

Di dashboard Cloudflare, bagian Turnstile, buat widget dengan tipe Managed. Cloudflare memberi Anda satu site key dan satu secret key.

shield.challengeDriver = turnstile
SHIELD_TURNSTILE_SITE_KEY=0x4AAAAAAA...
SHIELD_TURNSTILE_SECRET_KEY=0x4AAAAAAA...

site key aman untuk ditaruh di HTML — memang itu gunanya. secret key tidak boleh pernah masuk ke repository.

Cloudflare hanya mengirim challenge ke domain yang Anda daftarkan saat membuat widget. Kalau Anda lupa mendaftarkan localhost atau domain staging, widget tidak akan tampil saat development.

Saat pengunjung mengirim token, server Anda meneruskannya ke Cloudflare:

POST https://challenges.cloudflare.com/turnstile/v0/siteverify

Isinya: secret, response (token dari widget), dan remoteip (IP pengunjung, opsional tapi membantu Cloudflare menilai).

Alamat verifikasi bisa diganti kalau Anda mengarahkannya ke server verifikasi sendiri: SHIELD_TURNSTILE_VERIFY_URL (Turnstile) atau SHIELD_RECAPTCHA_VERIFY_URL (reCAPTCHA).

Shield mendaftarkan dua route untuk mekanisme ini (dari Ganadev\Shield\Codeigniter\Config\Routes):

Method Route Nama route Keterangan
GET /shield/challenge shield.challenge Menampilkan widget.
POST /shield/challenge/verify shield.challenge.verify Memverifikasi token dan memasang cookie.
  1. Request mencurigakan → Shield mengarahkan pengunjung ke /shield/challenge?redirect=<tujuan>.
  2. Pengunjung menyelesaikan widget, lalu form mengirim token ke /shield/challenge/verify.
  3. Server memverifikasi token ke Cloudflare/Google.
  4. Kalau gagal, pengunjung dikembalikan ke halaman challenge dengan ?error=1.
  5. Kalau berhasil, Shield memasang trusted cookie, lalu mengarahkan balik ke halaman tujuan.

Satu verifikasi yang sukses melakukan dua hal sekaligus:

  1. Mencabut semua efek ban pada IP tersebut — baris ban aktif di database di-set released, dan request berikutnya tidak lagi di-redirect ke challenge.
  2. Menerbitkan trusted cookie (shield_trusted) yang membuat request berikutnya langsung diizinkan tanpa tantangan lagi selama trustedTtlMinutes.

Setelah lolos, Shield memasang cookie bernama shield_trusted. Atributnya:

Atribut Nilai Untuk apa
HttpOnly aktif JavaScript tidak bisa membacanya.
Secure aktif Hanya dikirim lewat HTTPS.
SameSite Lax Dikirim untuk navigasi tingkat atas saja.

Atribut Secure di-hardcode true oleh ChallengeController, bukan berasal dari config. Karena itu challenge produksi wajib berjalan di HTTPS.

Cookie ini yang membuat pengunjung tidak di-challenge berulang kali selama menjelajah. Masa berlakunya diatur di app/Config/Shield.php:

public int $trustedTtlMinutes = 60;

Setel trustedEnabled ke false kalau Anda ingin setiap request yang mencurigakan selalu di-challenge ulang.

Halaman challenge menerima parameter redirect untuk menentukan tujuan setelah berhasil. Nilainya divalidasi ketat sebelum dipakai:

Masukan Hasil
/produk/123 Dipakai.
https://jahat.example Dibuang, dan pengunjung diarahkan ke /.
//jahat.example Dibuang, karena berarti URL protocol-relative.
/x:y Dibuang, karena terbaca seperti scheme.
\ atau %5c Dinormalkan menjadi /, lalu diperiksa ulang.

Kalau nilai parameter tidak aman, pengunjung diarahkan ke beranda. Ini mencegah attacker memakai challenge sebagai pembuka open redirect.

Tampilan halaman challenge dan blokir dikendalikan di app/Config/Shield.php:

public string $brandingTitle = 'Toko Online Aman';
public string $brandingAccentColor = '#22d3ee';
public string $brandingBackgroundColor = '#0b1220';
public bool $brandingShowRuleId = false;

Bila ingin kendali penuh, salin view bawaan ke aplikasi Anda:

  • vendor/ganadev/codeigniter4-shield/src/Views/shield/challenge.php → app/Views/shield/challenge.php
  • vendor/ganadev/codeigniter4-shield/src/Views/shield/blocked.php → app/Views/shield/blocked.php

Lalu arahkan lewat challengeView / blockedView kalau letaknya berbeda dari itu.

Dengan shield.challengeDriver=null, Anda bisa menguji alur challenge secara deterministik:

Terminal window
curl -i "http://localhost:8080/shield/challenge"

Verifikasi manual dengan token yang benar:

Terminal window
curl -i -X POST http://localhost:8080/shield/challenge/verify \
-d "shield_challenge_token=test-token" \
-d "redirect=/"

Token yang salah akan mengembalikan redirect ke ?error=1.

Gejala Penyebab yang paling mungkin
Widget tidak tampil sama sekali site_key kosong, atau domain Anda belum didaftarkan di Cloudflare.
Selalu gagal verifikasi secret_key salah, atau token kedaluwarsa.
Mengalihkan ke ?error=1 terus-menerus Token tidak terkirim, atau driver di null.
Pengunjung kena challenge berulang Trusted cookie tidak tersimpan — periksa HTTPS dan SameSite.
Semua orang kena challenge Skor perilaku terlalu rendah, atau thresholdChallenge terlalu kecil.

Untuk melihat komponen yang berjalan, gunakan php spark shield:health.

Powered by PT Ganadev Multi Solusi