PHP ile kullanıcı girişini nasıl sterilize edebilirim?


1124

Bazı HTML etiketi türlerine izin verirken, SQL enjeksiyonu ve XSS saldırıları için kullanıcı girişini dezenfekte etmek için iyi çalışan bir kaçak işlevi var mı?


42
Günümüzde sql enjeksiyonunu önlemek için PDO veya MySQLi kullanın.
Francisco Presencia

76
PDO veya MySQLi kullanmak yeterli değildir. SQL ifadelerinizi, örneğin güvenilir olmayan verilerle oluşturursanız, select * from users where name='$name'PDO veya MySQLi veya MySQL kullanmanız önemli değildir. Hala tehlikedesin. Parametreli sorgular kullanmanız veya verilerinizde kaçan mekanizmalar kullanmanız gerekir, ancak bu çok daha az tercih edilir.
Andy Lester

26
@AndyLester Birinin hazırlanmış ifadeler olmadan PDO kullandığını ima ediyor musunuz? :)

64
"PDO veya MySQLi Kullan" ın acemi onlara nasıl güvenli bir şekilde kullanılacağını açıklayacak kadar bilgi olmadığını söylüyorum. Siz ve ben, hazırlanan ifadelerin önemli olduğunu biliyoruz, ancak bu soruyu okuyan herkesin bunu bileceğini varsaymıyorum. Bu yüzden açık talimatları ekledim.
Andy Lester

30
Andy'nin yorumu tamamen geçerlidir. Son zamanlarda enjeksiyon saldırılarından bir şekilde güvende olduğumu düşünerek mysql web sitemi PDO'ya dönüştürdüm. Sadece süreç sırasında bazı sql ifadelerimin hala kullanıcı girişi kullanılarak oluşturulduğunu fark ettim. Daha sonra hazırlanan ifadeleri kullanarak bunu düzelttim. Tam bir acemi için, birçok uzman PDO kullanımı hakkında yorum yaptıklarından, ancak hazırlanan ifadelere duyulan ihtiyacı belirtmediğinden, bir ayrım olduğu açık değildir. Varsayım bunun açık olduğu yönündedir. Ama acemi değil.
GhostRider

Yanıtlar:


1184

Kullanıcı girişinin filtrelenebilmesi yaygın bir yanlış anlamadır. PHP bile sihirli tırnak olarak adlandırılan (şimdi kullanımdan kaldırılmış) bir "özelliğe" sahiptir ve bu fikir üzerine kuruludur. Saçmalık. Filtrelemeyi (veya temizlemeyi ya da insanların söylediği her şeyi) unutun.

Sorunlardan kaçınmak için yapmanız gerekenler oldukça basittir: bir dizeyi yabancı kod içine gömdüğünüzde, o dilin kurallarına göre kaçmanız gerekir. Örneğin, bir dizeyi MySQL hedefleyen bazı SQL'lere yerleştirirseniz, bu amaçla dizeden MySQL işlevinden kaçmanız gerekir ( mysqli_real_escape_string). (Veya veritabanlarında, hazırlanmış ifadelerin kullanılması, mümkün olduğunda daha iyi bir yaklaşımdır.)

Başka bir örnek HTML: Dizeleri HTML işaretlemesine katıştırırsanız, dizeden kaçmanız gerekir htmlspecialchars. Bu, her bir ifadenin echoveya printifadenin kullanması gerektiği anlamına gelir htmlspecialchars.

Eğer harici komutlara (örneğin argümanlar gibi) embed dizeleri yapacaksanız ve onları çağırır: Bir üçüncü örnek kabuk komutları olabilir execardından kullanmak gerekir, escapeshellcmdve escapeshellarg.

Ve böyle devam eder ...

Sadece sen önceden biçimlendirilmiş giriş kabul edilebilir eğer aktif filtre verilerine ihtiyaç durum vardır. Örneğin, kullanıcılarınızın HTML işaretlemesi göndermesine izin verirseniz sitede görüntülemeyi planlıyorsunuz. Bununla birlikte, bunu ne pahasına olursa olsun önlemek için akıllıca olmalısınız, çünkü ne kadar iyi filtre uygulasanız da, her zaman potansiyel bir güvenlik deliği olacaktır.


245
"Bu, her bir yankı veya baskı deyiminin htmlspecialchars kullanması gerektiği anlamına gelir" - elbette "her ... deyimi kullanıcı girdisi çıktısı" anlamına gelir; htmlspecialchars () - ifying "echo 'Merhaba dünya!';" deli olur;)
Bobby Jack

