En iyi PHP giriş temizleme işlevleri nelerdir?


161

Sanitasyon için tüm iplerimi geçirebileceğim bir fonksiyon bulmaya çalışıyorum. Böylece çıkan dize veritabanı ekleme için güvenli olacaktır. Ama orada çok fazla filtreleme işlevi var. Hangisini kullanmam gerektiğine emin değilim.

Lütfen boşlukları doldurmama yardım et:

function filterThis($string) {
    $string = mysql_real_escape_string($string);
    $string = htmlentities($string);
    etc...
    return $string;
}

4
ekleme için, mysql_real_escape_string kullanarak SQL enjeksiyonuna karşı sterilize etmek iyidir. SELECTed verilerini (html çıktısında veya bir php formülünde / işlevinde) kullanırken, htmlentities'i uygulamanız gerekir
davidosomething

Veritabanı eklemeye yönelik temizlemeye özgü bir yanıt için stackoverflow.com/questions/60174/… adresine bakın (diğerlerinin aşağıda belirttiği bir PDO örneği verir).
Pat

Yanıtlar:


433

Dur!

Burada bir hata yapıyorsun. Oh, hayır, verilerinizi biraz daha güvenli hale getirmek için doğru PHP işlevlerini seçtiniz. Bu iyi. Hatanız işlem sırasına ve bu işlevleri nasıl ve nerede kullanacağınıza bağlıdır.

Kullanıcı verilerinin hijyenik hale getirilmesi ve doğrulanması, depolamak için veri çıkışı ile sunum için veri çıkışı arasındaki farkı anlamak önemlidir.

Kullanıcı Verilerini Dezenfekte Etme ve Doğrulama

Kullanıcılar veri gönderdiğinde, beklediğiniz bir şey sağladıklarından emin olmanız gerekir.

Dezenfeksiyon ve Filtreleme

Örneğin, bir sayı bekliyorsanız , gönderilen verilerin bir sayı olduğundan emin olun . Ayrıca kullanıcı verilerini başka türlere de aktarabilirsiniz. Gönderilen her şey başlangıçta bir dize gibi ele alınır, bu nedenle bilinen sayısal verileri bir tamsayı veya şamandıra olmaya zorlamak sanitizasyonu hızlı ve ağrısız hale getirir.

Serbest biçimli metin alanları ve textareas ne olacak? Bu alanlarda beklenmedik bir şey olmadığından emin olmanız gerekir. Temel olarak, HTML içeriği olmaması gereken alanların aslında HTML içermediğinden emin olmanız gerekir. Bu sorunla başa çıkmanın iki yolu vardır.

İlk olarak, HTML girişinden kaçmayı deneyebilirsiniz htmlspecialchars. htmlentitiesHTML'yi etkisiz hale getirmek için kullanmamalısınız , çünkü aksanlı ve kodlanması gerektiğini düşündüğü diğer karakterlerin kodlamasını da yapar.

İkinci olarak, olası herhangi bir HTML'yi kaldırmayı deneyebilirsiniz . strip_tagshızlı ve kolaydır, aynı zamanda özensizdir. HTML Purifier , hem tüm HTML'yi sıyırma hem de etiketlerin ve niteliklerin seçici bir beyaz listesine izin vermenin çok daha kapsamlı bir işini yapar.

Modern PHP sürümleri , kullanıcı girişini sterilize etmek için kapsamlı bir yol sağlayan filtre uzantısı ile birlikte gelir .

onaylama

Gönderilen verilerin beklenmedik içerikten arınmış olduğundan emin olmak işin sadece yarısıdır. Ayrıca gönderilen verilerin gerçekten üzerinde çalışabileceğiniz değerleri içerdiğinden emin olmanız gerekir.

1 ile 10 arasında bir sayı bekliyorsanız, bu değeri kontrol etmeniz gerekir. Bir döndürücü ve adımlarla yeni süslü HTML5 dönemi sayısal girişlerinden birini kullanıyorsanız, gönderilen verilerin adımla uyumlu olduğundan emin olun.

