Apa fungsi sanitasi input PHP terbaik?

161

Saya mencoba untuk datang dengan fungsi yang saya bisa melewati semua string saya untuk membersihkan. Sehingga string yang keluar akan aman untuk penyisipan basis data. Tetapi ada begitu banyak fungsi penyaringan di luar sana saya tidak yakin mana yang harus saya gunakan / butuhkan.

Tolong bantu saya mengisi bagian yang kosong:

function filterThis($string) {
    $string = mysql_real_escape_string($string);
    $string = htmlentities($string);
    etc...
    return $string;
}
Lauren
sumber
4
untuk penyisipan, tidak apa-apa untuk membersihkan sanitasi dari injeksi SQL menggunakan mysql_real_escape_string. Ketika Anda menggunakan data SELECTed (dalam output html atau dalam formula / fungsi php) Anda harus menerapkan htmlentities
davidosomething
Lihat stackoverflow.com/questions/60174/… untuk jawaban spesifik untuk pembersihan untuk penyisipan basis data (ini memberikan contoh PDO, yang orang lain telah sebutkan di bawah).
Pat

Jawaban:

433

Berhenti!

Anda membuat kesalahan di sini. Oh, tidak, Anda sudah memilih fungsi PHP yang tepat untuk membuat data Anda sedikit lebih aman. Tidak apa-apa. Kesalahan Anda adalah dalam urutan operasi , dan bagaimana dan di mana menggunakan fungsi-fungsi ini.

Penting untuk memahami perbedaan antara membersihkan dan memvalidasi data pengguna, melarikan diri data untuk penyimpanan, dan melarikan diri data untuk presentasi.

Sanitasi dan Validasi Data Pengguna

Saat pengguna mengirimkan data, Anda perlu memastikan bahwa mereka telah memberikan sesuatu yang Anda harapkan.

Sanitasi dan Penyaringan

Misalnya, jika Anda mengharapkan nomor, pastikan data yang dikirimkan adalah angka . Anda juga bisa memasukkan data pengguna ke tipe lain. Segala sesuatu yang dikirimkan pada awalnya diperlakukan seperti string, sehingga memaksa data numerik yang dikenal menjadi bilangan bulat atau float membuat sanitasi menjadi cepat dan tidak menyakitkan.

Bagaimana dengan bidang teks bentuk bebas dan bidang teks? Anda perlu memastikan bahwa tidak ada yang tak terduga di bidang itu. Terutama, Anda perlu memastikan bahwa bidang yang seharusnya tidak memiliki konten HTML sebenarnya tidak mengandung HTML. Ada dua cara untuk mengatasi masalah ini.

Pertama, Anda dapat mencoba melarikan diri dengan masukan HTML htmlspecialchars. Anda sebaiknya tidak menggunakan htmlentitiesuntuk menetralkan HTML, karena itu juga akan melakukan pengkodean aksen dan karakter lain yang menurutnya juga perlu dikodekan.

Kedua, Anda dapat mencoba menghapus HTML apa pun yang mungkin. strip_tagscepat dan mudah, tetapi juga ceroboh. HTML Purifier melakukan pekerjaan yang jauh lebih menyeluruh baik dari menghapus semua HTML dan juga memungkinkan daftar putih dari tag dan atribut.

Versi PHP modern dikirimkan dengan ekstensi filter , yang menyediakan cara komprehensif untuk membersihkan input pengguna.

Validasi

Memastikan bahwa data yang dikirimkan bebas dari konten yang tidak terduga hanya setengah dari pekerjaan. Anda juga perlu mencoba dan memastikan bahwa data yang dikirim mengandung nilai yang benar-benar dapat Anda gunakan.

Jika Anda mengharapkan angka antara 1 dan 10, Anda perlu memeriksa nilai itu. Jika Anda menggunakan salah satu input angka era HTML5 mewah baru dengan pemintal dan langkah-langkah, pastikan bahwa data yang dikirimkan sesuai dengan langkah tersebut.

Jika data itu berasal dari apa yang seharusnya menjadi menu tarik-turun, pastikan bahwa nilai yang dikirimkan adalah yang muncul di menu.