10
Filtrelemenin doğru çözüm olduğunu düşündüğüm bir durum var: UTF-8. Uygulamanızın her yerinde geçersiz UTF-8 dizileri istemezsiniz (kod yoluna bağlı olarak farklı hata kurtarma işlemleri gerçekleştirebilirsiniz) ve UTF-8 kolayca filtrelenebilir (veya reddedilebilir).
Kornel

6
@jbyrd - hayır, LIKE özel bir normal ifade dili kullanıyor. Bir kez regexp ve bir kez mysql dize kodlaması için giriş dizenizden iki kez kaçmak zorunda kalacaksınız. Kod içindeki kod içindeki kod.
troelskn

6
Şu anda mysql_real_escape_stringkullanımdan kaldırıldı. Günümüzde SQL enjeksiyonunu önlemek için hazırlanmış ifadelerin kullanılması iyi bir uygulama olarak kabul edilmektedir . Yani MySQLi veya PDO'ya geçin.
Marcel Korpel

4
Çünkü saldırı yüzeyini sınırlandırıyorsunuz. Erken (giriş yaparken) sterilize ederseniz, uygulamada kötü verilerin girebileceği başka delik olmadığından emin olmalısınız. Eğer geç yaparsanız, o zaman çıktı fonksiyonunuz güvenli veri verildiğine "güvenmek" zorunda değildir - sadece her şeyin güvensiz olduğunu varsayar.
troelskn

217

Giriş verilerini sterilize ederek SQL enjeksiyonunu önlemeye çalışmayın.

Bunun yerine, SQL kodunuzu oluştururken verilerin kullanılmasına izin vermeyin . İlişkili değişkenleri kullanan Hazırlanmış Deyimler kullanın (örn. Şablon sorgusunda parametreleri kullanma). SQL enjeksiyonuna karşı garantili olmanın tek yolu budur.

SQL enjeksiyonunu önleme hakkında daha fazla bilgi için lütfen http://bobby-tables.com/ adresindeki web siteme bakın .


18
Ya da resmi belgeleri ziyaret edin ve PDO ve hazırlanmış bildirimleri öğrenin. Küçük öğrenme eğrisi, ancak SQL'i oldukça iyi biliyorsanız, adapte olmakta zorlanmayacaksınız.
bir kodlayıcı

2
SQL Enjeksiyon özgü özel durum için, bu doğru cevap!
Scott Arciszewski

4
Hazırlanan ifadelerin herhangi bir güvenlik sağlamadığını, parametreli sorguların eklemediğini unutmayın. PHP'de birlikte kullanımı çok kolay oluyor.
Temel

Tek garantili yol değil. Onaltılı giriş ve sorgudaki unhex de önleyecektir. Ayrıca hexing hakkını kullanırsanız hex saldırıları mümkün değildir.
Ramon Bakker

E-posta adresleri veya kullanıcı adları gibi özel bir şey giriyorsanız ne olur?
Abraham Brookes

79

Hayır. Ne için bir bağlam olmadan verileri genel olarak filtreleyemezsiniz. Bazen girdi olarak bir SQL sorgusu almak, bazen de HTML'yi girdi olarak almak istersiniz.

Bir beyaz listedeki girişi filtrelemeniz gerekir - verilerin beklediğiniz şeyin bazı özelliklerine uygun olduğundan emin olun. Ardından, kullandığınız içeriğe bağlı olarak, kullanmadan önce kaçmanız gerekir.

SQL enjeksiyonundan kaçınmak için SQL'den veri çıkış işlemi, XSS'yi önlemek için (X) HTML için veri çıkış işleminden çok farklıdır.


52

PHP şimdi yeni bir filter_input işlevine sahip.

Kendi filtre sınıfım (hatalı alanları vurgulamak için JavaScript kullanır) bir ajax isteği veya normal form gönderisi ile başlatılabilir. (aşağıdaki örneğe bakın)