Bu veriler açılır menüden olması gerekiyorsa, gönderilen değerin menüde görünen değer olduğundan emin olun.

Diğer ihtiyaçları karşılayan metin girdileri ne olacak? Örneğin, tarih girişleri strtotimeveya DateTime sınıfı aracılığıyla doğrulanmalıdır . Belirtilen tarih, beklediğiniz aralıklar arasında olmalıdır. E-posta adresleri ne olacak? Daha önce bahsedilen filtre uzantısı , bir adresin iyi biçimlendirildiğini kontrol edebilir, ancak ben is_email kütüphanesinin hayranıyım .

Aynısı diğer tüm form kontrolleri için de geçerlidir . Radyo düğmeleriniz mi var? Listeye göre doğrulayın. Onay kutularınız mı var? Listeye göre doğrulayın. Bir dosya yüklemeniz mi var? Dosyanın beklenen türde olduğundan emin olun ve dosya adına filtre uygulanmamış kullanıcı verileri gibi davranın.

Her modern tarayıcı, herkesin formunuzu manipüle etmesini önemsiz hale getiren tam bir geliştirici araçları seti ile birlikte gelir. Kodunuz, kullanıcının form içeriğiyle ilgili tüm istemci tarafı kısıtlamalarını tamamen kaldırdığını varsaymalıdır !

Depolama için Veriden Kaçış

Verilerinizin beklenen biçimde olduğundan ve yalnızca beklenen değerleri içerdiğinden emin olduğunuza göre, bu verileri depolamaya devam etmek konusunda endişelenmeniz gerekir.

Her bir veri depolama mekanizmasının, verilerin düzgün bir şekilde kaçtığından ve kodlandığından emin olmak için belirli bir yolu vardır. SQL oluşturuyorsanız, sorgularda veri aktarmanın kabul edilen yolu yer tutucularla hazırlanmış ifadelerdir .

PHP'deki çoğu SQL veritabanıyla çalışmanın daha iyi yollarından biri PDO uzantısıdır . Bir deyim hazırlamak , değişkenleri deyime bağlamak , sonra deyimi ve değişkenleri sunucuya göndermek için ortak bir kalıp izler . Daha önce PDO ile çalışmadıysanız, oldukça iyi bir MySQL odaklı eğitim .

Bazı SQL veritabanlarının SQL Server , PostgreSQL ve SQLite 3 dahil olmak üzere kendi özel uzantıları vardır . Bu uzantıların her biri PDO ile aynı hazırla-bağla-yürüt tarzında çalışan açıklama desteği hazırladı. Bazen standart olmayan özellikleri veya davranışları desteklemek için PDO yerine bu uzantıları kullanmanız gerekebilir.

MySQL'in de kendi PHP uzantıları vardır. Aslında ikisi. Sadece mysqli denileni kullanmak istersiniz . Eski "mysql" uzantısı kullanımdan kaldırılmıştır ve modern çağda kullanımı güvenli veya mantıklı değildir.

Ben şahsen mysqli hayranı değilim. Hazırlanan ifadeler üzerinde değişken bağlanma gerçekleştirme şekli esnek değildir ve kullanımı bir acı olabilir. Şüphe duyduğunuzda bunun yerine PDO kullanın.

Verilerinizi saklamak için bir SQL veritabanı kullanmıyorsanız, verilerin nasıl güvenli bir şekilde aktarılacağını belirlemek için kullandığınız veritabanı arabiriminin belgelerine bakın.

Mümkün olduğunda, veritabanınızın verilerinizi uygun bir biçimde sakladığından emin olun. Sayıları sayısal alanlarda saklayın. Tarihleri ​​tarih alanlarında saklayın. Parayı kayan nokta alanında değil ondalık bir alanda saklayın. Farklı veri türlerinin nasıl düzgün bir şekilde saklanacağına ilişkin veritabanınız tarafından sağlanan dokümanları inceleyin.

Sunum için Veriden Kaçış

Kullanıcılara her veri gösterdiğinizde, kaçmaması gerektiğini bilmediğiniz sürece verilerin güvenli bir şekilde kaçtığından emin olmalısınız .