Bagaimana dengan input teks yang memenuhi kebutuhan lain? Misalnya, input tanggal harus divalidasi melalui strtotimeatau kelas DateTime . Tanggal yang diberikan harus antara rentang yang Anda harapkan. Bagaimana dengan alamat email? Ekstensi filter yang disebutkan sebelumnya dapat memeriksa apakah suatu alamat terbentuk dengan baik, meskipun saya penggemar perpustakaan is_email .

Hal yang sama berlaku untuk semua kontrol bentuk lainnya. Punya tombol radio? Validasikan terhadap daftar. Punya kotak centang? Validasikan terhadap daftar. Punya file unggah? Pastikan file tersebut dari tipe yang diharapkan, dan perlakukan nama file seperti data pengguna tanpa filter.

Setiap peramban modern hadir dengan seperangkat alat pengembang lengkap yang terpasang di dalamnya, yang membuatnya sepele bagi siapa saja untuk memanipulasi formulir Anda. Kode Anda harus mengasumsikan bahwa pengguna telah sepenuhnya menghapus semua batasan sisi klien pada konten formulir !

Melarikan Data untuk Penyimpanan

Sekarang setelah Anda memastikan bahwa data Anda dalam format yang diharapkan dan hanya berisi nilai-nilai yang diharapkan, Anda perlu khawatir tentang mempertahankan data tersebut untuk disimpan.

Setiap mekanisme penyimpanan data tunggal memiliki cara khusus untuk memastikan data lolos dengan benar dan disandikan. Jika Anda sedang membangun SQL, maka cara yang diterima untuk meneruskan data dalam kueri adalah melalui pernyataan yang disiapkan dengan placeholder .

Salah satu cara yang lebih baik untuk bekerja dengan sebagian besar database SQL di PHP adalah ekstensi PDO . Ini mengikuti pola umum menyiapkan pernyataan , mengikat variabel ke pernyataan , kemudian mengirim pernyataan dan variabel ke server . Jika Anda belum pernah bekerja dengan PDO sebelumnya, inilah tutorial berorientasi MySQL yang cukup bagus .

Beberapa database SQL memiliki ekstensi khusus mereka sendiri di PHP, termasuk SQL Server , PostgreSQL dan SQLite 3 . Masing-masing ekstensi tersebut telah menyiapkan dukungan pernyataan yang beroperasi dengan cara persiapan-bind-eksekusi yang sama dengan PDO. Terkadang Anda mungkin perlu menggunakan ekstensi ini alih-alih PDO untuk mendukung fitur atau perilaku non-standar.

MySQL juga memiliki ekstensi PHP sendiri. Dua dari mereka, sebenarnya. Anda hanya ingin menggunakan yang disebut mysqli . Ekstensi "mysql" lama telah usang dan tidak aman atau waras untuk digunakan di era modern.

Saya pribadi bukan penggemar mysqli. Cara itu melakukan pengikatan variabel pada pernyataan yang disiapkan tidak fleksibel dan bisa menjadi sulit untuk digunakan. Jika ragu, gunakan PDO sebagai gantinya.

Jika Anda tidak menggunakan basis data SQL untuk menyimpan data Anda, periksa dokumentasi untuk antarmuka basis data yang Anda gunakan untuk menentukan cara melewati data dengan aman.

Jika memungkinkan, pastikan bahwa database Anda menyimpan data Anda dalam format yang sesuai. Simpan angka dalam bidang angka. Simpan tanggal di bidang tanggal. Menyimpan uang dalam bidang desimal, bukan bidang floating point. Tinjau dokumentasi yang disediakan oleh database Anda tentang cara menyimpan berbagai tipe data dengan benar.

Melarikan Data untuk Presentasi

Setiap kali Anda menampilkan data kepada pengguna, Anda harus memastikan bahwa data tersebut lolos dengan aman, kecuali jika Anda tahu bahwa data itu tidak boleh melarikan diri.

Saat memancarkan HTML, Anda harus selalu melewati data apa pun yang semula dipasok oleh pengguna htmlspecialchars. Bahkan, satu-satunya waktu Anda tidak boleh melakukan ini adalah ketika Anda tahu bahwa pengguna menyediakan HTML, dan Anda tahu bahwa itu sudah dibersihkan dengan menggunakan daftar putih.

