flawopen.com/Type Juggling/PHP ==
Apakah PHP == aman untuk membandingkan hash?
Tidak. Dengan ==, PHP membandingkan dua string numerik sebagai angka, sehingga string berbeda dalam notasi ilmiah dapat sama bahkan pada PHP 8. Validasi tipe input. Gunakan === untuk nilai persis dan hash_equals() untuk token rahasia atau MAC agar tidak membocorkan waktu yang bergantung pada isi.
<?php // Both strings are numeric and represent zero $storedHash = "0e462097431906509019562988736854"; $submittedHash = "0e987654321"; // == returns true on PHP 7 and PHP 8 if ($storedHash == $submittedHash) { login(); } // Request data may also have the wrong type: $submitted = $_POST['token'] ?? null; if ($storedHash == $submitted) { login(); } // ?token[]=x supplies an array, not a string.
<?php
$submitted = $_POST['token'] ?? null;
if (!is_string($submitted)) {
http_response_code(400);
exit;
}
// For secret tokens or MACs:
$tokenIsValid = hash_equals($storedToken, $submitted);
if ($tokenIsValid) {
login();
}
// For non-secret identifiers, strict
// comparison checks both type and value:
$idsMatch = ($expectedId === $submitted);
// Passwords require password_verify(),
// not a hand-written hash comparison:
$passwordIsValid = password_verify($plain, $storedPasswordHash);
Masalah “Magic Hash”
PHP membandingkan dua string numerik secara numerik sebelum maupun sesudah PHP 8. Hash heksadesimal yang diawali 0e dan diikuti hanya angka adalah string notasi ilmiah valid yang bernilai nol. Contohnya, 0e462097431906509019562988736854 dan 0e987654321 berbeda, tetapi keduanya bernilai nol sehingga sama dengan ==. PHP 8 mengubah perbandingan string-ke-angka, bukan kasus dua string numerik ini.
PHP 8 mengubah perbandingan angka dengan string nonnumerik: sekarang bentuk string dibandingkan, bukan string dianggap nol. Perbandingan klasik antara dua string numerik 0e… tetap ada. Jangan gunakan == untuk autentikasi pada versi PHP mana pun.
Tipe permintaan adalah bagian dari batas kepercayaan
Parameter permintaan belum tentu string. Query seperti ?token[]=x menghasilkan array. Mengirimnya ke API string dapat menimbulkan type error atau alur yang tidak diharapkan, bergantung pada versi PHP dan fungsinya. Pastikan nilainya string di batas permintaan sebelum membandingkan atau memanggil hash_equals().
Pertahanan yang tahan lama memiliki dua langkah: validasi tipe di batas, lalu pilih perbandingan sesuai kebutuhan. === memeriksa tipe dan nilai; hash_equals() membandingkan string rahasia tanpa kebocoran waktu yang bergantung pada isi.
Pertanyaan umum
Tidak. PHP 8 mengubah perbandingan string-ke-angka, tetapi dua string numerik tetap dibandingkan sebagai angka. String 0e… yang berbeda masih dapat sama. Gunakan === untuk nilai bertipe persis atau hash_equals() untuk rahasia, dan validasi tipe di semua versi yang didukung.
PHP mendokumentasikan hash_equals() sebagai aman terhadap serangan waktu pada isi string; perbandingan biasa dapat berbeda durasinya menurut letak perbedaan. Berikan rahasia yang diketahui sebagai argumen pertama dan string pengguna sebagai argumen kedua. Gunakan password_verify() untuk kata sandi.
JavaScript juga memiliki kejutan pada ==, sehingga === biasanya direkomendasikan. Bentuk Magic Hash khusus ini berasal dari perbandingan string heksadesimal dan notasi ilmiah di PHP.