/**
 *  Pork.FormValidator
 *  Validates arrays or properties by setting up simple arrays. 
 *  Note that some of the regexes are for dutch input!
 *  Example:
 * 
 *  $validations = array('name' => 'anything','email' => 'email','alias' => 'anything','pwd'=>'anything','gsm' => 'phone','birthdate' => 'date');
 *  $required = array('name', 'email', 'alias', 'pwd');
 *  $sanitize = array('alias');
 *
 *  $validator = new FormValidator($validations, $required, $sanitize);
 *                  
 *  if($validator->validate($_POST))
 *  {
 *      $_POST = $validator->sanitize($_POST);
 *      // now do your saving, $_POST has been sanitized.
 *      die($validator->getScript()."<script type='text/javascript'>alert('saved changes');</script>");
 *  }
 *  else
 *  {
 *      die($validator->getScript());
 *  }   
 *  
 * To validate just one element:
 * $validated = new FormValidator()->validate('blah@bla.', 'email');
 * 
 * To sanitize just one element:
 * $sanitized = new FormValidator()->sanitize('<b>blah</b>', 'string');
 * 
 * @package pork
 * @author SchizoDuckie
 * @copyright SchizoDuckie 2008
 * @version 1.0
 * @access public
 */
class FormValidator
{
    public static $regexes = Array(
            'date' => "^[0-9]{1,2}[-/][0-9]{1,2}[-/][0-9]{4}\$",
            'amount' => "^[-]?[0-9]+\$",
            'number' => "^[-]?[0-9,]+\$",
            'alfanum' => "^[0-9a-zA-Z ,.-_\\s\?\!]+\$",
            'not_empty' => "[a-z0-9A-Z]+",
            'words' => "^[A-Za-z]+[A-Za-z \\s]*\$",
            'phone' => "^[0-9]{10,11}\$",
            'zipcode' => "^[1-9][0-9]{3}[a-zA-Z]{2}\$",
            'plate' => "^([0-9a-zA-Z]{2}[-]){2}[0-9a-zA-Z]{2}\$",
            'price' => "^[0-9.,]*(([.,][-])|([.,][0-9]{2}))?\$",
            '2digitopt' => "^\d+(\,\d{2})?\$",
            '2digitforce' => "^\d+\,\d\d\$",
            'anything' => "^[\d\D]{1,}\$"
    );
    private $validations, $sanatations, $mandatories, $errors, $corrects, $fields;


    public function __construct($validations=array(), $mandatories = array(), $sanatations = array())
    {
        $this->validations = $validations;
        $this->sanitations = $sanitations;
        $this->mandatories = $mandatories;
        $this->errors = array();
        $this->corrects = array();
    }

    /**
     * Validates an array of items (if needed) and returns true or false
     *
     */
    public function validate($items)
    {
        $this->fields = $items;
        $havefailures = false;
        foreach($items as $key=>$val)
        {
            if((strlen($val) == 0 || array_search($key, $this->validations) === false) && array_search($key, $this->mandatories) === false) 
            {
                $this->corrects[] = $key;
                continue;
            }
            $result = self::validateItem($val, $this->validations[$key]);
            if($result === false) {
                $havefailures = true;
                $this->addError($key, $this->validations[$key]);
            }
            else
            {
                $this->corrects[] = $key;
            }
        }

        return(!$havefailures);
    }

    /**
     *
     *  Adds unvalidated class to thos elements that are not validated. Removes them from classes that are.
     */
    public function getScript() {
        if(!empty($this->errors))
        {
            $errors = array();
            foreach($this->errors as $key=>$val) { $errors[] = "'INPUT[name={$key}]'"; }

            $output = '$$('.implode(',', $errors).').addClass("unvalidated");'; 
            $output .= "new FormValidator().showMessage();";
        }
        if(!empty($this->corrects))
        {
            $corrects = array();
            foreach($this->corrects as $key) { $corrects[] = "'INPUT[name={$key}]'"; }
            $output .= '$$('.implode(',', $corrects).').removeClass("unvalidated");';   
        }
        $output = "<script type='text/javascript'>{$output} </script>";
        return($output);
    }


    /**
     *
     * Sanitizes an array of items according to the $this->sanitations
     * sanitations will be standard of type string, but can also be specified.
     * For ease of use, this syntax is accepted:
     * $sanitations = array('fieldname', 'otherfieldname'=>'float');
     */
    public function sanitize($items)
    {
        foreach($items as $key=>$val)
        {
            if(array_search($key, $this->sanitations) === false && !array_key_exists($key, $this->sanitations)) continue;
            $items[$key] = self::sanitizeItem($val, $this->validations[$key]);
        }
        return($items);
    }


    /**
     *
     * Adds an error to the errors array.
     */ 
    private function addError($field, $type='string')
    {
        $this->errors[$field] = $type;
    }