Terkadang Anda perlu membuat beberapa Javascript menggunakan PHP. Javascript tidak memiliki aturan pelolosan yang sama dengan HTML! Cara aman untuk memberikan nilai yang diberikan pengguna ke Javascript melalui PHP adalah melalui json_encode.

Dan lagi

Ada banyak lagi nuansa ke validasi data.

Sebagai contoh, pengkodean karakter dapat menjadi perangkap besar . Aplikasi Anda harus mengikuti praktik yang dijabarkan dalam " UTF-8 all through through ". Ada serangan hipotetis yang dapat terjadi ketika Anda memperlakukan data string sebagai rangkaian karakter yang salah.

Sebelumnya saya menyebutkan alat debug browser. Alat-alat ini juga dapat digunakan untuk memanipulasi data cookie. Cookie harus diperlakukan sebagai input pengguna yang tidak dipercaya .

Validasi dan pelolosan data hanya satu aspek dari keamanan aplikasi web. Anda harus membuat diri Anda sadar akan metodologi serangan aplikasi web sehingga Anda dapat membangun pertahanan terhadap mereka.

Charles
sumber
Dan ketika menentukannya, pastikan itu ada dalam daftar penyandian yang didukung.
Charles
3
Dan jangan menggunakan htmlentities sama sekali, ganti dengan htmlspecialchars dengan tujuan mengganti saja <>, tidak setiap karakter pada entitas itu
Your Common Sense
6
Pastikan untuk tidak menelepon htmlspecialcharsdua kali, karena ia membicarakannya di bagian "Saat pengguna mengirimkan data" dan di bagian "Saat menampilkan data".
Savageman
2
Terpilih. Jawaban paling membantu yang pernah saya baca dari banyak T&J tentang SQL Injection.
akinuri
Benar-benar jawaban Berkualitas dengan banyak penjelasan dan tautan untuk pengguna di masa mendatang untuk menjelajahi lebih banyak opsi. Mendapat satu-up dari saya juga ...
James Walker
32

Sanitasi yang paling efektif untuk mencegah injeksi SQL adalah menggunakan parameterisasi PDO. Menggunakan kueri parameter, kueri dipisahkan dari data, sehingga menghilangkan ancaman injeksi SQL orde pertama.

Dalam hal menghapus HTML, strip_tagsmungkin merupakan ide terbaik untuk menghapus HTML, karena hanya akan menghapus semuanya. htmlentitiesmelakukan apa yang terdengar, sehingga berfungsi juga. Jika Anda perlu mengurai HTML mana yang diizinkan (yaitu, Anda ingin mengizinkan beberapa tag), Anda harus menggunakan parser yang sudah ada seperti Pemurni HTML

Derek H
sumber
2
Ya ampun, saya menulis tembok teks raksasa itu hanya karena saya tidak melihat ada yang menyebut HTML Purifier, dan di sini Anda mengalahkan saya sekitar 40 menit. ;)
Charles
3
Bukankah seharusnya Anda hanya menghapus HTML pada output? IMO Anda tidak boleh mengubah data input - Anda tidak pernah tahu kapan Anda akan membutuhkannya
Joe Phillips
11

Input Basis Data - Bagaimana mencegah SQL Injection

  1. Periksa untuk memastikan data tipe integer, misalnya, valid dengan memastikan itu benar-benar bilangan bulat
    • Dalam kasus non-string Anda perlu memastikan bahwa data sebenarnya adalah tipe yang benar
    • Dalam hal string, Anda perlu memastikan string dikelilingi oleh tanda kutip dalam kueri (jelas, jika tidak, string itu tidak akan berfungsi)
  2. Masukkan nilai ke dalam database sambil menghindari injeksi SQL (mysql_real_escape_string atau kueri parameterisasi)
  3. Ketika Mengambil nilai dari database pastikan untuk menghindari serangan Cross Site Scripting dengan memastikan HTML tidak dapat disuntikkan ke halaman (htmlspecialchars)

Anda harus menghindari input pengguna sebelum memasukkan atau memperbaruinya ke dalam basis data. Ini cara yang lebih tua untuk melakukannya. Anda ingin menggunakan query parameter sekarang (mungkin dari kelas PDO).