HTML yayınlarken, neredeyse her zaman başlangıçta kullanıcı tarafından sağlanan verileri iletmeniz gerekir htmlspecialchars. Aslında, ne zaman bunu yapmamalıyız tek zamandır biliyoruz kullanıcı HTML sağladığını ve bunu biliyorum zaten bir beyaz liste kullanarak temizlenmiş oldu o.

Bazen PHP kullanarak bazı Javascriptler oluşturmanız gerekir. Javascript HTML ile aynı çıkış kurallarına sahip değil! PHP üzerinden Javascript'e kullanıcı tarafından sağlanan değerler sağlamanın güvenli bir yolu vardır json_encode.

Ve dahası

Veri doğrulamasında çok daha fazla nüans var.

Örneğin, karakter kümesi kodlaması büyük bir tuzak olabilir . Başvurunuz " UTF-8 " de belirtilen uygulamaları izlemelidir . Dize verilerini yanlış karakter kümesi olarak ele aldığınızda oluşabilecek varsayımsal saldırılar vardır.

Daha önce tarayıcı hata ayıklama araçlarından bahsetmiştim. Bu araçlar aynı zamanda çerez verilerini değiştirmek için de kullanılabilir. Çerezler güvenilir olmayan kullanıcı girişi olarak ele alınmalıdır .

Veri doğrulama ve çıkış, web uygulaması güvenliğinin yalnızca bir yönüdür. Kendinize karşı savunma oluşturabilmeniz için web uygulaması saldırı yöntemlerinden haberdar olmalısınız .


Ve belirtirken, desteklenen kodlamalar listesinde olduğundan emin olun.
Charles

3
Ve htmlentities kullanmayın, yerine sadece <>her karakteri değiştirmek için htmlspecialchars ile değiştirin
Common Sense

6
Sadece htmlspecialcharsiki kez aramadığınızdan emin olun , çünkü "Kullanıcılar veri bölümü gönderdiğinde" ve "Verileri görüntülerken" bölümünde konuşur.
Savageman

2
Upvoted. SQL Enjeksiyonu ile ilgili birçok soru-cevaptan okuduğum en yararlı cevap.
akinuri

Gelecekteki kullanıcıların daha fazla seçenek keşfetmesi için birçok açıklama ve bağlantı içeren Kesinlikle bir Kalite yanıtı. Benden de bir tane var ...
James Walker

32

SQL enjeksiyonunu önlemek için en etkili dezenfeksiyon parametre kullanımıdır PDO. Parametrelenmiş sorgular kullanarak, sorgu verilerden ayrılır, böylece birinci dereceden SQL enjeksiyonu tehdidini ortadan kaldırır.

HTML'yi kaldırma açısından strip_tags, muhtemelen her şeyi kaldıracağı için HTML'yi kaldırmak için muhtemelen en iyi fikirdir. htmlentitieskulağa hoş geliyor, bu da işe yarıyor. Hangi HTML'ye izin verileceğini ayrıştırmanız gerekiyorsa (yani, bazı etiketlere izin vermek istiyorsanız ), HTML Temizleyici gibi mevcut bir ayrıştırıcı kullanmalısınız


2
Ah adamım, o dev metin duvarını sadece HTML Arındırıcı'dan bahsetmediğini gördüğüm için yazdım ve burada beni 40 dakika kadar dövüyorsun. ;)
Charles

3
HTML'yi yalnızca çıktıda çıkarmamalısınız? IMO asla giriş verilerini değiştirmemelisiniz - ne zaman ihtiyacınız olacağını asla bilemezsiniz
Joe Phillips

11

Veritabanı Girişi - SQL Enjeksiyonu nasıl önlenir

  1. Örneğin tamsayı türü verilerin gerçekte bir tamsayı olduğundan emin olmak için geçerli olduğundan emin olun
    • Dizgisiz olması durumunda, verilerin gerçekten doğru türde olduğundan emin olmanız gerekir
    • Dizeler durumunda, dizenin sorgudaki tırnak işaretleri ile çevrili olduğundan emin olmanız gerekir (açıkçası, aksi takdirde işe yaramaz)
  2. SQL enjeksiyonundan kaçınırken değeri veritabanına girin (mysql_real_escape_string veya parametreli sorgular)
  3. Veritabanından değer alınırken, HTML'nin sayfaya enjekte edilemediğinden emin olarak Siteler Arası Komut Dosyası saldırılarından kaçının (htmlspecialchars)

