За последние 24 часа нас посетил 17791 программист и 1646 роботов. Сейчас ищут 960 программистов ...

sql инъекция, как бороться?

Тема в разделе "Прочие вопросы по PHP", создана пользователем ainur777, 25 окт 2014.

  1. ainur777

    ainur777 Активный пользователь

    С нами с:
    24 май 2013
    Сообщения:
    93
    Симпатии:
    0
    Всем привет! Это уже вторая моя тема по sql инъекции. Проблема не уходит, взламывают сайт и в бд меняют некоторые данные. Уже з***ли, какой то настырный упорно меняет всё. Сайт особо не интересен обычному пользователю, цель сайта такая: люди выкладывают свои эксклюзивные темы и рассказы. И вот кто то их тырит или просто извращается над сайтом. Помогите пожалуйста! Посмотрите код:
    Регистрация
    Код (Text):
    1.  
    2. $id = htmlspecialchars($_POST['id']);
    3. $id =stripslashes(trim($_POST['id']));
    4. $name = htmlspecialchars($_POST['name']);
    5. $name =stripslashes(trim($_POST['name']));
    6. $surname = htmlspecialchars($_POST['surname']);
    7. $surname =stripslashes(trim($_POST['surname']));
    8. $city = htmlspecialchars($_POST['city']);
    9. $city =stripslashes(trim($_POST['city']));
    10. $email = htmlspecialchars($_POST['email ']);
    11. $email  =stripslashes(trim($_POST[email ']));
    12. $login = htmlspecialchars($_POST['login']);
    13. $login=stripslashes(trim($_POST['login']));
    14. $password = htmlspecialchars($_POST['password']);
    15. $password=stripslashes(trim($_POST['password']));
    16. //Потом я проверяю empty введены ли данные
    17. if (empty($name)) {} // и.т.д
    18. //тут идет проверка капчи
    19. $password = md5 ($password); //хэширую
    20. $password = strrev($password);
    21. $password = $password."тут всякая шн*га";
    22. include ("bd.php");
    23. $sql = "SELECT id FROM users WHERE login=:login";
    24.     $stmt = $db->prepare($sql);                                  
    25.     $stmt->bindParam(':login', $login);        
    26.     $stmt->execute();
    27.  
    28. //ну и записываю
    29. $date = date("Y-m-d");
    30. $STH = $db->prepare("INSERT INTO users ( id, name, surname, login, email, password, city, country,  date) values (:id, :name, :surname, :login, :email, :password, :city, :country,  :date)");
    31. $STH -> execute(array(':id'=>$id, ':name'=>$name, ':surname'=>$surname, ':login'=>$login, ':email'=>$email, ':password'=>$password, ':city'=>$city, ':country'=>$country,  ':date'=>$date));
    32. //ну как бы всё, далее идет проверка записались ли в бд, если да то Респект и.т.п
    Авторизация:
    Код (Text):
    1.  
    2. if (isset($_POST['login'])) { $login = $_POST['login']; if ($login == '') { unset($login);} } //Проверяю, если нет то удаляю
    3. if (isset($_POST['password'])) { $password=$_POST['password']; if ($password =='') { unset($password);} }
    4. if (empty($login) or empty($password))
    5. { exit("Вы не ввели логин или пароль!");}
    6. $login = stripslashes($login);
    7. $login = htmlspecialchars($login);
    8. $password = stripslashes($password);
    9. $password = htmlspecialchars($password);
    10. $login = trim($login);
    11. $password = trim($password);
    12. include ("bd.php");
    13. $ip=getenv("HTTP_X_FORWARDED_FOR"); //Далее я проверяю ip нужно для того чтобы сделать проверку сколько раз пользователь вводил логин и пароль неверно, если больше 2 то блокирую на 15 минут
    14. if (empty($ip) || $ip=='unknown') { $ip=getenv("REMOTE_ADDR"); }
    15. mysql_query ("DELETE FROM error WHERE UNIX_TIMESTAMP() - UNIX_TIMESTAMP(date) > 900");
    16. $stmts = $db->query("SELECT col FROM error WHERE ip='$ip'");
    17. $stmts->setFetchMode(PDO::FETCH_ASSOC);
    18. $myrows = $stmts->fetch();
    19. if ($myrows['col'] > 2) {
    20. exit("Вы набрали логин или пароль неверно 3 раза. Подождите 15 минут до следующей попытки.");
    21. }
    22. $password = md5 ($password);
    23. $password = strrev($password);
    24. $password = $password."тут всякая шн*га";
    25. $stmt = $db->prepare("SELECT * FROM users WHERE login=? AND password=?");
    26. $stmt->bindValue(1,$login, PDO::PARAM_INT);
    27. $stmt->bindValue(2, $password, PDO::PARAM_STR);
    28. $stmt->execute();
    29. $myrow = $stmt->fetch();
    30.  
    31. if (empty($myrow['id']))
    32. {
    33.  
    34.  
    35. $select = $db->prepare("SELECT ip FROM error WHERE ip=?");
    36. $select->bindValue(1,$ip, PDO::PARAM_INT);
    37. $select->execute();
    38. $tmp = $select->fetch();
    39.  
    40. if ($ip == $tmp[0]) {
    41.  
    42. $stmt3 = $db->prepare("SELECT col FROM error WHERE ip=?");
    43. $stmt3->bindValue(1,$ip, PDO::PARAM_INT);
    44. $stmt3->execute();
    45. $myrow52 = $stmt3->fetch();
    46.  
    47. $col = $myrow52[0] + 1;
    48. mysql_query ("UPDATE error SET col=$col,date=NOW() WHERE ip='$ip'");
    49. }
    50. else {
    51. mysql_query ("INSERT INTO error (ip,date,col) VALUES ('$ip',NOW(),'1')");
    52. }
    53. exit ("<center>Извините, введённый вами логин или пароль неверный.<br><input type='submit' onclick='history.back();' name='submit' value='Вернуться назад'  class='yellow-btn'></center>");
    54. }
    Проверка на странице / личная страница пользователя:
    Код (Text):
    1.  
    2. session_start();
    3. header("Content-type: text/html; charset=utf-8");
    4. include ("bd.php");
    5. if (isset($_SESSION['id'])) {$id =$_SESSION['id']; }
    6. else
    7. { exit("<h3>Вы зашил на страницу без параметра.Вернитесь назад и заполните все данные <a href='index.php'>Назад</a></h3>");}
    8. if (!preg_match("|^[\d]+$|", $id)) {
    9. exit("<p><h3>Неверный формат запроса! Проверьте URL</h3></p>");
    10. }
    11. if (!empty($_SESSION['login']) and !empty($_SESSION['password']))
    12. {
    13. $login = htmlspecialchars("$_SESSION[login]");
    14. $password = htmlspecialchars("$_SESSION[password]");
    15. $login=stripslashes(trim("$_SESSION[login]"));
    16. $password=stripslashes(trim("$_SESSION[password]"));
    17.  
    18.  
    19. $stmt = $db->prepare("SELECT id FROM users WHERE login=? AND password=?");
    20. $stmt->bindValue(1,$login, PDO::PARAM_INT);
    21. $stmt->bindValue(2, $password, PDO::PARAM_STR);
    22. $stmt->execute();
    23. $myrow = $stmt->fetch();
    24.  
    25. if (empty($myrow['id']))
    26.    {
    27.     exit("<center>Вход на эту страницу разрешен только зарегистрированным.</center>");
    28.    }
    29. }
    30. else {
    31. exit("<center>Вход на эту страницу разрешен только зарегистрированным.</center>"); }
    32.  
    33.  
    34.  
    35. $stmt = $db->prepare("SELECT * FROM users WHERE id=?");
    36. $stmt->bindValue(1,$id, PDO::PARAM_INT);
    37. $stmt->execute();
    38. $row = $stmt->fetch();
    39.  
    40.  
    41. if (empty($row['login'])) { exit("<center>Пользователя не существует!</center>");}
    Подключение к бд:
    Код (Text):
    1.  
    2. try {
    3.   $db = new PDO('mysql:host=localhost;dbname=page', 'лог', 'пароль');
    4.   $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    5.   $db->exec("set names utf8");
    6. }
    7. catch(PDOException $e) {
    8.     echo $e->getMessage();
    9. }
     
  2. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.251
    Адрес:
    там-сям
    я тебя помню именно по этому "эксклюзивные материалы". в реальности люди так не говорят, только в рекламных роликах :)
    почему ты думаешь, что виноваты инъекции?
     
  3. ainur777

    ainur777 Активный пользователь

    С нами с:
    24 май 2013
    Сообщения:
    93
    Симпатии:
    0
    Меняли логины некторых пользователей и в 3 топиках вместо материала, написали всякую ерунду.

    Добавлено спустя 14 минут 50 секунд:
    К стати при регистрации есть поле id, это поле для реф ссылки статьи. Если нет то ему присваивается статься, это нужно для того чтобы он лайкнул. Один из условии, при регистрации нужно поставить лайк на статью.
    я делаю так:
    Код (Text):
    1.  
    2. function vote() {
    3.  
    4.     var req = getXmlHttp()        
    5.  
    6.     var statusElem = document.getElementById('statia')
    7.     var statusElem2 = document.getElementById('statia2')
    8.     req.onreadystatechange = function() {  
    9.  
    10.         if (req.readyState == 4) {
    11.  
    12.  
    13.             if(req.status == 200) {
    14.  
    15.                 alert("Вам назначена статья, оцените её после регистрации ");
    16.                 document.querySelector('#id').value = req.responseText;
    17.  
    18.             }
    19.  
    20.         }
    21.     }
    22.  
    23.     req.open('GET', 'poisk.php', true);  
    24.  
    25.  
    26.     req.send(null);
    27.  
    28.     statusElem.innerHTML = 'Поиск статьи...'
    29.  
    30. }
    31. </script>
    а в poisk.php следующее:
    Вытаскиваю так
    Код (Text):
    1.  
    2. include ("bd.php");
    3. $stmt = $db->prepare("SELECT * FROM `statia` WHERE laik>=? AND laik<=? ORDER BY RAND() LIMIT 1");
    4. $stmt->bindValue(1,0, PDO::PARAM_INT);
    5. $stmt->bindValue(2, 10, PDO::PARAM_STR);
    6. $stmt->execute();
    7. $row = $stmt->fetch();
    8.  
    9.  
    10.  
    11. sleep(3);
    12. echo "$row[id]"; //т.е я вывожу id статью с наименьшим лайком от 0 до 10
     
  4. smitt

    smitt Старожил

    С нами с:
    3 янв 2012
    Сообщения:
    3.166
    Симпатии:
    65
    Не буду говорить что кодировка не правильно устанавливаешь, открой доки, но что там дальше
    Что там делает mysql?

    Добавлено спустя 3 минуты 20 секунд:
    Не легче

    if($_POST['login'] != ''){
    $login = $_POST['login'];
    }
    Как вообще у тебя что то работает?

    Добавлено спустя 3 минуты 9 секунд:
    Чувак твое приложение полный отстой, возможно дырыще у тебя где в другом месте и вряд ли ты это найдешь.
    Выкладывай исходники или ссыль на сайт, может надется человек кто протестирует это.
     
  5. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    Кто совершит подвиг и наконец-то сделает мануал по экранированию? Прилеплю в mysql разделе.
     
  6. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.600
    Симпатии:
    1.764
    Вообще, вроде большинство запросов через плейсхолдеры, не должно быть sql-инъекций. В логах доступа есть sql-команды?
     
  7. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.131
    Симпатии:
    1.251
    Адрес:
    там-сям
    в прошлый раз я уже писал тебе, что система уязвима настолько, насколько уязвимо ее самое слабое звено. а ты по прежнему трендишь "вроде в большинстве мест...".

    сам себе злобный буратино. заплати уже один раз чтобы твое лоскутное одеялко поменяли на что-то нормальное.
     
  8. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.600
    Симпатии:
    1.764
    Код (Text):
    1. $id = htmlspecialchars($_POST['id']);
    2. $id =stripslashes(trim($_POST['id']));
    3. $name = htmlspecialchars($_POST['name']);
    4. $name =stripslashes(trim($_POST['name']));
    5. $surname = htmlspecialchars($_POST['surname']);
    6. $surname =stripslashes(trim($_POST['surname']));
    7. $city = htmlspecialchars($_POST['city']);
    8. $city =stripslashes(trim($_POST['city']));
    9. $email = htmlspecialchars($_POST['email ']);
    10. $email  =stripslashes(trim($_POST[email ']));
    11. $login = htmlspecialchars($_POST['login']);
    12. $login=stripslashes(trim($_POST['login']));
    13. $password = htmlspecialchars($_POST['password']);
    14. $password=stripslashes(trim($_POST['password']));
    Вот эта вся фигня не нужна
     
  9. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    Да это вообще капец
     
  10. smitt

    smitt Старожил

    С нами с:
    3 янв 2012
    Сообщения:
    3.166
    Симпатии:
    65
    Да ладно, подожди немного ему скоро надоест или хакнет окончательно и все исправит :)

    По теме глянь
    http://php.ru/manual/pdo.construct.html#113498
    http://php.ru/manual/ref.pdo-mysql.connection.html

    Если ты используешь prepared statement то тебя не взламают. Ищи где ты пропустил... а возможно ошибка где то в другом месте.
     
  11. VLK

    VLK Старожил

    С нами с:
    15 дек 2013
    Сообщения:
    3.010
    Симпатии:
    58
    Что то я не совсем понимаю в чем юмор вот этого вот:
    Код (PHP):
    1. $id = htmlspecialchars($_POST['id']);
    2. $id =stripslashes(trim($_POST['id'])); 
    Добавлено спустя 14 минут 39 секунд:
    ainur777, тебе не приходило в голову использовать массив для данных пользователя, вот так вот:
    Код (PHP):
    1. $data = array( 'id' => NULL, 'name' => NULL, 'surname' => NULL /* и т.д. */ );
    ключи как видишь совпадают с теми что будет в массиве $_POST, а потом сделать просто вот так вот:
    Код (PHP):
    1. foreach($data as $key => $value)
    2. {
    3.     if ($_POST[$key] != '')
    4.     {
    5.         $data[$key] = stripslashes( trim( htmlspecialchars($_POST[$key]) ) );
    6.     }
    7. }
    и потом крутить этот массив через foreach как за хочешь.
     
  12. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.600
    Симпатии:
    1.764
    VLK, зачем это всё? Плейсхолдеров более чем достаточно перед добавлением в базу данных, htmlspecialchars нужен перед выводом.

    ainur777, Вы бы посмотрели, может вам шеллы где заливают? SQL-инъекции не являются единственным способом взлома.
     
  13. VLK

    VLK Старожил

    С нами с:
    15 дек 2013
    Сообщения:
    3.010
    Симпатии:
    58
    я показал только подход укорочения кода, все остальное, пропускание через всякие stripslashes( trim( htmlspecialchars, это взято из кода автара.
     
  14. rognorog

    rognorog Новичок

    С нами с:
    7 июл 2014
    Сообщения:
    330
    Симпатии:
    0
    Могу сделать, когда приеду, через 2 - 3 дня начну только делать?
    Оформлю нормально и покажу все в разных стилях? М?
    Это не имеет значения, ты должен был ему дать нормальный пример или совет.
    А ты дал херню.
    Для работы со строкой для записи в базу нужно использовать экранирование
    А также для числовых данных, воспользоваться приведением к типу: (int), (double) <-> (float) манипуляции с типами.

    А при выводе из базы также делать уже обработку и то которая может даже не потребоваться в некоторых случаях.
    Можно обезопасить html от <script> и других ресурсов, а так тут думаю и не потребуется больше ничего обрабатывать.

    Разные задачи бывают, по этому тут как бы нужно гибкую функцию делать.
    Просто подумай, для каких целей у тебя поля в таблице по ним и сделай свой модуль.