$mysql['username'] = mysql_real_escape_string($clean['username']);
$sql = "SELECT * FROM userlist WHERE username = '{$mysql['username']}'";
$result = mysql_query($sql);

Output dari database - Bagaimana mencegah XSS (Cross Site Scripting)

Gunakan htmlspecialchars()hanya saat mengeluarkan data dari database. Hal yang sama berlaku untuk Pemurni HTML. Contoh:

$html['username'] = htmlspecialchars($clean['username'])

Dan Akhirnya ... apa yang Anda minta

Saya harus menunjukkan bahwa jika Anda menggunakan objek PDO dengan query parameter (cara yang tepat untuk melakukannya) maka sebenarnya tidak ada cara mudah untuk mencapai ini dengan mudah. Tetapi jika Anda menggunakan cara 'mysql' lama maka inilah yang Anda butuhkan.

function filterThis($string) {
    return mysql_real_escape_string($string);
}
Joe Phillips
sumber
5

5 sen saya.

Tidak ada yang mengerti cara mysql_real_escape_stringkerjanya. Fungsi ini tidak memfilter atau "membersihkan" apapun.
Jadi, Anda tidak dapat menggunakan fungsi ini karena beberapa filter universal yang akan menyelamatkan Anda dari injeksi.
Anda dapat menggunakannya hanya ketika Anda memahami cara kerjanya dan di mana itu berlaku.

Saya punya jawaban untuk pertanyaan yang sangat mirip yang sudah saya tulis: Di PHP ketika mengirimkan string ke database haruskah saya menangani karakter ilegal menggunakan htmlspecialchars () atau menggunakan ekspresi reguler?
Silakan klik untuk penjelasan lengkap untuk keamanan sisi basis data.

Adapun htmlentities - Charles benar memberitahu Anda untuk memisahkan fungsi-fungsi ini.
Bayangkan saja Anda akan memasukkan data, yang dihasilkan oleh admin, yang diizinkan memposting HTML. fungsi Anda akan merusaknya.

Meskipun saya akan menyarankan agar htmlentities. Fungsi ini menjadi usang sejak lama. Jika Anda ingin mengganti hanya <, >dan "karakter dalam demi keselamatan HTML - menggunakan fungsi yang dikembangkan sengaja untuk tujuan itu - sebuah htmlspecialchars () satu.

