За последние 24 часа нас посетили 22384 программиста и 1150 роботов. Сейчас ищут 642 программиста ...

Безопасно ли формирование запроса?

Тема в разделе "PHP и базы данных", создана пользователем Ggatsby, 17 сен 2017.

  1. Ggatsby

    Ggatsby Новичок

    С нами с:
    9 фев 2017
    Сообщения:
    9
    Симпатии:
    0
    Вечер добрый, собственно, интересно услышать мнение бывалых о дырявости реализации собирания и выполнения запроса.
    Пример get запроса - mysite.com/api/customers/search/first_name=John&last_name=Doe&phone=0987654321
    Делаю апишечку на Slim фреймворке, и собственно данный путь должен парсить входящую строку и выводить пользователей с необходимыми аттрибутами:

    PHP:
    1. $app->get('/api/customers/search/{query}', function(Request $request, Response $response) {
    2.     $name = $request->getAttribute('query');
    3.  
    4.     parse_str($name, $parsedQuery);
    5.  
    6.     $q = '';
    7.     $bindings = [];
    8.     // Определяем необходимость AND в sql запросе.
    9.     $putAnd = false;
    10.    
    11.     foreach ($parsedQuery as $key => $value) {
    12.         if ($putAnd && !empty($value)) {
    13.             $q .= ' AND ';
    14.         }
    15.  
    16.         if (!empty($value)) {
    17.             $q .= "$key = :$key";
    18.             $bindings[] = "$key";
    19.             $putAnd = true;
    20.         }
    21.     }
    22.    
    23.     if (!empty($q)) {
    24.         $sql = "SELECT * FROM customers WHERE $q";
    25.     } else {
    26.         $sql = "SELECT * FROM customers";
    27.     }
    28.  
    29.     try {
    30.         $db = new db();
    31.         $db = $db->connect();
    32.  
    33.         $stmt = $db->prepare($sql);
    34.         foreach ($bindings as $value) {
    35.             $stmt->bindParam(":$value", $parsedQuery["$value"]);
    36.         }
    37.         $stmt->execute();
    38.  
    39.         $result = $stmt->fetchAll(PDO::FETCH_OBJ);
    40.         $db = null;
    41.         echo json_encode($result);
    42.     } catch(PDOException $e){
    43.         echo '{"error": {"text": '.$e->getMessage().'}';
    44.     }
    45. });
    Спасибо.
     
  2. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.155
    Симпатии:
    1.769
    Адрес:
    :сердА
    Зачем?
    И, если честно, код слишком индусский. В чем смысл такого усложнения? И зачем не глядя(!!!) формировать WHERE из гета? Это прям врата к тебе в БД. Открытые. С вывеской "Заходи кто хочет!"
     
  3. Ggatsby

    Ggatsby Новичок

    С нами с:
    9 фев 2017
    Сообщения:
    9
    Симпатии:
    0
    По задумке должно соединять WHERE условия.

    Код-то индусский, не спорю. Касательно WHERE из гета, в какую сторону копнуть для закрытия врат?
     
  4. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.155
    Симпатии:
    1.769
    Адрес:
    :сердА
    Ну как минимум не пилить неглядя запрос на основе гет-параметров, даже не сверяя их с неким белым списком.
    Как максимум - отказаться от такого механизма в принципе. Абстракции это круто, но не в случае, когда они опираются на данные, приходящие извне. Data-driven logic вообще тема довольно тонкая и опасная. У нас тут не лабораторные задачи по лиспу. У нас тут веб. Надо быть параноиком и всегда исходить из того, что клиент - злоумышленник.
     
    AlexandrS нравится это.
  5. Ggatsby

    Ggatsby Новичок

    С нами с:
    9 фев 2017
    Сообщения:
    9
    Симпатии:
    0
    Fell-x27, спасибо за разъяснения. Зачастую не хватает стороннего мнения опытного человека и палки, чтобы по пальцам вовремя прихватывать. Попробую переписать без белого списка и поискать иные пути решения задачи.
     
  6. Ggatsby

    Ggatsby Новичок

    С нами с:
    9 фев 2017
    Сообщения:
    9
    Симпатии:
    0
    @Fell-x27, а можно пример вредоносного кода, для наглядности, к моей индусской реализации? В customers есть поля id, first_name, last_name, phone.
     
  7. Fell-x27

    Fell-x27 Суперстар
    Команда форума Модератор

    С нами с:
    25 июл 2013
    Сообщения:
    12.155
    Симпатии:
    1.769
    Адрес:
    :сердА
    Почитай документацию по MySQL. Секция WHERE принимает на вход любое логическое выражение. При этом каждый операнд выражения может быть получен абсолютно любым путем, включая селекты с джоинами со вложенными селектами. Плюс, вполне реально тебе вкрутить сюда инъекцию в последнем параметре для where. Хотя, если подумать, то этот колхоз после биндинга, технически вообще работать не должен. У тебя ошибок синтаксиса нет там, случайно при исполнении запросов, содержащих текстовые данные? Если работает, то тебе можно не парясь вкрутить инъекцию, да.