    /**
     *
     * Sanitize a single var according to $type.
     * Allows for static calling to allow simple sanitization
     */
    public static function sanitizeItem($var, $type)
    {
        $flags = NULL;
        switch($type)
        {
            case 'url':
                $filter = FILTER_SANITIZE_URL;
            break;
            case 'int':
                $filter = FILTER_SANITIZE_NUMBER_INT;
            break;
            case 'float':
                $filter = FILTER_SANITIZE_NUMBER_FLOAT;
                $flags = FILTER_FLAG_ALLOW_FRACTION | FILTER_FLAG_ALLOW_THOUSAND;
            break;
            case 'email':
                $var = substr($var, 0, 254);
                $filter = FILTER_SANITIZE_EMAIL;
            break;
            case 'string':
            default:
                $filter = FILTER_SANITIZE_STRING;
                $flags = FILTER_FLAG_NO_ENCODE_QUOTES;
            break;

        }
        $output = filter_var($var, $filter, $flags);        
        return($output);
    }

    /** 
     *
     * Validates a single var according to $type.
     * Allows for static calling to allow simple validation.
     *
     */
    public static function validateItem($var, $type)
    {
        if(array_key_exists($type, self::$regexes))
        {
            $returnval =  filter_var($var, FILTER_VALIDATE_REGEXP, array("options"=> array("regexp"=>'!'.self::$regexes[$type].'!i'))) !== false;
            return($returnval);
        }
        $filter = false;
        switch($type)
        {
            case 'email':
                $var = substr($var, 0, 254);
                $filter = FILTER_VALIDATE_EMAIL;    
            break;
            case 'int':
                $filter = FILTER_VALIDATE_INT;
            break;
            case 'boolean':
                $filter = FILTER_VALIDATE_BOOLEAN;
            break;
            case 'ip':
                $filter = FILTER_VALIDATE_IP;
            break;
            case 'url':
                $filter = FILTER_VALIDATE_URL;
            break;
        }
        return ($filter === false) ? false : filter_var($var, $filter) !== false ? true : false;
    }       



}

Tabii ki, kullandığınız db türüne bağlı olarak sql sorgunuzu da kaçmanız gerektiğini unutmayın (mysql_real_escape_string () örneğin bir sql sunucusu için işe yaramaz). Muhtemelen bunu otomatik olarak bir ORM gibi uygun uygulama katmanınızda işlemek istersiniz. Ayrıca, yukarıda belirtildiği gibi: html çıktısı için htmlspecialchars gibi diğer php adanmış işlevlerini kullanın;)

Soyulmuş sınıflar ve / veya etiketler gibi HTML girişlerine gerçekten izin vermek, özel xss doğrulama paketlerinden birine bağlıdır. KENDİ REGEXLERİNİZİ PARSE HTML'E YAZMAYIN!


18
Bu, girişleri doğrulamak için kullanışlı bir komut dosyası gibi görünebilir, ancak soru ile tamamen ilgisizdir.
rjmunro

43

Hayır yok.

Her şeyden önce, SQL enjeksiyonu bir giriş filtreleme problemidir ve XSS bir çıkıştan kaçar - bu nedenle bu iki işlemi kod yaşam döngüsünde aynı anda yürütemezsiniz.

Temel kurallar

  • SQL sorgusu için, parametreleri bağlayın (PDO'da olduğu gibi) veya sorgu değişkenleri için sürücü-yerel bir kaçış işlevi kullanın (örneğin mysql_real_escape_string())
  • strip_tags()İstenmeyen HTML'yi filtrelemek için kullanın
  • Diğer tüm çıkışlardan kaçın htmlspecialchars()ve buradaki 2. ve 3. parametreleri dikkate alın.

1
Bu nedenle, girdinin sırasıyla kurtulmak veya kaçmak istediğiniz HTML'ye sahip olduğunu bildiğinizde strip_tags () veya htmlspecialchars () kullanırsınız - bunu herhangi bir güvenlik amacıyla kullanmıyorsunuz değil mi? Ayrıca, bağlamayı yaptığınızda, Bobby Tables gibi şeyler için ne yapar? "Robert '); DROP TABLE Öğrenciler; -" Sadece alıntılardan kaçıyor mu?
Robert Mark Bram

2
Veritabanına girecek ve daha sonra web sayfalarında görüntülenecek kullanıcı verileriniz varsa, genellikle yazıldığından çok daha fazla okunmaz mı? Bana göre, her görüntülediğinizde filtrelemek yerine, kaydetmeden önce bir kez (giriş olarak) filtrelemek daha mantıklıdır. Bir şey mi eksik veya bir grup insan bu ve kabul edilen cevapta gereksiz performans yükü için oy kullandı mı?
jbo5112