Akal Sehat Anda
sumber
1
mysql_real_escape_stringlolos dari karakter yang diperlukan di dalam string. Ini tidak sepenuhnya menyaring atau membersihkan, tetapi melampirkan string dalam tanda kutip juga tidak (dan semua orang melakukannya, saya hampir tidak pernah melihat pertanyaan tentang itu). Jadi tidak ada yang disanitasi ketika kita menulis SQL? Tentu saja tidak. Apa yang mencegah injeksi SQL adalah penggunaan mysql_real_escape_string. Juga kutipan terlampir, tetapi semua orang melakukannya, dan jika Anda menguji apa yang Anda lakukan, Anda berakhir dengan kesalahan sintaks SQL dengan kelalaian ini. Bagian yang sangat berbahaya ditangani mysql_real_escape_string.
Savageman
@Savageman maaf sobat, Anda tidak mengerti apa-apa. Anda tidak mengerti cara mysql_real_escape_string bekerja. "Karakter yang diperlukan" ini ADALAH kutipan. Bukan fungsi ini atau kutipan saja membersihkan apa pun. 2 hal ini hanya bekerja bersama . Membuat string kueri hanya benar secara sintaksis, bukan "aman dari injeksi". Dan kesalahan sintaks apa yang akan saya dapatkan hanya WHERE id = 1? ;)
Akal Sehat Anda
Coba WHERE my_field = two words(tanpa tanda kutip) untuk mendapatkan kesalahan sintaksis. Contoh Anda buruk karena tidak perlu mengutip atau melarikan diri, hanya cek numerik. Juga saya tidak mengatakan bahwa kutipan itu tidak berguna. Saya mengatakan semua orang menggunakannya jadi ini bukan sumber masalah tentang injeksi SQL.
Savageman
1
@ Savageman jadi, yang saya katakan: Anda dapat menggunakannya hanya ketika Anda memahami cara kerjanya dan di mana itu berlaku. Anda baru saja mengakui bahwa mysql_real_escape_string tidak berlaku di mana-mana. Adapun everyone use themAnda dapat memeriksa kode di sini di SO. Banyak orang tidak menggunakan tanda kutip dengan angka. Sosok pergi. Tolong, ingatlah bahwa saya tidak membahas di sini apa yang Anda katakan dan mengapa Anda tidak. Saya hanya menjelaskan aturan keamanan basis data dasar. Anda sebaiknya belajar daripada berdebat kosong. Tidak ada yang menyebutkan kutipan atau casting di sini tetapi m_r_e_s hanya seolah-olah itu ajaib. Apa yang saya bicarakan
Your Common Sense
1
satu ke atas, serta @Charles. Sebagai pemula, interaksi basis data ... membuat hal-hal aman untuk input dan tampilan, karakter khusus, masalah injeksi, telah menjadi kurva pembelajaran yang sangat curam. Membaca posting Anda dan jawabannya (serta jawaban PHP Anda yang lain untuk pertanyaan lain, telah sangat membantu saya. Tx untuk semua masukan Anda.
James Walker
2

Untuk penyisipan basis data, yang Anda butuhkan adalah mysql_real_escape_string(atau gunakan kueri parameterisasi). Anda biasanya tidak ingin mengubah data sebelum menyimpannya, yang akan terjadi jika Anda menggunakannya htmlentities. Itu akan menyebabkan kekacauan kacau nanti ketika Anda menjalankannya htmlentitieslagi untuk menampilkannya di suatu tempat di halaman web.

Gunakan htmlentitiessaat Anda menampilkan data di halaman web di suatu tempat.

Agak terkait, jika Anda mengirim data yang dikirimkan di suatu tempat dalam email, seperti misalnya dengan formulir kontak, pastikan untuk menghapus baris baru dari data apa pun yang akan digunakan di header (seperti Dari: nama dan alamat email, subleksi, dll. )

$input = preg_replace('/\s+/', ' ', $input);

Jika Anda tidak melakukan ini, itu hanya masalah waktu sebelum bot spam menemukan formulir Anda dan menyalahgunakannya, saya telah belajar dengan cara yang sulit.

rampok
sumber
2

Itu tergantung pada jenis data yang Anda gunakan. Yang umum terbaik untuk digunakan adalah mysqli_real_escape_stringtetapi, misalnya, Anda tahu tidak akan ada konten HTML, menggunakan strip_tags akan menambah keamanan ekstra.

Anda juga dapat menghapus karakter yang Anda tahu tidak boleh diizinkan.

Aaron Harun
sumber
1

Saya selalu merekomendasikan untuk menggunakan paket validasi kecil seperti GUMP: https://github.com/Wixel/GUMP

Bangun semua fungsi dasar Anda di sekitar perpustakaan seperti ini dan hampir tidak mungkin untuk melupakan sanitasi. "mysql_real_escape_string" bukan alternatif terbaik untuk penyaringan yang baik (Seperti "Your Common Sense" jelaskan) - dan jika Anda lupa menggunakannya hanya sekali, seluruh sistem Anda akan dapat diserang melalui suntikan dan serangan jahat lainnya.

Simon Schneider
sumber
1

Untuk semua yang berbicara dan mengandalkan mysql_real_escape_string, Anda perlu memperhatikan bahwa fungsi itu sudah tidak digunakan lagi di PHP5 dan tidak lagi ada di PHP7.

IMHO cara terbaik untuk menyelesaikan tugas ini adalah dengan menggunakan query parametrized melalui penggunaan PDO untuk berinteraksi dengan database. Periksa ini: https://phpdelusions.net/pdo_examples/select

Selalu gunakan filter untuk memproses input pengguna. Lihat http://php.net/manual/es/function.filter-input.php

Kuntur
sumber
Ini sebenarnya tidak menjawab pertanyaan. Pertimbangkan untuk memodifikasi jawaban Anda untuk memasukkan solusi.
Keris
Harap Anda menyukainya!
Kuntur
Saya lakukan. Jawaban bagus!
Keris
Saya sarankan untuk mencatat bahwa dalam PHP 7 mysqli_real_escape_string()tersedia.
Chris
Halo Chris, solusi yang diekspos di sini membuat referensi ke mysql_real_escape_string, saya perhatikan yang membaca dari sekarang bahwa itu tidak ada lagi di PHP7 dan mengusulkan alternatif menggunakan PDO (dan filter) bukan mysqli. Jangan ragu untuk menambahkan catatan yang menjelaskan solusi menggunakan apa yang Anda sarankan. Salam
Kuntur
0

Anda menggunakan mysql_real_escape_string () dalam kode yang mirip dengan yang berikut ini.

$query = sprintf("SELECT * FROM users WHERE user='%s' AND password='%s'",
  mysql_real_escape_string($user),
  mysql_real_escape_string($password)
);

Seperti yang dikatakan dalam dokumentasi, tujuannya adalah melepaskan karakter khusus dalam string yang dilewatkan sebagai argumen, dengan mempertimbangkan set karakter koneksi saat ini sehingga aman untuk menempatkannya di mysql_query () . Dokumentasi juga menambahkan:

Jika data biner akan dimasukkan, fungsi ini harus digunakan.

htmlentities () digunakan untuk mengonversi beberapa karakter dalam entitas, saat Anda mengeluarkan string dalam konten HTML.

kiamlaluno
sumber
0

Ini adalah salah satu cara saya saat ini berlatih,

  1. Implan csrf, dan garam menggoda token bersama dengan permintaan yang akan dibuat oleh pengguna, dan memvalidasi semuanya bersama-sama dari permintaan. Rujuk ke Sini
  2. pastikan tidak terlalu mengandalkan cookie sisi klien dan pastikan untuk berlatih menggunakan sesi sisi server
  3. ketika ada parsing data, pastikan untuk hanya menerima tipe data dan metode transfer (seperti POST dan GET)
  4. Pastikan untuk menggunakan SSL untuk webApp / Aplikasi Anda
  5. Pastikan juga membuat permintaan sesi basis waktu untuk membatasi permintaan spam dengan sengaja.
  6. Ketika data diuraikan ke server, pastikan untuk memvalidasi permintaan yang harus dibuat dalam data yang Anda inginkan, seperti json, html, dan lain-lain ... lalu lanjutkan
  7. melarikan diri semua atribut ilegal dari input menggunakan tipe escape ... seperti realescapestring.
  8. setelah itu verifikasi hanya format format data yang Anda inginkan dari pengguna.
    Contoh:
    - Email: periksa apakah input dalam format email yang valid
    - teks / string: Periksa hanya input yang berupa format teks (string)
    - angka: periksa hanya format angka yang diizinkan.
    - dll. Pelase merujuk ke pustaka validasi input php dari portal php
    - Setelah divalidasi, silakan lanjutkan menggunakan pernyataan SQL / PDO yang disiapkan.
    - Setelah selesai, pastikan untuk keluar dan mengakhiri koneksi
    - Jangan lupa untuk menghapus nilai output setelah selesai.

Itu yang saya percaya cukup untuk detik dasar. Seharusnya mencegah semua serangan besar dari hacker.

Untuk keamanan sisi server, Anda mungkin ingin mengatur di apache / htaccess Anda untuk pembatasan akses dan pencegahan robot dan juga pencegahan routing. Ada banyak yang harus dilakukan untuk keamanan sisi server selain detik dari sistem di sisi server.

Anda dapat mempelajari dan mendapatkan salinan detik dari level htaccess apache sec (rpactices umum)

Ahmad Anuar
sumber
0
function sanitize($string,$dbmin,$dbmax){
$string = preg_replace('#[^a-z0-9]#i', '', $string); //useful for strict cleanse, alphanumeric here
$string = mysqli_real_escape_string($con, $string); //get ready for db
if(strlen($string) > $dbmax || strlen($string) < $dbmin){
    echo "reject_this"; exit();
    }
return $string;
}
stkmedia
sumber
0

bagaimana dengan ini

$string = htmlspecialchars(strip_tags($_POST['example']));

atau ini

$string = htmlentities($_POST['example'], ENT_QUOTES, 'UTF-8');
jerryurenaa
sumber