Bu PHP kodu güvenli midir?

6 Cevap

Sadece hızlı bir soru: Aşağıdaki PHP kodu güvenlidir? Ayrıca yapabilseydim ya da eklemek gerektiğini düşünüyorum bir şey var mı?

    $post = $_GET['post'];

    if(is_numeric($post))
    {
        $post = mysql_real_escape_string($post);
    }
    else
    {
        die("NAUGHTY NAUGHTY");
    }

    mysql_select_db("****", $*****);

    $content = mysql_query("SELECT * FROM tbl_***** WHERE Id='" . $post . "'");

6 Cevap

(Eğer hala SQL deyimi, krş Alex'in 'cevabını kırmak mümkün olacaktır rağmen) bu özel durumda, ben is_numeric SQL enjeksiyonu sizi kurtarır sanırım. Ancak, ben gerçekten (aka. hazırlanmış deyimleri) parametreli sorgular kullanarak düşünmelisiniz düşünüyorum, çünkü:

  1. Sayısal olmayan türleri parametreleri kullanılarak bile onlar sizi koruyacaktır
  2. Eğer daha fazla parametre eklemek gibi giriş sanitasyon unutmadan risk yok
  3. Sizin kod yazmak için çok daha kolay olacak ve okuyacak

İşte bir örnek (burada $db bir PDO bağlantısı):

$stmt = $db->prepare('SELECT * FROM tbl_Persons WHERE Id = :id');
$stmt->execute(array(':id' => $_GET['post']));
$rows = $stmt->fetchAll();

PHP parametreli SQL ifadeleri hakkında daha fazla bilgi için bkz:

is_numeric gibi '0 xff gibi onaltılık sayılar için 'true dönecektir.

: EDIT: Bu etrafında almak için, gibi bir şey yapabilirsiniz

sprintf('%d', mysql_real_escape_string($post, $conn));
//If $post is not an int, it will become 0 by sprintf

here on php.net daha fazla bilgi için pasajı bak.

You're not passing the connection resource to mysql_real_escape_string() (but you seemingly do so with mysql_select_db()). The connection resource amongst other things stores the connection charset setting which might affect the behavior of real_escape_string().
Either don't pass the resource anywhere or (preferably) pass it always but don't make it even worse than not passing the resource by mixing both.

Benim kitapta, "Güvenlik", aynı zamanda kod "anlaşılabilir", okunabilir ve "düz-ileri" şeyler yapar mı kapsar. Örnekte en az bir SELECT sorgusu bir dize olarak kimliği tedavi zaman tüm !numeric -> die şube var neden bana açıklamak zorunda olurdu. Benim karşı argüman (örnek olarak duruyor; yanlış olabilir sizin context) "Neden rahatsız SEÇİMİ sadece sayısal olmayan bir kimliği için herhangi bir kayıt döndürmez? Olur" kod azaltır

if ( isset($_GET['post']) ) {
  $query = sprintf(
    "SELECT x,y,z FROM foo WHERE id='%s'",
    mysql_real_escape_string($_GET['post'], $mysqlconn) 
  );
   ...
}

Bu automagically is_numeric () (diğer cevaplar açıklandığı gibi) beklendiği gibi davranmasına değil çünkü içine çalışabilir sorun ortadan kaldırır.

edit: And there's something to be said about using die() to often/to early in production code. It's fine for test/example code but in a live system you almost always want to give control back to the surrounding code instead of just exiting (so your application can handle the error gracefully). During the development phase you might want to bail out early or put more tests in. In that case take a look at http://docs.php.net/assert.
Your example might qualify for an assertion. It won't break if the assertion is deactivated but it might give a developer more information about why it's not working as intended (by this other developer) when a non-numeric argument is passed. But you have to be careful about separating necessary tests from assertions; they are not silver bullets.
If you feel is_numeric() to be an essential test your function(?) might return false, throw an exception or something to signal the condition. But to me an early die() is the easy way out, a bit like a clueless opossum, "I have no idea what to do now. If i play dead maybe no one will notice" ;-)

Kime ipucu hazırlanan tablolarda: http://docs.php.net/pdo.prepared-statements

Ben ok görünüyor düşünüyorum.

Ben her zaman bağlama sorgusu kullanmak veritabanlarına erişerek benim dizeleri kaçmak unutursanız, bu sorunları önler.

Biraz kaba, ama ben hemen hiçbir ciddi sorunlara neden olacak bir şey görmüyorum. Bunu onaltılık gösterimde belgelerine göre is_numeric() içinde kabul edilir dikkat etmelisiniz. Sen is_int() kullanın veya döküm isteyebilirsiniz. Ve netlik için, ben parametreli sorgular kullanarak öneririm:

$sql = sprintf("SELECT col1 
                FROM tbl 
                WHERE col2 = '%s'", mysql_real_escape_string($post));

Bu durumda, $post %s değeri olarak kabul edilir.

Siz doğru bir fikir var ama sizin istediğiniz gibi is_numeric () davranabilir değil.

Bu testi deneyin:

<?php
$tests = Array(
        "42", 
        1337, 
        "1e4", 
        "not numeric", 
        Array(), 
        9.1
        );

foreach($tests as $element)
{
    if(is_numeric($element))
    {
        echo "'{$element}' is numeric", PHP_EOL;
    }
    else
    {
        echo "'{$element}' is NOT numeric", PHP_EOL;
    }
}
?>

Sonuç:

'42' is numeric
'1337' is numeric
'1e4' is numeric
'not numeric' is NOT numeric
'Array' is NOT numeric
'9.1' is numeric

1e4 Eğer yaygın bir sayısal değer olarak adlandırılır ne arıyorsanız eğer, SQL Server anladığı şey olmayabilir. Bir SQL enjeksiyon açısından iyisin.