2
Benim için en iyi cevap. Kısa ve bana sorarsanız soruyu iyi ele alıyor. Bir şekilde enjeksiyonla $ _POST veya $ _GET yoluyla PHP'ye saldırmak mümkün mü yoksa bu imkansız mı?
Jo Smo

oh evet, $ post ve $ get dizileri tüm karakterleri kabul eder, ancak karakterin yayınlanan php sayfasında numaralandırılmasına izin verilirse bu karakterlerden bazıları size karşı kullanılabilir. bu nedenle, kapsülleyici karakterlerden ("," ve "gibi) kaçmazsanız bir saldırı vektörü açabilir.` `karakter genellikle kaçırılır ve komut satırı yürütme saldırıları oluşturmak için kullanılabilir. ancak web uygulaması güvenlik duvarı kesmek size yardımcı olmaz
drtechno

22

XSS sorununu çözmek için HTML Arıtma Sistemine göz atın . Oldukça yapılandırılabilir ve iyi bir geçmişe sahiptir.

SQL enjeksiyon saldırılarına gelince, kullanıcı girişini kontrol ettiğinizden emin olun ve mysql_real_escape_string () ile çalıştırın. Bununla birlikte, işlev tüm enjeksiyon saldırılarını yenmeyecektir, bu nedenle verileri sorgu dizenize dökmeden önce kontrol etmeniz önemlidir.

Daha iyi bir çözüm hazırlanmış ifadeler kullanmaktır. PDO kütüphane ve mysqli uzantısı bu destekler.


sanitize giriş gibi bir şey yapmak için "en iyi yolu" yoktur .. Bazı kütüphane kullanın, html temizleyici iyidir. Bu kütüphaneler birçok kez vurulmuştur. Yani ou kendiniz gelebilir her şeyden çok daha kurşun geçirmez
paan

Ayrıca bkz . Bioinformatics.org/phplabware/internal_utilities/htmLawed . Anladığım kadarıyla WordPress daha eski bir sürümünü kullanıyor: core.trac.wordpress.org/browser/tags/2.9.2/wp-includes/kses.php
Steve Clay

WordPress ile ilgili sorun, mutlaka veritabanı ihlallerine neden olan bir php-sql enjeksiyon saldırısı değildir. Bir xml sorgusunun sırları açığa çıkardığı verileri depolayan Miss programlanmış eklentiler daha sorunludur.
drtechno


17

Bir sayfanızın olduğu /mypage?id=53ve WHERE yan tümcesinde kimliği kullandığınız belirli durumlarda yardımcı olabilecek bir numara, kimliğin kesinlikle bir tamsayı olmasını sağlamaktır:

if (isset($_GET['id'])) {
  $id = $_GET['id'];
  settype($id, 'integer');
  $result = mysql_query("SELECT * FROM mytable WHERE id = '$id'");
  # now use the result
}

Ama elbette bu sadece bir saldırıyı kesiyor, bu yüzden diğer tüm cevapları okuyun. (Ve evet, yukarıdaki kodun harika olmadığını biliyorum, ancak belirli bir savunmayı gösteriyor.)


11
Onun yerine $ id = intval ($ id) kullanıyorum :)
Duc Tran

Tamsayı döküm, yalnızca sayısal verilerin girilmesini sağlamanın iyi bir yoludur.
test

1
$id = (int)$_GET['id']and $que = sprintf('SELECT ... WHERE id="%d"', $id)is good too
vladkras

16

