Какво представлява SQL Injection атаката?

+9 гласа
1,244 прегледа
попитан 2016 юни 13 в Обща дискусия от Veronika.Georgieva. (1,460 точки)
Н аинтервю за работа ме попитаха какво е SQL injection и как може да се предпазим от подобна атака. Някой може ли да ми разкаже повече или да ми дадете примери или като цяло как се отговаря на този въпрос?

2 отговори

+2 гласа
отговорени 2016 юни 13 от Nolongerexists2 (1,770 точки)

SQL Injector е техника за инжектиране на код който се използва за атака. Тя позволява да вземеш информацията на една база данни. Първите признаци за уязвимост се появяват когато потребителят който използва SQL Injection въведе знаци които не могат да се филтрират правилно.

Нека да речем, че нашият сайт има страница

  • www.stranica.com/news.php?id=3

Първото нещо което трябва да направя аз като тест е да добавя знак ' след id=3 

  • www.stranica.com/news.php?id=3'

И ако нашият сайт е уязвим на такъв вид атака то ще ни излезе съобщение със следната информация

Error : You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '\'' at line 

Как да се предпазиме от такъв вид атаки?
Да речем, че това е нашият код


<?php 
if(isset($_GET['id'])){
    // Избираме данните от news
    $sel = mysql_query("SELECT * FROM news WHERE id = '".$_GET['id']."'"); 
        $row = mysql_fetch_array($sel);
}

?>


Ако сме задали променливата id то тогава ще изберем всичко от news с това id, но след като добавиме още една кавичка след id = '".$_GET['id']."' то целият код ще даде една перфектна грешка за един хакер да проникне в нашата система.

За да оправиме този проблем, към нашият код трябва да добавим, че искаме да се въвеждат само цифри(is_numeric) което автоматично ще ни предпази от следваща SQL атака


<?php 
    if(isset($_GET['id']) && is_numeric($_GET['id'])){
        // Избираме данните от news
        $sel = mysql_query("SELECT * FROM news WHERE id = '".$_GET['id']."'"); 
            $row = mysql_fetch_array($sel);
    }
?>

+1 глас
отговорени 2016 юни 13 от VeskoNikolov (1,640 точки)

Единственото, което ще добавя по темата е следното:
POST метода също не е имунизиран срещу SQL инжекция.

Примерно да речем, че имаш логин страница, която ще изглежда приблизително така:

<form method="POST">
    <input type="text" name="username" />
    <input type="password" name="password" />
    <input type="submit" name="loginformsubmit" value="вход"/>
</form>

<?php

if(isset($_POST['loginformsubmit'])){
    //Този код се изпълнява само тогава, когато е натиснат бутона вход
    $username = $_POST['username'];
    $password = $_POST['password'];

    $sql = "  SELECT * FROM `users` WHERE `username`='$username' AND `password`='$password'  ";
    //След това изпълняваме SQL-a, без значение как. Белята вече е станала
    $q = mysql_query($sql);
    $r = mysql_fetch_array($q);

    if(!empty($r)){
        echo "Влезе баце! Мноо си луд. Са земи си сипи една рикия оти си мноо умен хакер. НАЗДРАВЕ!";
    }
}
?>


Този код работи, НО той има една огромна слабост. Ако някой въведе в полето за паролата следното:


glupost' OR '1'='1
 

към базата ще се прати следният SQL:


SELECT * FROM `users` WHERE `username`='tamnqkfoime' AND `password`='glupost' OR '1'='1'


Този SQL се изпълнява и хакер влиза в профила с име "tamnqkfoime", но без да ползва парола.
Решения: 

  • Споменатите в предишният отговор проверки
  • Ползване на ORM (Object relational mapper) - в зависимост от езика, който се ползва има различни възможности (при PHP най-препоръчван е doctrine)
  • Или при изпълнение на самият SQL да се bind-ват параметрите. При php това става чрез  PDO. Показаният по-горе код би изглеждал по следният начин:

 

if(isset($_POST['loginformsubmit'])){
    //Този код се изпълнява само тогава, когато е натиснат бутона вход
    $username = $_POST['username'];
    $password = $_POST['password'];
    $sql = "  SELECT * FROM users WHERE username=:username AND password=:password  ";
    //При изпълнение по този начин сме защитени от SQL инжекция
    $statement = $db->prepare($sql);
    $statement->bindValue(':username',$username); //тук bind-ваме с помощта на PDO
    $statement->bindValue(':password',$password);
    $statement->execute();
    $r = $statement->fetchAll();

    if(!empty($r)){
        echo "Влезе баце! Мноо си луд. Са земи си сипи една рикия оти си мно умен, само дека тоо път не си хакер. НАЗДРАВЕ!";
    }
}


Разбира се, този пример е леко пресилен, защото паролите най-често ще се хешират, но добре демонстрира какво представлява SQL инжекция.

...