Veritabanına eklemeden veya güncellemeden önce kullanıcı girişinden kaçmanız gerekir. İşte bunu yapmanın daha eski bir yolu. Şimdi parametrelenmiş sorguları kullanmak istiyorsunuz (muhtemelen PDO sınıfından).

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

Veritabanından çıktı - XSS (Siteler Arası Komut Dosyası) nasıl önlenir

htmlspecialchars()Yalnızca veritabanından veri çıktısı alırken kullanın . Aynısı HTML Temizleyici için de geçerlidir. Misal:

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

Ve son olarak ... ne istersen

Ben parametreli sorgular ile PDO nesneleri (bunu yapmak için doğru yolu) kullanırsanız o zaman gerçekten bu kolayca elde etmek için kolay bir yol olduğunu belirtmek gerekir. Ancak eski 'mysql' yolunu kullanırsanız, ihtiyacınız olan şey budur.

function filterThis($string) {
    return mysql_real_escape_string($string);
}

5

5 sentim.

Burada kimse nasıl mysql_real_escape_stringçalıştığını anlamıyor . Bu işlev hiçbir şeyi filtrelemez veya "sterilize etmez".
Bu nedenle, bu işlevi sizi enjeksiyondan koruyacak bazı evrensel filtre olarak kullanamazsınız.
Sadece nasıl çalıştığını ve nerede uygulanabilir olduğunu anladığınızda kullanabilirsiniz.

Ben zaten yazdım çok benzer sorunun cevabı var: PHP veritabanına dizeleri gönderirken htmlspecialchars () kullanarak yasadışı karakterleri dikkat çekmek gerekir veya normal bir ifade?
Veritabanı tarafı güvenliği ile ilgili tüm açıklamalar için lütfen tıklayınız.

Htmlentities gelince - Charles size bu işlevleri ayırmak söylüyor.
HTML yayınlamasına izin verilen yönetici tarafından oluşturulan bir veri ekleyeceğinizi düşünün. fonksiyonunuz onu bozacaktır.

Htmlentities karşı tavsiye olsa da. Bu işlev uzun zaman önce kullanımdan kaldırıldı. Eğer değiştirmek istiyorsanız sadece <, >ve "HTML güvenliği uğruna karakterler - bir - bu amaçla kasten geliştirilen işlevini kullanın htmlspecialchars () tek.


1
mysql_real_escape_stringbir dizenin içindeki gerekli karakterlerden kaçar. Kesinlikle süzmek veya sterilize etmek değil, ancak bir dizeyi tırnak içine almak (ve herkes bunu yapıyor, bunun hakkında bir soru görmedim). SQL yazdığımızda hiçbir şey sterilize edilmiyor mu? Tabii ki değil. SQL enjeksiyonunu engelleyen şey kullanımıdır mysql_real_escape_string. Ayrıca tırnak içine alır, ancak herkes bunu yapar ve ne yaptığınızı test ederseniz, bu ihmal ile bir SQL sözdizimi hatasıyla sonuçlanırsınız. Gerçek tehlikeli kısım ele alınır mysql_real_escape_string.
Savageman

@ Savaveman üzgünüm dostum, hiçbir şey anlamadın. Mysql_real_escape_string'in çalışma şeklini anlamıyorsunuz. Bu "gerekli karakterler" alıntıdır. Bu işlev ya da tek başına alıntılar hiçbir şeyi sterilize etmez. Bu 2 şey sadece birlikte çalışır . Sorgu dizesini sözdizimsel olarak doğru yapmak, "enjeksiyondan korumak" değil. Ve hangi sözdizimi hatasını alırım WHERE id = 1? ;)
Yaygın Duygunuz