PHP ile kullanıcı girişini sterilize etme yöntemleri:

  • MySQL ve PHP'nin Modern Sürümlerini kullanın.

  • Karakter kümesini açıkça ayarlayın:

    • $ Mysqli-> set_charset ( "utf8");
      Manuel
    • $ pdo = yeni PDO ('mysql: host = localhost; dbname = testdb; karakter kümesi = UTF8', $ kullanıcı, $ şifre);
      Manuel
    • $ pdo-> exec ("set adları utf8");
      Manuel
    • $ pdo = yeni PDO (
      "mysql: host = $ host; dbname = $ db", $ kullanıcı, $ pass, 
      dizi(
      PDO :: ATTR_ERRMODE => PDO :: ERRMODE_EXCEPTION,
      PDO :: MYSQL_ATTR_INIT_COMMAND => "İSİMLERİ ayarla utf8"
      )
      );
      Manuel
    • mysql_set_charset ( 'utf8')
      [PHP 5.5.0'da kullanımdan kaldırıldı, PHP 7.0.0'da kaldırıldı].
  • Güvenli karakter kümeleri kullanın:

    • Utf8, latin1, ascii .. seçin, savunmasız karakterleri kullanmayın big5, cp932, gb2312, gbk, sjis.
  • Uzamsal işlevi kullanın:

    • MySQLi tarafından hazırlanan ifadeler:
      $ stmt = $ mysqli-> hazırlayın ('SELECT * FROM test WHERE name =? LIMIT 1'); 
      $ param = "'VEYA 1 = 1 / *";
      $ stmt-> bind_param ('s', $ param);
      $ stmt->) (yürütmek;
    • PDO :: quote () - tırnakları giriş dizesinin etrafına (gerekirse) yerleştirir ve temel sürücüye uygun bir tırnak stili kullanarak giriş dizesi içindeki özel karakterlerden kaçar:

      $ pdo = yeni PDO ('mysql: host = localhost; dbname = testdb; karakter kümesi = UTF8', $ kullanıcı, $ şifre); açık karakter seti
      $ pdo-> setAttribute (PDO :: ATTR_EMULATE_PREPARES, false); MySQL'in yerel olarak hazırlayamadığı taklit ifadelere geri
      dönüşü önlemek için hazırlanmış ifadeleri taklit etmeyi devre dışı bırak (enjeksiyonu önlemek için) $ var = $ pdo-> quote ("'OR 1 = 1 / *"); Sadece değişmez kelimeden kaçmakla kalmaz, aynı zamanda alıntı yapar (tek tırnaklı 'karakterlerle) $ stmt = $ pdo-> query ("SELECT * FROM test WHERE name = $ var LIMIT 1");

    • PDO Hazırlanan İfadeler : vs MySQLi tarafından hazırlanan ifadeler daha fazla veritabanı sürücüsünü ve adlandırılmış parametreleri destekler:

      $ pdo = yeni PDO ('mysql: host = localhost; dbname = testdb; karakter kümesi = UTF8', $ kullanıcı, $ şifre); açık karakter seti
      $ pdo-> setAttribute (PDO :: ATTR_EMULATE_PREPARES, false); MySQL'in yerel olarak hazırlayamadığı taklit ifadelere geri dönüşü önlemek için hazırlanmış ifadeleri taklit etmeyi devre dışı bırak (enjeksiyonu önlemek için) $ stmt = $ pdo-> hazırlayın ('SELECT * FROM test WHERE name =? LIMIT 1'); $ stmt-> execute (["'OR 1 = 1 / *"]);

    • mysql_real_escape_string [PHP 5.5.0'da kullanımdan kaldırıldı, PHP 7.0.0'da kaldırıldı].
    • mysqli_real_escape_string Bağlantının geçerli karakter kümesini göz önünde bulundurarak, bir SQL ifadesinde kullanmak üzere bir dizede özel karakterlerden kaçar. Ancak Hazırlanan İfadelerin kullanılması önerilir, çünkü bunlar sadece kaçan dizeler değildir, bir ifade hangi tabloları ve dizinleri kullanacağı da dahil olmak üzere eksiksiz bir sorgu yürütme planı ile gelir, optimize edilmiş bir yoldur.
    • Sorgunuzdaki değişkenlerinizin etrafında tek tırnak ('') kullanın.
  • Değişkenin ne beklediğinizi içerdiğini kontrol edin:

    • Bir tam sayı bekliyorsanız, şunu kullanın:
      ctype_digit - Sayısal karakter (ler) olup olmadığını kontrol et; 
      $ değer = (int) $ değer;
      $ değer = aralık ($ değer);
      $ var = filter_var ('0755', FILTER_VALIDATE_INT, $ seçenekler);
    • Dizeler için:
      is_string () - Bir değişkenin türünün dize olup olmadığını bulma

      Filtre İşlevini Kullan filter_var () - bir değişkeni belirtilen filtreyle filtreler:
      $ email = filter_var ($ email, FILTER_SANITIZE_EMAIL); 
      $ newstr = filtre_var ($ str, FILTER_SANITIZE_STRING);
      daha önceden tanımlanmış filtreler
    • filter_input () - Belirli bir harici değişkeni ada göre alır ve isteğe bağlı olarak filtreler:
      $ search_html = filter_input (INPUT_GET, 'arama', FILTER_SANITIZE_SPECIAL_CHARS);
    • preg_match () - Normal ifade eşleşmesi gerçekleştirir;
    • Kendi doğrulama fonksiyonunuzu yazın.

11

Burada açıkladığınız iki ayrı konudur:

  1. Kullanıcı giriş verilerinin sterilize edilmesi / filtrelenmesi.
  2. Kaçan çıktı.

1) Kullanıcı girişinin her zaman kötü olduğu varsayılmalıdır.

Hazırlanan ifadeleri kullanmak veya mysql_real_escape_string ile filtreleme kesinlikle şarttır. PHP ayrıca başlamak için iyi bir yer olan filter_input yerleşiktir.

2) Bu büyük bir konudur ve çıkmakta olan verinin bağlamına bağlıdır. HTML için htmlpurifier gibi çözümler var. Genel bir kural olarak, her zaman çıktılarınızdan kaçın.

