Penyalahgunaan penyertaan
1. Penyebab kerentanan:
Sertakan adalah fungsi yang paling umum digunakan dalam menulis situs web PHP dan mendukung jalur relatif. Ada banyak skrip PHP yang secara langsung menggunakan variabel input sebagai parameter Sertakan, menyebabkan kerentanan seperti referensi skrip arbitrer dan kebocoran jalur absolut. Lihatlah kode berikut:
...
$includepage=$_GET["includepage"];
include($termasukhalaman);
...
Tentunya kita hanya perlu mengirimkan variabel Includepage yang berbeda untuk mendapatkan halaman yang diinginkan. Jika Anda mengirimkan halaman yang tidak ada, Anda dapat menyebabkan skrip PHP error dan membocorkan jalur absolut sebenarnya (solusi untuk masalah ini dijelaskan di artikel berikut).
2. Penyelesaian kerentanan:
Solusi untuk kerentanan ini sangat sederhana, yaitu menentukan terlebih dahulu apakah halaman tersebut ada dan kemudian memasukkannya. Atau lebih tepatnya, gunakan array untuk menentukan file yang dapat dimasukkan. Lihatlah kode berikut:
$pagelist=array("test1.php","test2.php","test3.php"); //Ini menentukan file yang dapat dimasukkan
if(isset($_GET["includepage"])) //Tentukan apakah ada $includepage
{
$includepage=$_GET["includepage"];
foreach($daftar halaman sebagai $prepage)
{
if($includepage==$prepage) //Periksa apakah file ada dalam daftar yang diizinkan
{
include($persiapan);
$checkfind=benar;
merusak;
}
}
if($checkfind==true){ tidak disetel($checkfind);
else{ die("Halaman referensi tidak valid!" }
}
Ini akan menyelesaikan masalah dengan baik.
Tip: Fungsi dengan masalah ini meliputi: require(), require_once(), include_once(), readfile(), dll. Anda juga harus memperhatikan saat menulis.
Variabel masukan tidak difilter
1. Penyebab kerentanan:
Kerentanan ini telah lama muncul di ASP, menyebabkan kerentanan injeksi yang tak terhitung jumlahnya pada saat itu. Namun karena PHP memiliki pengaruh yang kecil pada saat itu, tidak banyak orang yang bisa memperhatikan hal ini. Untuk PHP, dampak kerentanan ini lebih besar dibandingkan dengan ASP, karena lebih banyak skrip PHP yang menggunakan database teks. Tentu saja, ada juga masalah injeksi pernyataan SQL. Untuk memberikan contoh yang lebih klasik, yang pertama adalah database:
$id=$_GET["id"];
$query="SELECT * FROM my_table Where id='".$id."'"; //Kerentanan injeksi SQL yang sangat klasik
$hasil=mysql_query($query);
Jelas di sini bahwa kita dapat menggunakan injeksi untuk mendapatkan konten database lainnya. Saya tidak akan menjelaskannya secara rinci di sini. Sama seperti injeksi ASP, Anda dapat melihat pertahanan hitam sebelumnya. Lalu kita melihat masalah database teks:
$teks1=$_POST["teks1"];
$teks2=$_POST["teks2"];
$teks3=$_POST["teks3"];
$fd=fopen("test.php","a");
fwrite($fd,"rn$text1&line;$text2&line;$text3");
fclose($fd);
Kerentanan teks ini bisa dibilang lebih serius. Jika kita memasukkan sepotong kecil kode PHP ke dalam variabel yang dikirimkan, kita dapat mengubah database teks test.php ini menjadi pintu belakang PHP. Bahkan memasukkan kode unggahan memungkinkan kita mengunggah backdoor PHP lengkap. Kemudian tingkatkan hak istimewa dan server menjadi milik Anda.
2. Penyelesaian kerentanan:
Solusi untuk kerentanan ini sebenarnya sangat sederhana, yaitu memfilter secara ketat semua variabel yang dikirimkan. Ganti beberapa karakter sensitif. Kita dapat mengganti konten HTML dengan bantuan fungsi htmlspecialchars() yang disediakan oleh PHP. Berikut ini contohnya:
//Bangun fungsi filter www.knowsky.com
fungsi flt_tags($teks)
{
$badwords=array("Persetan","persetan"); //Daftar filter kata
$teks=rtrim($teks);
foreach($badwords as $badword) //Filter kosakata di sini
{
if(stristr($text,$badword)==true){ die("Kesalahan: Konten yang Anda kirimkan mengandung kata-kata sensitif, mohon jangan mengirimkan konten sensitif." }
}
$text=htmlspecialchars($text); //penggantian HTML
//Kedua baris ini menggantikan carriage return dengan
$text=str_replace("r","
",$teks);
$teks=str_replace("n","",$teks);
$text=str_replace("&line;","│",$text); //Ganti pemisah database teks "&line;" dengan "│" lebar penuh
$text=preg_replace("/s{ 2 }/"," ",$teks); //penggantian spasi
$text=preg_replace("/t/"," ",$text); // Masih mengganti spasi
if(get_magic_quotes_gpc()){ $text=stripslashes($text); //Jika magic_quotes diaktifkan, ganti '
kembalikan $teks;
}
$teks1=$_POST["teks1"];
$teks2=$_POST["teks2"];
$text3=$_POST["text3"];
//Filter semua masukan
$teks1=flt_tags($teks1);
$teks2=flt_tags($teks2);
$text3=flt_tags($text3);
$fd=fopen("test.php","a");
fwrite($fd,"rn$text1&line;$text2&line;$text3");
fclose($fd);
Setelah beberapa penggantian dan pemfilteran, Anda dapat dengan aman menulis data ke teks atau database.
Penilaian administrator tidak lengkap
1. Penyebab kerentanan:
Kami menggunakan PHP untuk menulis skrip, yang biasanya melibatkan izin administrator. Beberapa skrip hanya membuat penilaian "ya" pada izin administrator, namun sering mengabaikan penilaian "tidak". Ketika register_globals diaktifkan di file konfigurasi PHP (dinonaktifkan secara default di versi setelah 4.2.0, tetapi banyak orang mengaktifkannya untuk kenyamanan, yang merupakan perilaku yang sangat berbahaya), akan ada situasi di mana variabel dikirimkan untuk meniru identitas administrator. Mari kita lihat contoh kodenya:
$cookiesign="admincookiesign"; //Tentukan apakah variabel cookie Admin
$adminsign=$_COOKIE["sign"]; //Dapatkan variabel cookie pengguna
if($adminsign==$cookiesign)
{
$admin=benar;
}
if($admin){ echo "Anda sekarang adalah administrator.";
Kelihatannya sangat aman, haha. Sekarang kita asumsikan register_globals diaktifkan di file konfigurasi PHP. Kami mengirimkan alamat seperti "test.php?admin=true", sudahkah Anda melihat hasilnya? Walaupun kita tidak mempunyai cookie yang benar, karena register_globals diaktifkan, variabel admin yang kita kirimkan secara otomatis terdaftar sebagai true. Selain itu, skrip ini tidak memiliki penilaian "tidak", yang memungkinkan kami berhasil mendapatkan izin administrator melalui admin=true. Masalah ini terjadi di sebagian besar situs web dan forum.
2. Penyelesaian kerentanan:
Untuk mengatasi masalah ini, kita hanya perlu menambahkan penilaian "tidak" kepada administrator di skrip. Kami masih berasumsi bahwa register_globals diaktifkan di file konfigurasi PHP. Lihatlah kodenya:
$cookiesign="admincookiesign"; //Tentukan apakah variabel cookie Admin
$adminsign=$_COOKIE["sign"]; //Dapatkan variabel cookie pengguna
if($adminsign==$cookiesign)
{
$admin=benar;
}
kalau tidak
{
$admin=salah;
}
if($admin){ echo "Anda sekarang adalah administrator."; }
Dengan cara ini, bahkan jika penyerang mengirimkan variabel admin=true tanpa cookie yang benar, skrip akan menetapkan $admin ke False dalam penilaian selanjutnya. Ini memecahkan sebagian dari masalah. Namun, karena $admin adalah variabel, jika terjadi celah pada referensi skrip lain di masa mendatang dan $admin ditugaskan kembali, krisis baru akan terjadi. Oleh karena itu, kita harus menggunakan konstanta untuk menyimpan penentuan izin administrator. Gunakan pernyataan Define() untuk mendefinisikan konstanta admin untuk mencatat izin administrator. Jika ditugaskan kembali setelah ini, kesalahan akan terjadi, sehingga mencapai tujuan perlindungan. Lihatlah kode berikut:
$cookiesign="admincookiesign"; //Tentukan apakah variabel cookie Admin
$adminsign=$_COOKIE["sign"]; //Dapatkan variabel cookie pengguna
if($adminsign==$cookiesign)
{
definisikan(admin,benar);
}
kalau tidak
{
definisikan(admin,salah);
}
if(admin){ echo "Anda sekarang berstatus administrator.";
Perlu diperhatikan bahwa kita menggunakan pernyataan Define, jadi saat memanggil konstanta Admin, jangan biasa menambahkan simbol variabel $ di depan, tetapi gunakan Admin dan !admin.
Basis data teks terbuka
1. Penyebab kerentanan:
Seperti disebutkan sebelumnya, karena fleksibilitas database teks yang tinggi, tidak diperlukan dukungan eksternal. Selain itu, PHP mempunyai kemampuan pemrosesan file yang sangat kuat, sehingga database teks banyak digunakan dalam skrip PHP. Bahkan ada beberapa program forum bagus yang menggunakan database teks. Namun ada untung dan ruginya, dan keamanan database teks lebih rendah dibandingkan database lainnya.
2. Penyelesaian kerentanan:
Basis data teks bertindak sebagai file biasa, yang dapat diunduh, seperti halnya MDB. Oleh karena itu, kita perlu melindungi database teks dengan cara yang sama seperti MDB. Ubah nama akhiran database teks menjadi .PHP. dan bergabung di baris pertama database. Dengan cara ini database teks akan diperlakukan sebagai file PHP dan eksekusi akan keluar pada baris pertama. Artinya, halaman kosong dikembalikan untuk mencapai tujuan melindungi database teks.
Jalan yang salah bocor
1. Penyebab kerentanan:
Ketika PHP menemui kesalahan, ia akan memberikan lokasi, nomor baris dan alasan skrip kesalahan tersebut, misalnya:
Pemberitahuan: Penggunaan pengujian konstanta yang tidak terdefinisi - diasumsikan 'tes' di D:interpubbigflytest.php pada baris 3
Banyak orang bilang itu bukan masalah besar. Namun konsekuensi dari kebocoran jalur sebenarnya tidak terbayangkan. Bagi beberapa penyusup, informasi ini sangat penting. Faktanya, banyak server sekarang mengalami masalah ini.
Beberapa administrator jaringan hanya mengatur display_errors di file konfigurasi PHP ke Off untuk menyelesaikan masalah, tapi menurut saya metode ini terlalu negatif. Terkadang, kita sangat membutuhkan PHP untuk mengembalikan informasi kesalahan untuk debugging. Dan ketika terjadi kesalahan, Anda mungkin juga perlu memberikan penjelasan kepada pengguna atau bahkan membuka halaman lain.
2. Penyelesaian kerentanan:
PHP telah menyediakan fungsi penanganan kesalahan khusus set_error_handler() sejak 4.1.0, tetapi hanya sedikit penulis skrip yang mengetahuinya. Di antara banyak forum PHP, saya melihat hanya sedikit yang menangani situasi ini. Penggunaan set_error_handler adalah sebagai berikut:
string set_error_handler ( panggilan balik error_handler [, int error_types])
Sekarang kami menggunakan penanganan kesalahan khusus untuk memfilter jalur sebenarnya.
//Admin adalah penentu identitas administrator, benar adalah administrator.
//Fungsi penanganan kesalahan khusus harus memiliki empat variabel input berikut $errno, $errstr, $errfile, $errline, jika tidak maka tidak valid.
fungsi my_error_handler($errno,$errstr,$errfile,$errline)
{
//Jika Anda bukan administrator, filter jalur sebenarnya
jika(!admin)
{
$errfile=str_replace(getcwd(),"",$errfile);
$errstr=str_replace(getcwd(),"",$errstr);
}
beralih($errno)
{
kasus E_ERROR:
echo "KESALAHAN: [ID $errno] $errstr (Baris: $errline dari $errfile)
N";
echo "Program berhenti berjalan, silakan hubungi administrator.";
//Keluar dari skrip ketika menemui kesalahan tingkat Error
KELUAR;
istirahat;
kasus E_PERINGATAN:
echo "PERINGATAN: [ID $errno] $errstr (Baris: $errline dari $errfile)
N";
istirahat
;
//Jangan tampilkan kesalahan tingkat Pemberitahuan
merusak;
}
}
//Atur penanganan kesalahan ke fungsi my_error_handler
set_error_handler("handler_error_saya");
…
Dengan cara ini, kontradiksi antara keamanan dan kenyamanan debugging dapat diselesaikan dengan baik. Dan Anda juga dapat memikirkan untuk membuat pesan kesalahan menjadi lebih indah agar sesuai dengan gaya situs web. Namun perhatikan dua hal:
(1) E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, dan E_COMPILE_WARNING tidak akan diproses oleh pegangan ini, artinya akan ditampilkan dengan cara yang paling orisinal. Namun, kesalahan ini disebabkan oleh kesalahan kompilasi atau kernel PHP dan tidak akan terjadi dalam keadaan normal.
(2) Setelah menggunakan set_error_handler(), error_reporting() akan menjadi tidak valid. Artinya, semua kesalahan (kecuali kesalahan yang disebutkan di atas) akan diserahkan ke fungsi kustom untuk diproses.
Untuk informasi lain tentang set_error_handler(), Anda dapat merujuk ke manual resmi PHP.
Kerentanan POST
1. Penyebab kerentanan:
Seperti disebutkan sebelumnya, mengandalkan register_globals untuk mendaftarkan variabel adalah kebiasaan buruk. Dalam beberapa program buku tamu dan forum, lebih penting lagi untuk memeriksa secara ketat metode perolehan halaman dan interval waktu antar pengiriman. Untuk mencegah postingan spam dan kiriman eksternal. Mari kita lihat kode program buku tamu berikut ini:
...
$teks1=flt_tags($teks1);
$teks2=flt_tags($teks2);
$teks3=flt_tags($teks3);
$fd=fopen("data.php","a");
fwrite($fd,"rn$text1&line;$text2&line;$text3");
fclose($fd);
...
Tentunya jika kita mengirimkan URL "post.php?text1=testhaha&text2=testhaha&text3=testhaha". Data akan ditulis ke file secara normal. Program ini tidak mendeteksi sumber variabel dan bagaimana browser memperoleh halaman tersebut. Jika kita mengirimkan banyak kiriman ke halaman ini, maka akan menyebabkan banjir. Ada juga beberapa software yang memanfaatkan kerentanan ini untuk memasang iklan di forum atau buku tamu, yang merupakan perilaku yang memalukan (buku tamu teman saya kebanjiran lebih dari 10 halaman dalam satu minggu, yang tidak berdaya).
2. Penyelesaian kerentanan:
Sebelum memproses dan menyimpan data, tentukan terlebih dahulu bagaimana browser memperoleh halaman tersebut. Gunakan variabel $_SERVER["REQUEST_METHOD"] untuk mendapatkan metode browser dalam memperoleh halaman. Periksa apakah itu "POST". Gunakan sesi dalam skrip untuk mencatat apakah pengguna mengirimkan data melalui saluran normal (yaitu, halaman tempat konten pengiriman diisi). Atau gunakan $_SERVER["HTTP_REFERER"] untuk mendeteksi ini, tetapi ini tidak disarankan. Karena beberapa browser tidak menyetel REFERER, beberapa firewall juga akan memblokir REFERER. Selain itu, kita juga perlu memeriksa konten yang dikirimkan untuk melihat apakah ada duplikat konten di database. Ambil contoh buku tamu, gunakan Session untuk menentukan:
Di halaman tempat Anda mengisi konten penelusuran, kami menambahkan di bagian depan:
$_SESSION["allowgbookpost"]=time(); //Waktu pengisian pendaftaran. Di halaman tempat data pesan diterima dan disimpan, kami juga menggunakan Session untuk melakukan pemrosesan berikut sebelum pemrosesan data:
if(strtoupper($_SERVER["REQUEST_METHOD"])!="POST"){ die("Error: Jangan kirim secara eksternal."); } //Periksa apakah metode akuisisi halaman adalah POST
if(!isset($_SESSION["allowgbookpost"]) or (time()-$_SESSION["allowgbookpost"] < 10)){ die("Error: Jangan kirim secara eksternal."); //Periksa pesannya Waktu saat mengisi
if(isset($_SESSION["gbookposttime"]) and (time()-$_SESSION["gbookposttime"] < 120)){ die("Error: Interval antara dua pengiriman pesan tidak boleh kurang dari 2 menit. "); } //Periksa interval pesan
unset($_SESSION["allowgbookpost"]); //Batalkan registrasi variabelallowgbookpost untuk mencegah beberapa kiriman masuk ke halaman pengisian sekaligus
$_SESSION["gbookposttime"]=time(); //Daftarkan waktu pengiriman pesan untuk mencegah spam atau serangan jahat
...
Pemrosesan dan penyimpanan data
...
Setelah beberapa kali peninjauan, program Anda akan jauh lebih aman.