WHERE my_field = two wordsSözdizimi hatasını almak için (tırnak işaretleri olmadan) deneyin . Örneğiniz kötü çünkü tırnaklardan kaçmaya gerek yok, sadece sayısal bir kontrol. Ayrıca tırnak işe yaramaz demedim. Herkesin bunları kullandığını söyledim, bu SQL enjeksiyonu ile ilgili sorunların kaynağı değil.
Savageman

1
@Savageman öyle dedim ki: Sadece nasıl çalıştığını ve nerede uygulanabilir olduğunu anladığınızda kullanabilirsiniz. Az önce mysql_real_escape_string'in her yerde geçerli olmadığını itiraf ettiniz. Gelince everyone use themburada SO üzerinde kodları kontrol edebilirsiniz. Birçok kişi sayılarla tırnak kullanmaz. Git şekil. Lütfen, söylediklerinizi ve ne yapmayacağınızı burada tartışmayacağımı unutmayın. Sadece temel veritabanı güvenliği kurallarını açıklıyorum. Boş tartışmak yerine öğrensen iyi olur. Kimse alıntılardan veya dökümden bahsetmedi ama m_r_e_s sadece sanki sihirmiş gibi. Ne hakkında konuşuyorum
Your Common Sense

1
Biri yanı sıra @Charles. Bir acemi olarak, veritabanı etkileşimi ... giriş ve görüntüleme için işleri güvenli hale getirmek, Özel karakterler, enjeksiyon sorunları, çok dik bir öğrenme eğrisi olmuştur. Mesajınızı ve onun (ve diğer PHP'nin diğer sorulara verdikleri cevapların) okunması bana çok yardımcı oldu. Tüm girdileriniz için Tx.
James Walker

2

Veritabanı eklemek için tek ihtiyacınız olan şey mysql_real_escape_string(veya parametreli sorguları kullanmak). Genellikle verileri kaydetmeden önce değiştirmek istemezsiniz, yani kullanırsanız ne olur htmlentities. Bu htmlentities, bir web sayfasında bir yerde görüntülemek için tekrar çalıştırdığınızda bozuk bir karışıklığa yol açacaktır .

htmlentitiesVerileri bir web sayfasında bir yerde görüntülerken kullanın .

Bir şekilde, örneğin bir iletişim formunda olduğu gibi, bir e-postanın herhangi bir yerine gönderilen verileri gönderiyorsanız, başlıkta kullanılacak verilerden (Kimden: ad ve e-posta adresi, alt vb. )

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

Bunu yapmazsanız, spam botlarının formunuzu bulup kötüye kullanması sadece bir zaman meselesidir, zor yolu öğrendim.



2

Kullandığınız veri türüne bağlıdır. Kullanılacak en iyi genel yöntem olabilir, mysqli_real_escape_stringancak örneğin, HTML içeriği olmayacağını biliyorsunuz, strip_tags kullanmak ekstra güvenlik ekleyecektir.

İzin verilmemesi gerektiğini bildiğiniz karakterleri de kaldırabilirsiniz.


1

Her zaman GUMP gibi küçük bir doğrulama paketi kullanmanızı öneririm: https://github.com/Wixel/GUMP

Tüm bu temel bir kütüphane etrafında temel fonksiyonları inşa ve sanitasyonu unutmak neredeyse imkansız. "mysql_real_escape_string" iyi filtreleme için en iyi alternatif değildir ("Ortak Aklınız" açıklandığı gibi) - ve sadece bir kez kullanmayı unutursanız, tüm sisteminiz enjeksiyonlar ve diğer kötü saldırılar yoluyla saldırıya uğrayabilir.


1

Burada mysql_real_escape_string hakkında konuşan ve güvenen herkes için, bu işlevin PHP5'te kullanımdan kaldırıldığını ve PHP7'de artık mevcut olmadığını fark etmeniz gerekir.

IMHO, bu görevi gerçekleştirmenin en iyi yolu, veritabanıyla etkileşimde bulunmak için PDO kullanarak parametreli sorguları kullanmaktır. Bunu kontrol et: https://phpdelusions.net/pdo_examples/select

Kullanıcı girişini işlemek için daima filtreleri kullanın. Bkz. Http://php.net/manual/es/function.filter-input.php


Bu aslında soruyu cevaplamıyor. Yanıtınızı bir çözüm içerecek şekilde değiştirmeyi düşünün.
kris

Umarım beğenirsin!
Kuntur

Yaparım. Güzel cevap!
kris

Ben PHP 7 mysqli_real_escape_string()kullanılabilir olduğunu not etmenizi öneririz .
Chris

Merhaba Chris, burada maruz kalan çözümler mysql_real_escape_string referans yapılmış, ben artık PHP7 üzerinde artık olmadığını okudum ve mysqli değil PDO (ve filtreler) kullanarak bir alternatif önerdi fark ettim. Önerilerinizi kullanarak bir çözümü açıklayan bir not eklemekten çekinmeyin. Saygılarımızla
Kuntur

0

Aşağıdaki kod benzer mysql_real_escape_string () kullanın .

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

Belgelerin dediği gibi, amacı mysql_query () içine yerleştirmenin güvenli olması için bağlantının geçerli karakter kümesini dikkate alarak argüman olarak iletilen dizedeki özel karakterlerden kaçmaktır . Belgeler ayrıca şunları ekler:

İkili veri eklenecekse, bu işlev kullanılmalıdır.

htmlentities () , HTML içeriğinde bir dize çıkardığınızda varlıklardaki bazı karakterleri dönüştürmek için kullanılır.


0

Şu anda pratik yaptığım yollardan biri bu,

  1. Kullanıcı tarafından yapılacak talep ile birlikte csrf ve tuz özendirici belirteci implant edin ve bunları istekten birlikte doğrulayın. Buraya bakın
  2. istemci tarafı çerezlerine çok fazla güvenmediğinizden emin olun ve sunucu tarafı oturumlarını kullanarak pratik yaptığınızdan emin olun
  3. Herhangi bir ayrıştırma verisi olduğunda, yalnızca veri türü ve aktarma yöntemini (POST ve GET gibi) kabul ettiğinizden emin olun.
  4. WebApp / Uygulamanız için SSL kullandığınızdan emin olun
  5. Spam isteğini kasten kısıtlamak için zaman tabanı oturum isteği oluşturduğunuzdan emin olun.
  6. Veriler sunucuya ayrıştırıldığında, isteğin json, html vb. Gibi istediğiniz veri yönteminde yapılması gerektiğini doğrulayın ve devam edin.
  7. realescapestring gibi escape türünü kullanarak girişteki tüm yasadışı niteliklerden kaçın.
  8. bundan sonra u kullanıcıdan istediğiniz veri türünün sadece temiz biçimini doğrulayın.
    Örnek:
    - E-posta: girişin geçerli e-posta biçiminde olup olmadığını kontrol edin
    - metin / dize: Yalnızca girişin yalnızca metin biçimi (dize)
    olup olmadığını kontrol edin - sayı: yalnızca sayı biçimine izin verilip verilmediğini kontrol edin.
    - vs. Pelase, php portalından php giriş doğrulama kütüphanesine başvurur.
    - Doğrulandıktan sonra lütfen hazırlanmış SQL ifadesini / PDO'yu kullanarak devam edin.
    - Bittiğinde, bağlantıdan çıkıp bağlantıyı
    kestiğinizden emin olun. - Bittiğinde çıkış değerini silmeyi unutmayın.

Tüm inanıyorum bu temel sn için yeterli. Bilgisayar korsanı tarafından yapılan büyük saldırıları önlemelidir.

Sunucu tarafı güvenliği için, erişim sınırlaması ve robot önleme ve ayrıca yönlendirme önleme için apache / htaccess'inizi ayarlamak isteyebilirsiniz.

Htaccess apache sn düzeyinden sn'nin bir kopyasını öğrenebilir ve alabilirsiniz (yaygın uygulamalar)


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;
}

0

Peki buna ne dersin

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

veya bu

$string = htmlentities($_POST['example'], ENT_QUOTES, 'UTF-8');
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.