Her iki konu da tek bir gönderiye girmek için çok büyük, ancak daha fazla ayrıntı içeren birçok gönderi var:

PHP çıktı yöntemleri

Daha güvenli PHP çıktısı



8

Hiçbir katolik işlevi yoktur, çünkü ele alınması gereken birden fazla endişe vardır.

  1. SQL Enjeksiyonu - Bugün, her PHP projesi, PHP Data Objects (PDO) aracılığıyla hazırlanan ifadeleri en iyi uygulama olarak kullanmalı ve başıboş bir alıntıdan kaynaklanan bir hatayı ve enjeksiyona karşı tam özellikli bir çözümü engellemelidir . Ayrıca veritabanınıza erişmenin en esnek ve güvenli yoludur.

    PDO hakkında bilmeniz gereken hemen hemen her şey için (tek uygun) PDO öğretici göz atın . (Konuyla ilgili bu harika kaynak için en iyi SO katılımcısı @YourCommonSense'e içten teşekkürler.)

  2. XSS - Yoldaki verileri sterilize ...

    • HTML Purifier uzun zamandır var ve hala aktif olarak güncelleniyor. Kötü niyetli girdileri dezenfekte ederken, yine de cömert ve yapılandırılabilir bir etiket beyaz listesine izin verirken kullanabilirsiniz. Birçok WYSIWYG editörüyle harika çalışır, ancak bazı kullanım durumlarında ağır olabilir.

    • HTML / Javascript'i hiç kabul etmek istemediğimiz diğer durumlarda, bu basit işlevi yararlı buldum (ve XSS'ye karşı birden fazla denetimden geçtim):

      /* Prevent XSS input */ function sanitizeXSS () { $_GET = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING); $_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING); $_REQUEST = (array)$_POST + (array)$_GET + (array)$_REQUEST; }

  3. XSS - Çıkışta verileri sterilize edin ... Veritabanınıza eklemeden önce verilerin düzgün bir şekilde sterilize edildiğini garanti etmezseniz, kullanıcılarınıza göstermeden önce verileri dezenfekte etmeniz gerekir, bu kullanışlı PHP işlevlerinden yararlanabiliriz:

    • Kullanıcı tarafından sağlanan değerleri çağırdığınızda echoveya printgörüntülediğinizde htmlspecialchars, veriler güvenli bir şekilde sterilize edilmedikçe ve HTML görüntülemesine izin verilmediği sürece kullanın .
    • json_encode PHP'den Javascript'e kullanıcı tarafından sağlanan değerleri sağlamanın güvenli bir yoludur
  4. Harici kabuk komutlarını exec()veya system()işlevlerini kullanarak veya backtickoperatöre çağırıyor musunuz ? Öyleyse, SQL Injection & XSS'ye ek olarak, sunucunuzda kötü amaçlı komutlar çalıştıran kullanıcılar için ek bir endişeniz olabilir . escapeshellcmdTüm komuttan kaçmak veya YA DA escapeshellargbağımsız değişkenlerden kaçmak istiyorsanız kullanmanız gerekir .


mb_encode_numericentity kullanılabilir mi? Her şeyi kodladığı için mi?
drtechno

@drtechno - # 3 XSS bağlantısında mb_encode_numericentitytartışıldıhtmlspecialchars
webaholik

5

Girişi sanitize etmekten ve veri kaçmaktan kaynaklanan hatalardan kaçınmanın en kolay yolu Symfony , Nette vb.Gibi PHP çerçevesini veya bu çerçevenin bir kısmını (şablonlama motoru, veritabanı katmanı, ORM) kullanmaktır.

Twig veya Latte gibi şablon motoru çıkıştan varsayılan olarak kaçıyor - içeriğe (web sayfasının HTML veya Javascript kısmı) bağlı olarak çıkışınızdan düzgün bir şekilde kaçtıysanız manuel olarak çözmeniz gerekmez.

Çerçeve girdiyi otomatik olarak dezenfekte eder ve doğrudan $ _POST, $ _GET veya $ _SESSION değişkenlerini değil, yönlendirme, oturum işleme vb.

Ve veritabanı (model) katmanı için Doktrin gibi ORM çerçeveleri veya PDO'nun etrafında Nette Veritabanı gibi sarmalayıcılar vardır.

Bununla ilgili daha fazla bilgiyi buradan edinebilirsiniz - Yazılım çerçevesi nedir?


3

Sadece çıkış kaçış konusunda eklemek istedim, html çıkış yapmak için php DOMDocument kullanıyorsanız, otomatik olarak doğru bağlamda kaçacaktır. Bir özellik (değer = "") ve bir <span> öğesinin iç metni eşit değildir. XSS'ye karşı güvenli olmak için şunu okuyun: OWASP XSS Önleme Hile Sayfası


2

Girdiyi asla sterilize etmezsiniz.

Her zaman çıktıyı sterilize edersiniz.

SQL ifadesine dahil edilmesini güvenli hale getirmek için verilere uyguladığınız dönüşümler, HTML'ye dahil etmek için uyguladığınızdan tamamen farklıdır. CSS'ye dahil etmek için uyguladığınızlardan tamamen farklı bir E-postaya eklemek için uyguladığınızdan tamamen farklıdır ....

Bütün araçlar tarafından validate girişi - Eğer daha fazla işlem için bunu kabul veya kabul edilemez kullanıcıyı söylemelidir karar verir. Ancak PHP arazisini terk etmek üzere olana kadar verinin sunumunda herhangi bir değişiklik yapmayın.

Uzun zaman önce birisi tek boyutlu bir veri icat etmek için tüm mekanizma uydurmak için çalıştı ve biz tüm çıktı hedefleri için veri düzgün kaçmadı ve farklı kod çalışması için farklı kurulum sonuçlanan " magic_quotes " ile sonuçlandı.


bununla ilgili bir sorun, her zaman bir veritabanı saldırısı ve tüm kullanıcı girişlerinin sistemden korunması gerektiğidir. sadece bir dil türü değil. Dolayısıyla, sitelerinizde, $ _POST verilerinizi, bağlayıcı kullanarak bile numaralandırdığınızda, kabuk veya hatta başka bir php kodu yürütmek için yeterince kaçabilir.
drtechno

"her zaman bir veritabanı saldırısı değildir": "Bir SQL deyimine dahil edilmesini güvenli hale getirmek için verilere uyguladığınız dönüşümler, bunlardan tamamen farklıdır ...."
symcbean

"tüm kullanıcı girişleri sistemden korunmalıdır": hayır sistem kullanıcı girişinden korunmamalıdır.
symcbean

Peki kelimelerim bitti, ama evet girişin sistem çalışmasını etkilemesi önlenmelidir. bunu açıklığa kavuşturmak için ...
drtechno

Hem girdi hem de çıktı sterilize edilmelidir.
Tajni

1

Kullanıcı verilerine asla güvenmeyin.

function clean_input($data) {
  $data = trim($data);
  $data = stripslashes($data);
  $data = htmlspecialchars($data);
  return $data;
}

trim()Fonksiyon kaldırır boşluk ve bir dize her iki tarafından diğer önceden tanımlanmış karakter.

stripslashes()Fonksiyon ters eğik çizgi kaldırır

htmlspecialchars()Fonksiyon HTML öğeleri bazı önceden tanımlı karakterler dönüştürür.

Önceden tanımlanmış karakterler:

& (ampersand) becomes &amp;
" (double quote) becomes &quot;
' (single quote) becomes &#039;
< (less than) becomes &lt;
> (greater than) becomes &gt;

1
Bu neye karşı koruma sağlar? Bu XSS için mi? O clean_inputzaman neden çağırılıyor ? Neden eğik çizgileri çıkarmak istersiniz?
Dharman

4
UYARI: Bu, kullanıcı verilerini sihirli bir şekilde güvenli hale getirmez. Bu işlev hiçbir şeyden korunmadan verilerinize gereksiz yere zarar verir. BUNU KULLANMA!
Dharman

İfadeniz yanlış.
Erik Thiart

0

Tüm GPC değişkenleriyle oldukça iyi çalışan filtre uzantısı ( howto-link , manuel ) vardır. Her şey sihirli bir şey değil, yine de kullanmanız gerekecek.

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.