Как я могу предотвратить SQL-инъекцию в PHP?

Если пользовательский ввод вставлен без изменений в SQL-запрос, тогда приложение становится уязвимым для SQL-инъекции , как в следующем примере:

 $unsafe_variable = $_POST['user_input']; 

mysql_query("INSERT INTO `table` (`column`) VALUES ('$unsafe_variable')");
 

Это потому, что пользователь может вводить что-то вроде value'); DROP TABLE table;-- , и запрос становится:

 INSERT INTO `table` (`column`) VALUES('value'); DROP TABLE table;--')
 

Что можно сделать, чтобы это не произошло?

вопрос задан 12.09.2008
Andrew G. Johnson
13270 репутация

28 ответов


  • 0 рейтинг

    Если возможно, введите типы параметров. Но он работает только с простыми типами, такими как int, bool и float.

     $unsafe_variable = $_POST['user_id'];
    
    $safe_variable = (int)$unsafe_variable ;
    
    mysqli_query($conn, "INSERT INTO table (column) VALUES ('" . $safe_variable . "')");
     
    ответ дан devOp, с репутацией 2879, 12.06.2012
  • 0 рейтинг

    Я бы рекомендовал использовать PDO (объекты данных PHP) для запуска параметризованных SQL-запросов.

    Это не только защищает от SQL-инъекций, но и ускоряет выполнение запросов.

    И используя PDO вместо функций mysql_ , mysqli_ и pgsql_ , вы делаете свое приложение немного более абстрактным из базы данных, в редких случаях, когда вам приходится переключать поставщиков баз данных.

    ответ дан Kibbee, с репутацией 50900, 13.09.2008
  • 0 рейтинг

    Несколько рекомендаций по экранированию специальных символов в операторах SQL.

    Не используйте MySQL , это расширение устарело, используйте MySQLi или PDO .

    MySQLi

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

    Пример:

     $mysqli = new mysqli( 'host', 'user', 'password', 'database' );
    $mysqli->set_charset( 'charset');
    
    $string = $mysqli->real_escape_string( $string );
    $mysqli->query( "INSERT INTO table (column) VALUES ('$string')" );
     

    Для автоматического экранирования значений с помощью подготовленных операторов используйте mysqli_prepare и mysqli_stmt_bind_param, где должны быть указаны типы для соответствующих переменных привязки для соответствующего преобразования:

    Пример:

     $stmt = $mysqli->prepare( "INSERT INTO table ( column1, column2 ) VALUES (?,?)" );
    
    $stmt->bind_param( "is", $integer, $string );
    
    $stmt->execute();
     

    Независимо от того, используете ли вы подготовленные операторы или mysqli_real_escape_string, вам всегда нужно знать тип входных данных, с которыми вы работаете.

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

    И использование mysqli_real_escape_string для, как сказано в названии, означает экранирование специальных символов в строке, поэтому оно не сделает целые числа безопасными. Цель этой функции - предотвратить разрыв строк в операторах SQL и повреждение базы данных, которое она может вызвать. mysqli_real_escape_string - полезная функция при правильном использовании, особенно в сочетании с sprintf.

    Пример:

     $string = "x' OR name LIKE '%John%";
    $integer = '5 OR id != 0';
    
    $query = sprintf( "SELECT id, email, pass, name FROM members WHERE email ='%s' AND id = %d", $mysqli->real_escape_string( $string ), $integer );
    
    echo $query;
    // SELECT id, email, pass, name FROM members WHERE email ='x\' OR name LIKE \'%John%' AND id = 5
    
    $integer = '99999999999999999999';
    $query = sprintf( "SELECT id, email, pass, name FROM members WHERE email ='%s' AND id = %d", $mysqli->real_escape_string( $string ), $integer );
    
    echo $query;
    // SELECT id, email, pass, name FROM members WHERE email ='x\' OR name LIKE \'%John%' AND id = 2147483647
     
    ответ дан Danijel, с репутацией 9505, 9.05.2013
  • 0 рейтинг

    Предупреждение: примерный код ответа (например, примерный код вопроса) использует расширение PHP mysql , которое устарело в PHP 5.5.0 и полностью удалено в PHP 7.0.0.

    Если вы используете последнюю версию PHP, описанный ниже вариант mysql_real_escape_string больше не будет доступен (хотя mysqli::escape_string - это современный эквивалент). В эти дни вариант mysql_real_escape_string будет иметь смысл только для устаревшего кода на старой версии PHP.


    У вас есть два варианта: экранирование специальных символов в unsafe_variable или использование параметризованного запроса. Оба будут защищать вас от SQL-инъекций. Параметрированный запрос считается лучшей практикой, но для его использования потребуется переходить на более новое расширение mysql в PHP.

    Мы рассмотрим нижнюю ударную струну, которая будет первой.

     //Connect
    
    $unsafe_variable = $_POST["user-input"];
    $safe_variable = mysql_real_escape_string($unsafe_variable);
    
    mysql_query("INSERT INTO table (column) VALUES ('" . $safe_variable . "')");
    
    //Disconnect
     

    См. Также подробную информацию о функции mysql_real_escape_string .

    Чтобы использовать параметризованный запрос, вам нужно использовать MySQLi, а не функции MySQL . Чтобы переписать ваш пример, нам нужно что-то вроде следующего.

     <?php
        $mysqli = new mysqli("server", "username", "password", "database_name");
    
        // TODO - Check that connection was successful.
    
        $unsafe_variable = $_POST["user-input"];
    
        $stmt = $mysqli->prepare("INSERT INTO table (column) VALUES (?)");
    
        // TODO check that $stmt creation succeeded
    
        // "s" means the database expects a string
        $stmt->bind_param("s", $unsafe_variable);
    
        $stmt->execute();
    
        $stmt->close();
    
        $mysqli->close();
    ?>
     

    Ключевой функцией, которую вы хотите прочитать, будет mysqli::prepare .

    Кроме того, как предложили другие, вы можете сочтет полезным / легче повысить уровень абстракции с помощью чего-то вроде PDO .

    Обратите внимание, что случай, о котором вы просили, довольно простой, и что более сложные случаи могут потребовать более сложных подходов. В частности:

    • Если вы хотите изменить структуру SQL на основе ввода пользователем, параметризованные запросы не помогут, и требуемое экранирование не покрывается mysql_real_escape_string . В этом случае вам лучше было бы пропускать вход пользователя через белый список, чтобы обеспечить только «безопасные» значения.
    • Если вы используете целые числа из пользовательского ввода в состоянии и применяете подход mysql_real_escape_string , вы столкнетесь с проблемой, описанной Polynomial в комментариях ниже. Этот случай более сложный, поскольку целые числа не будут окружены кавычками, поэтому вы можете справиться, подтвердив, что пользовательский ввод содержит только цифры.
    • Вероятно, есть другие случаи, о которых я не знаю. Вы можете обнаружить, что это полезный ресурс по некоторым из более тонких проблем, с которыми вы можете столкнуться.
    ответ дан Matt Sheppard, с репутацией 65888, 13.09.2008
  • 0 рейтинг

    Предупреждение о безопасности . Этот ответ не соответствует рекомендациям по безопасности. Эвакуация неадекватна для предотвращения внедрения SQL , вместо этого используйте подготовленные инструкции . Используйте стратегию, изложенную ниже, на свой страх и риск. (Кроме того, mysql_real_escape_string() был удален в PHP 7.)

    Вы могли бы сделать что-то основное:

     $safe_variable = mysql_real_escape_string($_POST["user-input"]);
    mysql_query("INSERT INTO table (column) VALUES ('" . $safe_variable . "')");
     

    Это не решит каждую проблему, но это очень хороший шаг. Я оставил очевидные элементы, такие как проверка существования переменной, формат (числа, буквы и т. Д.).

    ответ дан Tanerax, с репутацией 5183, 13.09.2008
  • 0 рейтинг

    Независимо от того, что вы делаете в конечном итоге, убедитесь, что вы проверяете, что ваш вход еще не был искалечен magic_quotes или каким-либо другим хорошо продуманным мусором, и, если необходимо, запустите его через stripslashes или что-нибудь, чтобы его дезинфицировать.

    ответ дан Rob, с репутацией 43150, 8.12.2008
  • 0 рейтинг

    Я думаю, что если кто-то захочет использовать PHP и MySQL или какой-нибудь другой сервер базы данных:

    1. Подумайте об обучении PDO (объекты данных PHP) - это уровень доступа к базе данных, обеспечивающий единый метод доступа к нескольким базам данных.
    2. Подумайте об обучении MySQLi
    3. Используйте собственные функции PHP, такие как strip_tags , mysql_real_escape_string или переменная числовая, всего (int)$foo . Подробнее о типах переменных в PHP читайте здесь . Если вы используете библиотеки, такие как PDO или MySQLi, всегда используйте PDO :: quote () и mysqli_real_escape_string () .

    Примеры библиотек:

    ---- PDO

    ----- Без заполнителей - спелые для SQL-инъекций! Это плохо

     $request = $pdoConnection->("INSERT INTO parents (name, addr, city) values ($name, $addr, $city)");
     

    ----- Без названия

     $request = $pdoConnection->("INSERT INTO parents (name, addr, city) values (?, ?, ?);
     

    ----- Именованные заполнители

     $request = $pdoConnection->("INSERT INTO parents (name, addr, city) value (:name, :addr, :city)");
     

    --- MySQLi

     $request = $mysqliConnection->prepare('
           SELECT * FROM trainers
           WHERE name = ?
           AND email = ?
           AND last_login > ?');
    
        $query->bind_param('first_param', 'second_param', $mail, time() - 3600);
        $query->execute();
     

    PS :

    PDO выигрывает эту битву с легкостью. Благодаря поддержке двенадцати различных драйверов баз данных и именованных параметров мы можем игнорировать небольшую потерю производительности и привыкнуть к ее API. С точки зрения безопасности, оба они безопасны, пока разработчик использует их так, как они должны использоваться

    Но хотя PDO и MySQLi довольно быстры, MySQLi работает незначительно быстрее в тестах - ~ 2,5% для незаготовленных операторов и ~ 6.5% для готовых.

    И, пожалуйста, проверьте каждый запрос в своей базе данных - это лучший способ предотвратить инъекцию.

    ответ дан RDK, с репутацией 4176, 10.10.2012
  • 0 рейтинг

    Если вы хотите использовать кэш-движки, такие как Redis или Memcached , возможно, DALMP может быть выбором. Он использует чистый MySQLi . Проверьте это: Уровень абстракции базы данных DALMP для MySQL с использованием PHP.

    Кроме того, вы можете «подготовить» свои аргументы перед подготовкой своего запроса, чтобы вы могли создавать динамические запросы и в конце иметь полностью подготовленный запрос. Уровень абстракции базы данных DALMP для MySQL с использованием PHP.

    ответ дан nbari, с репутацией 10361, 15.10.2012
  • 0 рейтинг

    Что касается многих полезных ответов, я надеюсь добавить некоторые значения в этот поток. SQL-инъекция - это атака, которая может быть выполнена через пользовательские входы (входные данные, заполненные пользователем, а затем используемые внутри запросов). Шаблоны инъекций SQL - это правильный синтаксис запроса, в то время как мы можем назвать это: плохие запросы по неверным причинам, мы предполагаем, что быть плохим человеком, который пытается получить секретную информацию (в обход контроля доступа), которая влияет на три принципа безопасности (конфиденциальность, целостность, доступность).

    Теперь мы хотим предотвратить угрозы безопасности, такие как атаки SQL-инъекций, вопрос (как предотвратить атаку SQL-инъекций с использованием PHP), быть более реалистичным, фильтрация данных или очистка входных данных - это случай, когда пользовательские входные данные внутри таких запрос, использование PHP или любого другого языка программирования не так, или, как рекомендовано больше людей, использовать современные технологии, такие как подготовленный оператор или любые другие инструменты, которые в настоящее время поддерживают предотвращение внедрения SQL-инъекций, считают, что эти инструменты недоступны? Как вы защищаете свое приложение?

    Мой подход к внедрению SQL - это очистка пользовательских данных перед отправкой их в базу данных (прежде чем использовать ее в любом запросе).

    Фильтрация данных для (Преобразование небезопасных данных в безопасные данные). Убедитесь, что PDO и MySQLi недоступны, как вы можете защитить свое приложение? Вы заставляете меня использовать их? Как насчет других языков, кроме PHP? Я предпочитаю предлагать общие идеи, поскольку он может использоваться для более широкой границы не только для конкретного языка.

    1. Пользователь SQL (ограничение привилегий пользователя): наиболее распространенными операциями SQL являются (SELECT, UPDATE, INSERT), а затем, почему предоставление привилегий UPDATE пользователю, который этого не требует? Например, логин и поисковые страницы используют только SELECT, а затем зачем использовать пользователей БД на этих страницах с высокими привилегиями? ПРАВИЛО: не создавайте одного пользователя базы данных для всех привилегий, для всех операций SQL вы можете создать свою схему как (deluser, selectuser, updateuser) в качестве имен пользователей для удобства использования.

    см. Принцип наименьших привилегий

    1. Фильтрация данных: перед созданием любого запроса пользовательский ввод должен быть проверен и отфильтрован, для программистов важно определить некоторые свойства для каждого пользовательского ввода: тип данных, шаблон данных и длину данных . поле, которое является числом между (x и y), должно быть точно проверено с использованием точного правила, для поля, которое является строкой (текстом): шаблон имеет значение, например, имя пользователя должно содержать только некоторые символы, позволяющие сказать [a- zA-Z0-9_-.] длина изменяется между (x и n), где x и n (целые числа, x <= n). Правило: создание точных фильтров и правил проверки - лучшая практика для меня.

    2. Используйте другие инструменты: здесь я также соглашусь с вами, что подготовленный оператор (параметризованный запрос) и хранимые процедуры, недостатки здесь - эти способы требуют передовых навыков, которых не существует для большинства пользователей, основная идея здесь заключается в том, чтобы различать SQL-запрос и данные, которые используются внутри, оба подхода могут использоваться даже с небезопасными данными, поскольку входные данные пользователя здесь ничего не добавляют к исходному запросу, например (any или x = x). Для получения дополнительной информации, пожалуйста, прочитайте Cheat Sheet OWASP SQL Injection Prevention .

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

    Наконец, давайте рассмотрим, что пользователь отправляет этот текст ниже, а не вводит его имя пользователя:

     [1] UNION SELECT IF(SUBSTRING(Password,1,1)='2',BENCHMARK(100000,SHA1(1)),0) User,Password FROM mysql.user WHERE User = 'root'
     

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

    Последнее указывает на обнаружение неожиданного поведения, которое требует больших усилий и сложности; это не рекомендуется для обычных веб-приложений. Неожиданным поведением в пользовательском входе является SELECT, UNION, IF, SUBSTRING, BENCHMARK, SHA, root после обнаружения этих слов, вы можете избежать ввода.

    Update1:

    Пользователь прокомментировал, что этот пост бесполезен, ОК! Вот что предлагает OWASP.ORG :

    Первичная защита:

    Вариант №1: Использование подготовленных заявлений (параметризованные запросы)
    Вариант № 2: Использование хранимых процедур
    Вариант № 3: экранирование всех входных данных пользователя

    Дополнительная защита:

    Также соблюдайте минимальную привилегию
    Также выполните: подтверждение ввода белого списка

    Как вы знаете, заявка на статью должна поддерживаться действительным аргументом, по крайней мере, одной ссылкой! В противном случае это считается атакой и плохим требованием!

    Update2:

    Из руководства PHP, PHP: подготовленные заявления - руководство :

    Escaping и SQL-инъекция

    Связанные переменные автоматически экранируются сервером. Сервер вставляет свои экранированные значения в соответствующие места в шаблон оператора перед выполнением. Чтобы создать соответствующее преобразование, сервер должен указать подсказку для типа связанной переменной. Дополнительную информацию см. В функции mysqli_stmt_bind_param ().

    Автоматическое экранирование значений внутри сервера иногда считается защитой для предотвращения внедрения SQL. Такая же степень безопасности может быть достигнута с помощью незаготовленных операторов, если входные значения сбрасываются правильно.

    Update3:

    Я создал тестовые примеры, чтобы узнать, как PDO и MySQLi отправляют запрос на сервер MySQL при использовании подготовленного оператора:

    PDO:

     $user = "''1''"; //Malicious keyword
    $sql = 'SELECT * FROM awa_user WHERE userame =:username';
    $sth = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
    $sth->execute(array(':username' => $user));
     

    Журнал запросов:

         189 Query SELECT * FROM awa_user WHERE userame ='\'\'1\'\''
        189 Quit
     

    MySQLi:

     $stmt = $mysqli->prepare("SELECT * FROM awa_user WHERE username =?")) {
    $stmt->bind_param("s", $user);
    $user = "''1''";
    $stmt->execute();
     

    Журнал запросов:

         188 Prepare   SELECT * FROM awa_user WHERE username =?
        188 Execute   SELECT * FROM awa_user WHERE username ='\'\'1\'\''
        188 Quit
     

    Понятно, что подготовленный оператор также избегает данных, ничего другого.

    Как также упоминалось в предыдущем заявлении The automatic escaping of values within the server is sometimes considered a security feature to prevent SQL injection. The same degree of security can be achieved with non-prepared statements, if input values are escaped correctly , это доказывает, что проверка данных, такая как intval() является хорошей идеей для целочисленных значений перед отправкой любого запроса, кроме того, предотвращение вредоносных пользовательских данных перед отправкой запроса является правильным и допустимым .

    Подробнее см. Этот вопрос: PDO отправляет необработанный запрос в MySQL, в то время как Mysqli отправляет подготовленный запрос, оба дают тот же результат

    Рекомендации:

    1. Шифрование SQL Injection Cheat Sheet
    2. SQL-инъекция
    3. Информационная безопасность
    4. Принципы безопасности
    5. Валидация данных
    ответ дан Apurv Nerlekar, с репутацией 2102, 28.01.2013
  • 0 рейтинг

    Простую альтернативу этой проблеме можно решить, предоставив соответствующие разрешения в самой базе данных. Например: если вы используете базу данных mysql, введите в базу данных через терминал или предоставленный интерфейс и просто следуйте этой команде:

      GRANT SELECT, INSERT, DELETE ON database TO username@'localhost' IDENTIFIED BY 'password';
     

    Это ограничит пользователя только ограничиться только указанным запросом. Удалите разрешение удаления, и поэтому данные никогда не будут удалены из запроса, запущенного с php-страницы. Второе, что нужно сделать, это очистить привилегии, чтобы mysql обновлял разрешения и обновления.

     FLUSH PRIVILEGES; 
     

    Дополнительная информация о флеше .

    Чтобы просмотреть текущие привилегии для пользователя, выполните следующий запрос.

     select * from mysql.user where User='username';
     

    Узнайте больше о GRANT .

    ответ дан Apurv Nerlekar, с репутацией 2102, 25.10.2012
  • 0 рейтинг

    Каждый ответ здесь охватывает только часть проблемы.
    На самом деле, есть четыре различных части запроса, которые мы можем добавить к ней динамически:

    • строка
    • число
    • идентификатор
    • ключевое слово синтаксиса.

    и подготовленные заявления охватывают только 2 из них

    Но иногда мы должны сделать наш запрос еще более динамичным, добавив операторы или идентификаторы.
    Таким образом, нам понадобятся разные методы защиты.

    В целом такой подход защиты основан на « белом списке» . В этом случае каждый динамический параметр должен быть жестко закодирован в вашем скрипте и выбран из этого набора.
    Например, для динамического упорядочения:

     $orders  = array("name","price","qty"); //field names
    $key     = array_search($_GET['sort'],$orders)); // see if we have such a name
    $orderby = $orders[$key]; //if not, first one will be set automatically. smart enuf :)
    $query   = "SELECT * FROM `table` ORDER BY $orderby"; //value is safe
     

    Однако есть еще один способ защитить идентификаторы - экранирование. Пока вы указываете идентификатор, вы можете избежать обратных звонков внутри, удвоив их.

    В качестве дальнейшего шага мы можем заимствовать поистине блестящую идею использования некоторого заполнителя (прокси для представления фактического значения в запросе) из подготовленных операторов и изобретать местозаполнитель другого типа - заполнителя идентификатора.

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

    Таким образом, общая рекомендация может быть сформулирована как
    Пока вы добавляете динамические части в запрос с использованием заполнителей (и эти правильно оформленные заполнители, конечно,), вы можете быть уверены, что ваш запрос безопасен .

    Тем не менее, есть проблема с ключевыми словами синтаксиса SQL (например, AND , DESC и так далее), но белый список - единственный подход в этом случае.

    Обновить

    Несмотря на то, что существует общее согласие в отношении наилучшей практики в области защиты от SQL-инъекций, существует еще много плохих методов. И некоторые из них слишком глубоко укоренены в умах пользователей PHP. Например, на этой самой странице есть (хотя и невидимые для большинства посетителей) более 80 удаленных ответов - все они удалены сообществом из-за плохого качества или продвижения плохих и устаревших практик. Хуже того, некоторые из плохих ответов не удаляются, а скорее процветают.

    Например, есть (1) являются (2) до сих пор (3) много (4) ответов (5) , в том числе второго по upvoted ответа предлагая вам вручную строку вытекающей - устаревший подход , который , как доказано быть небезопасными.

    Или есть немного лучший ответ, который предлагает только другой метод форматирования строк и даже может похвастаться им как окончательной панацеей. Хотя, конечно, это не так. Этот метод не лучше обычного форматирования строки, но он сохраняет все свои недостатки: он применим только к строкам и, как и любое другое ручное форматирование, по существу является необязательной, необязательной мерой, склонной к человеческой ошибке любого рода.

    Я думаю, что все это из-за одного очень старого суеверия, поддерживаемого такими авторитетами, как руководство OWASP или PHP , которое провозглашает равенство между тем, что «ускользает» и защищает от SQL-инъекций.

    Независимо от того, что написано в руководстве по PHP в течение веков, *_escape_string ни в коем случае не делает данные безопасными и никогда не предназначались. Помимо бесполезности для любой части SQL, отличной от строки, ручное экранирование неверно, поскольку оно является ручным, как автоматическое.

    И OWASP делает это еще хуже, подчеркивая, что вы избегаете ввода пользователя, что является полной бессмыслицей: таких слов в контексте защиты от инъекций не должно быть. Каждая переменная потенциально опасна - независимо от источника! Или, другими словами, каждая переменная должна быть должным образом отформатирована, чтобы быть помещенной в запрос - независимо от источника. Это вопрос назначения. В тот момент, когда разработчик начинает отделять овец от коз (думая, является ли какая-то конкретная переменная «безопасной» или нет), он делает свой первый шаг к катастрофе. Не говоря уже о том, что даже формулировка предполагает, что в точке входа происходит массовое ускорение, напоминающее очень волшебную функцию котировок - уже презренный, устаревший и удаленный.

    Таким образом, в отличие от любого «ускользания» подготовленные операторы являются мерой, которая действительно защищает от SQL-инъекции (когда это применимо).

    Если вы все еще не уверены в этом, вот пошаговое объяснение, которое я написал в «Руководстве по автостопщикам для предотвращения инъекций SQL» , где я подробно объяснил все эти вопросы и даже составил раздел, полностью посвященный плохой практике и их раскрытию.

    ответ дан Your Common Sense, с репутацией 1, 24.11.2011
  • 0 рейтинг

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

    ответ дан Deepak Thomas, с репутацией 1659, 25.06.2013
  • 0 рейтинг

    Я написал эту небольшую функцию несколько лет назад:

     function sqlvprintf($query, $args)
    {
        global $DB_LINK;
        $ctr = 0;
        ensureConnection(); // Connect to database if not connected already.
        $values = array();
        foreach ($args as $value)
        {
            if (is_string($value))
            {
                $value = "'" . mysqli_real_escape_string($DB_LINK, $value) . "'";
            }
            else if (is_null($value))
            {
                $value = 'NULL';
            }
            else if (!is_int($value) && !is_float($value))
            {
                die('Only numeric, string, array and NULL arguments allowed in a query. Argument '.($ctr+1).' is not a basic type, it\'s type is '. gettype($value). '.');
            }
            $values[] = $value;
            $ctr++;
        }
        $query = preg_replace_callback(
            '/{(\\d+)}/', 
            function($match) use ($values)
            {
                if (isset($values[$match[1]]))
                {
                    return $values[$match[1]];
                }
                else
                {
                    return $match[0];
                }
            },
            $query
        );
        return $query;
    }
    
    function runEscapedQuery($preparedQuery /*, ...*/)
    {
        $params = array_slice(func_get_args(), 1);
        $results = runQuery(sqlvprintf($preparedQuery, $params)); // Run query and fetch results.   
        return $results;
    }
     

    Это позволяет запускать операторы в однострочном C # -ish String.Format, например:

     runEscapedQuery("INSERT INTO Whatever (id, foo, bar) VALUES ({0}, {1}, {2})", $numericVar, $stringVar1, $stringVar2);
     

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

    ОБНОВЛЕНИЕ БЕЗОПАСНОСТИ: предыдущая версия str_replace допускала инъекции, добавляя токены {#} в пользовательские данные. Эта версия preg_replace_callback не вызывает проблем, если замена содержит эти токены.

    ответ дан Calmarius, с репутацией 8198, 18.02.2014
  • 0 рейтинг

    Используйте подготовленные заявления и параметризованные запросы. Это операторы SQL, которые отправляются и анализируются сервером базы данных отдельно от любых параметров. Таким образом, злоумышленник не может внедрить вредоносный SQL.

    У вас в основном есть два варианта:

    1. Использование PDO (для любого поддерживаемого драйвера базы данных):

       $stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');
      
      $stmt->execute(array('name' => $name));
      
      foreach ($stmt as $row) {
          // do something with $row
      }
       
    2. Использование MySQLi (для MySQL):

       $stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?');
      $stmt->bind_param('s', $name); // 's' specifies the variable type => 'string'
      
      $stmt->execute();
      
      $result = $stmt->get_result();
      while ($row = $result->fetch_assoc()) {
          // do something with $row
      }
       

    Если вы подключаетесь к базе данных, отличной от MySQL, есть вторая опция, зависящая от драйвера, к которой вы можете обратиться (например, pg_prepare() и pg_execute() для PostgreSQL). PDO является универсальным вариантом.

    Правильная настройка соединения

    Обратите внимание, что при использовании PDO для доступа к базе данных MySQL реальные подготовленные операторы по умолчанию не используются . Чтобы исправить это, вы должны отключить эмуляцию подготовленных операторов. Пример создания соединения с использованием PDO:

     $dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');
    
    $dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    $dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
     

    В приведенном выше примере режим ошибки не является абсолютно необходимым, но рекомендуется добавить его . Таким образом, сценарий не остановится с Fatal Error когда что-то пойдет не так. И это дает разработчику шанс на catch ошибок (я), которые составляют throw н. С PDOException с.

    Однако обязательной является первая $stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?'); $stmt->bind_param('s', $name); // 's' specifies the variable type => 'string' $stmt->execute(); $result = $stmt->get_result(); while ($row = $result->fetch_assoc()) { // do something with $row } строк, которая сообщает PDO об отключении эмулируемых подготовленных операторов и использовании реальных подготовленных операторов. Это гарантирует, что оператор и значения не будут разбираться с PHP перед отправкой на сервер MySQL (давая возможность злоумышленнику возможности внедрить вредоносный SQL).

    Хотя вы можете установить $stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?'); $stmt->bind_param('s', $name); // 's' specifies the variable type => 'string' $stmt->execute(); $result = $stmt->get_result(); while ($row = $result->fetch_assoc()) { // do something with $row } в опциях конструктора, важно отметить, что «более старые» версии PHP (<5.3.6) молча игнорировали параметр charset в DSN.

    объяснение

    Случается, что оператор SQL, который вы передаете в $stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?'); $stmt->bind_param('s', $name); // 's' specifies the variable type => 'string' $stmt->execute(); $result = $stmt->get_result(); while ($row = $result->fetch_assoc()) { // do something with $row } , анализируется и компилируется сервером базы данных. Указав параметры (либо $stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?'); $stmt->bind_param('s', $name); // 's' specifies the variable type => 'string' $stmt->execute(); $result = $stmt->get_result(); while ($row = $result->fetch_assoc()) { // do something with $row } либо именованный параметр, как $stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?'); $stmt->bind_param('s', $name); // 's' specifies the variable type => 'string' $stmt->execute(); $result = $stmt->get_result(); while ($row = $result->fetch_assoc()) { // do something with $row } в приведенном выше примере), вы указываете механизм базы данных, в который вы хотите включить фильтр. Затем, когда вы вызываете $stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?'); $stmt->bind_param('s', $name); // 's' specifies the variable type => 'string' $stmt->execute(); $result = $stmt->get_result(); while ($row = $result->fetch_assoc()) { // do something with $row } , подготовленный оператор объединяется со значениями параметров, которые вы указываете.

    Важно то, что значения параметров объединены с скомпилированным оператором, а не с строкой SQL. SQL-инъекция работает, обманывая сценарий, включая вредоносные строки, когда он создает SQL для отправки в базу данных. Поэтому, отправляя фактический SQL отдельно от параметров, вы ограничиваете риск того, что закончите то, чего не намеревались. Любые параметры, которые вы отправляете при использовании подготовленного оператора, будут обрабатываться только как строки (хотя механизм базы данных может сделать некоторую оптимизацию, поэтому, конечно, параметры могут также оказаться как числа). В приведенном выше примере, если переменная $stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?'); $stmt->bind_param('s', $name); // 's' specifies the variable type => 'string' $stmt->execute(); $result = $stmt->get_result(); while ($row = $result->fetch_assoc()) { // do something with $row } содержит $stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?'); $stmt->bind_param('s', $name); // 's' specifies the variable type => 'string' $stmt->execute(); $result = $stmt->get_result(); while ($row = $result->fetch_assoc()) { // do something with $row } результатом будет просто поиск строки $stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?'); $stmt->bind_param('s', $name); // 's' specifies the variable type => 'string' $stmt->execute(); $result = $stmt->get_result(); while ($row = $result->fetch_assoc()) { // do something with $row } , и вы не получите пустую таблицу .

    Еще одно преимущество использования подготовленных операторов состоит в том, что если вы выполняете один и тот же оператор много раз в одном сеансе, он будет обрабатываться и компилироваться один раз, что дает вам некоторую прирост скорости.

    О, и поскольку вы спросили о том, как это сделать для вставки, вот пример (с использованием PDO):

     $stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?');
    $stmt->bind_param('s', $name); // 's' specifies the variable type => 'string'
    
    $stmt->execute();
    
    $result = $stmt->get_result();
    while ($row = $result->fetch_assoc()) {
        // do something with $row
    }
     

    Могут ли подготовленные операторы использоваться для динамических запросов?

    Хотя вы все еще можете использовать подготовленные инструкции для параметров запроса, структура самого динамического запроса не может быть параметризована, а некоторые функции запроса не могут быть параметризованы.

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

     pg_prepare() 
    ответ дан Theo, с репутацией 112921, 13.09.2008
  • 0 рейтинг

    Использование PDO и MYSQLi - хорошая практика для предотвращения инъекций SQL, но если вы действительно хотите работать с функциями и запросами MySQL, было бы лучше использовать

    mysql_real_escape_string

     $unsafe_variable = mysql_real_escape_string($_POST['user_input']);
     

    Есть больше возможностей для предотвращения этого: например, идентификация - если вход представляет собой строку, число, символ или массив, существует так много встроенных функций, чтобы обнаружить это. Кроме того, было бы лучше использовать эти функции для проверки входных данных.

    is_string

     $unsafe_variable = (is_string($_POST['user_input']) ? $_POST['user_input'] : '');
     

    is_numeric

     $unsafe_variable = (is_numeric($_POST['user_input']) ? $_POST['user_input'] : '');
     

    И гораздо лучше использовать эти функции для проверки входных данных с помощью mysql_real_escape_string .

    ответ дан Rakesh Sharma, с репутацией 12198, 17.01.2014
  • 0 рейтинг

    Хорошей идеей является использование «объектно-реляционного картографа», такого как Idiorm :

     $user = ORM::for_table('user')
    ->where_equal('username', 'j4mie')
    ->find_one();
    
    $user->first_name = 'Jamie';
    $user->save();
    
    $tweets = ORM::for_table('tweet')
        ->select('tweet.*')
        ->join('user', array(
            'user.id', '=', 'tweet.user_id'
        ))
        ->where_equal('user.username', 'j4mie')
        ->find_many();
    
    foreach ($tweets as $tweet) {
        echo $tweet->text;
    }
     

    Это не только избавляет вас от SQL-инъекций, но и от синтаксических ошибок! Также поддерживает коллекции моделей с цепочкой методов для фильтрации или применения действий к нескольким результатам сразу и нескольких подключений.

    ответ дан Thomas Ahle, с репутацией 20791, 20.03.2014
  • 0 рейтинг

    Есть так много ответов для PHP и MySQL , но вот код для PHP и Oracle для предотвращения SQL-инъекций, а также регулярное использование драйверов oci8:

     $conn = oci_connect($username, $password, $connection_string);
    $stmt = oci_parse($conn, 'UPDATE table SET field = :xx WHERE ID = 123');
    oci_bind_by_name($stmt, ':xx', $fieldval);
    oci_execute($stmt);
     
    ответ дан Chintan Gor, с репутацией 769, 30.01.2014
  • 0 рейтинг

    Используя эту функцию PHP mysql_escape_string() вы можете быстро получить хорошую профилактику.

    Например:

     SELECT * FROM users WHERE name = '".mysql_escape_string($name_from_html_form)."'
     

    mysql_escape_string - Сбрасывает строку для использования в mysql_query

    Для большей профилактики вы можете добавить в конце ...

     wHERE 1=1   or  LIMIT 1
     

    Наконец, вы получаете:

     SELECT * FROM users WHERE name = '".mysql_escape_string($name_from_html_form)."' LIMIT 1
     
    ответ дан Nicolas Finelli, с репутацией 1926, 3.08.2012
  • 0 рейтинг

    Используйте PDO и подготовленные запросы.

    ( $conn - объект PDO )

     $stmt = $conn->prepare("INSERT INTO tbl VALUES(:id, :name)");
    $stmt->bindValue(':id', $id);
    $stmt->bindValue(':name', $name);
    $stmt->execute();
     
    ответ дан Imran, с репутацией 42190, 13.09.2008
  • 0 рейтинг

    Параметризованный запрос и проверка ввода - это путь. Существует много сценариев, в которых может произойти SQL-инъекция, хотя используется mysql_real_escape_string() .

    Эти примеры уязвимы для SQL-инъекций:

     $offset = isset($_GET['o']) ? $_GET['o'] : 0;
    $offset = mysql_real_escape_string($offset);
    RunQuery("SELECT userid, username FROM sql_injection_test LIMIT $offset, 10");
     

    или

     $order = isset($_GET['o']) ? $_GET['o'] : 'userid';
    $order = mysql_real_escape_string($order);
    RunQuery("SELECT userid, username FROM sql_injection_test ORDER BY `$order`");
     

    В обоих случаях вы не можете использовать ' для защиты инкапсуляции.

    Источник : непредвиденная инъекция SQL (когда Escaping недостаточно)

    ответ дан Cedric, с репутацией 2900, 3.07.2011
  • 0 рейтинг

    ВАЖНЫЙ

    Лучший способ предотвратить SQL Injection состоит в том, чтобы использовать подготовленные выражения вместо того, чтобы убегать , как демонстрирует принятый ответ .

    Существуют библиотеки, такие как Aura.Sql и EasyDB, которые позволяют разработчикам легче использовать подготовленные инструкции. Чтобы узнать больше о том, почему подготовленные заявления лучше остановить инъекции SQL , обратитесь к этому mysql_real_escape_string() байпасу и недавно исправленные уязвимости Инъекции Unicode SQL в WordPress .

    Предотвращение инъекций - mysql_real_escape_string ()

    У PHP есть специально созданная функция для предотвращения этих атак. Все, что вам нужно сделать, это использовать рот функции, mysql_real_escape_string .

    mysql_real_escape_string берет строку, которая будет использоваться в запросе MySQL и возвращает ту же строку, при которой все попытки SQL-инъекций безопасно экранированы. В принципе, это заменит эти неприятные цитаты ('), которые пользователь может ввести с заменой MySQL-заменителем, скрытой цитатой \'.

    ПРИМЕЧАНИЕ. Вы должны подключиться к базе данных, чтобы использовать эту функцию!

    // Подключение к MySQL

     $name_bad = "' OR 1'"; 
    
    $name_bad = mysql_real_escape_string($name_bad);
    
    $query_bad = "SELECT * FROM customers WHERE username = '$name_bad'";
    echo "Escaped Bad Injection: <br />" . $query_bad . "<br />";
    
    
    $name_evil = "'; DELETE FROM customers WHERE 1 or username = '"; 
    
    $name_evil = mysql_real_escape_string($name_evil);
    
    $query_evil = "SELECT * FROM customers WHERE username = '$name_evil'";
    echo "Escaped Evil Injection: <br />" . $query_evil;
     

    Вы можете найти более подробную информацию в MySQL - SQL Injection Prevention .

    ответ дан rahularyansharma, с репутацией 8531, 17.06.2011
  • 0 рейтинг

    Как вы можете видеть, люди предлагают вам максимально использовать подготовленные заявления. Это не так, но когда ваш запрос выполняется всего один раз за процесс, будет небольшое снижение производительности.

    Я столкнулся с этой проблемой, но я думаю, что решил ее очень сложным образом - как хакеры используют, чтобы избежать использования котировок. Я использовал это в сочетании с эмулированными подготовленными заявлениями. Я использую его , чтобы предотвратить все виды возможных атак с внедрением SQL.

    Мой подход:

    • Если вы ожидаете, что ввод будет целым, убедитесь, что он действительно целочисленный. В языке с переменным типом, таком как PHP, это очень важно. Вы можете использовать, например, это очень простое, но мощное решение: sprintf("SELECT 1,2,3 FROM table WHERE 4 = %u", $input);

    • Если вы ожидаете чего-либо еще от целого шестнадцатеричного значения . Если вы отбросите его, вы полностью избежите ввода. В C / C ++ есть функция с именем mysql_hex_string() , в PHP вы можете использовать bin2hex() .

      Не беспокойтесь о том, что экранированная строка будет иметь размер в 2 раза ее первоначальной длины, потому что, даже если вы используете mysql_real_escape_string , PHP должен выделять ту же емкость ((2*input_length)+1) , что и то же самое.

    • Этот шестнадцатеричный метод часто используется при передаче двоичных данных, но я не вижу причин, почему бы не использовать его во всех данных для предотвращения атак SQL-инъекций. Обратите внимание, что вам нужно заранее добавить данные с помощью 0x или вместо этого использовать функцию MySQL UNHEX .

    Так, например, запрос:

     SELECT password FROM users WHERE name = 'root'
     

    Станет:

     SELECT password FROM users WHERE name = 0x726f6f74
     

    или

     SELECT password FROM users WHERE name = UNHEX('726f6f74')
     

    Hex - идеальный побег. Никоим образом не вводить.

    Разница между функцией UNHEX и префиксом 0x

    В комментариях было некоторое обсуждение, поэтому я, наконец, хочу дать понять. Эти два подхода очень похожи, но в некоторых отношениях они немного отличаются:

    Префикс ** 0x ** может использоваться только для столбцов данных, таких как char, varchar, text, block, binary и т . Д.
    Кроме того, его использование немного сложно, если вы собираетесь вставить пустую строку. Вам придется полностью заменить его на mysql_hex_string() , или вы получите сообщение об ошибке.

    UNHEX () работает в любой колонке; вам не нужно беспокоиться о пустой строке.


    Hex-методы часто используются в качестве атак

    Обратите внимание, что этот шестнадцатеричный метод часто используется в качестве атаки SQL-инъекции, где целые числа являются точно такими же, как строки, и избегают только с mysql_hex_string() . Тогда вы можете избежать использования котировок.

    Например, если вы просто делаете что-то вроде этого:

     mysql_hex_string() 

    атака может ввести вас очень легко . Рассмотрим следующий введенный код, возвращенный из вашего скрипта:

    SELECT ... WHERE id = -1 union all select table_name from information_schema.tables

    и теперь просто извлеките структуру таблицы:

    SELECT ... WHERE id = -1 union all select column_name from information_schema.column, где table_name = 0x61727469636c65

    А затем просто выберите нужные данные. Разве это не круто?

    Но если кодер инъекционного сайта будет его шестнадцатеричным, инъекции не будет возможным, потому что запрос будет выглядеть так: mysql_hex_string()

    ответ дан Zaffy, с репутацией 11638, 3.10.2012
  • 0 рейтинг

    ** Предупреждение: подход, описанный в этом ответе, применим только к очень конкретным сценариям и не является безопасным, поскольку атаки SQL-инъекций не только полагаются на возможность вставить X=Y **

    Если злоумышленники пытаются взломать форму через переменную PHP $_GET или строку запроса URL, вы сможете поймать их, если они не защищены.

     RewriteCond %{QUERY_STRING} ([0-9]+)=([0-9]+)
    RewriteRule ^(.*) ^/track.php
     

    Потому что 1=1 , 2=2 , 1=2 , 2=1 , 1+1=2 и т. Д. Являются распространенными вопросами к базе данных SQL злоумышленника. Возможно, он также используется многими хакерскими приложениями.

    Но вы должны быть осторожны, чтобы не переписывать безопасный запрос с вашего сайта. В приведенном выше коде вам дается подсказка, переписывать или перенаправлять (это зависит от вас), что строка динамического запроса, зависящая от хакерства, на страницу, которая будет хранить IP-адрес злоумышленника, или EVEN THEIR COOKIES, историю, браузер или любые другие чувствительные информации, поэтому вы можете иметь дело с ними позже, запретив их учетную запись или контактные органы.

    ответ дан 5ervant, с репутацией 2252, 4.04.2013
  • 0 рейтинг

    Я использую три разных способа предотвращения уязвимости моего веб-приложения для SQL-инъекции.

    1. Использование mysql_real_escape_string() , которое является предопределенной функцией в PHP , и этот код добавляет обратную косую черту к следующим символам: \x00 , \n , \r , \ , ' , " и \x1a . Передайте входные значения в качестве параметров, чтобы свести к минимуму вероятность внедрения SQL.
    2. Самый продвинутый способ - использование PDO.

    Я надеюсь, что это поможет вам.

    Рассмотрим следующий запрос:

    $iId = mysql_real_escape_string("1 OR 1=1"); $sSql = "SELECT * FROM table WHERE id = $iId";

    mysql_real_escape_string () не будет защищать здесь. Если вы используете одиночные кавычки ('') вокруг ваших переменных внутри вашего запроса, это то, что защищает вас от этого. Ниже приведено ниже решение:

    $iId = (int) mysql_real_escape_string("1 OR 1=1"); $sSql = "SELECT * FROM table WHERE id = $iId";

    На этот вопрос есть хорошие ответы.

    Я предлагаю, что использование PDO - лучший вариант.

    Редактировать:

    \x00 устарел с PHP 5.5.0. Используйте либо mysqli, либо PDO.

    Альтернативой mysql_real_escape_string () является

     \x00 

    Пример:

     \x00 
    ответ дан Soumalya Banerjee, с репутацией 1848, 14.09.2012
  • 0 рейтинг

    На мой взгляд, лучший способ вообще запретить SQL-инъекцию в вашем приложении PHP (или любом веб-приложении, если на то пошло) - это думать о архитектуре вашего приложения. Если единственный способ защитить от SQL-инъекции - не забудьте использовать специальный метод или функцию, которая делает The Right Thing каждый раз, когда вы разговариваете с базой данных, вы делаете это неправильно. Таким образом, это всего лишь вопрос времени, пока вы не забудете правильно форматировать свой запрос в какой-то момент вашего кода.

    Принятие шаблона MVC и структуры, такой как CakePHP или CodeIgniter , вероятно, является правильным способом: общие задачи, такие как создание безопасных запросов к базе данных, были решены и централизованно реализованы в таких рамках. Они помогают организовать ваше веб-приложение разумным образом и заставляют вас больше думать о загрузке и сохранении объектов, а не о безопасном построении отдельных SQL-запросов.

    ответ дан Johannes Fahrenkrug, с репутацией 30267, 3.07.2012
  • 0 рейтинг

    Существует множество способов предотвращения SQL-инъекций и других SQL-хаков. Вы можете легко найти его в Интернете (Google Search). Конечно, PDO - одно из хороших решений. Но я хотел бы предложить вам некоторые хорошие ссылки с помощью SQL Injection.

    Что такое SQL-инъекция и как предотвратить

    Руководство по PHP для SQL-инъекций

    Microsoft объясняет SQL-инъекцию и предотвращение в PHP

    и некоторые другие, такие как предотвращение SQL-инъекций с MySQL и PHP

    Теперь, почему вам нужно предотвратить запрос из SQL-инъекции?

    Я хотел бы сообщить вам: почему мы пытаемся предотвратить SQL-инъекцию с помощью небольшого примера ниже:

    Запрос для аутентификации входа:

     $query="select * from users where email='".$_POST['email']."' and password='".$_POST['password']."' ";
     

    Теперь, если кто-то (хакер) ставит

     $_POST['email']= admin@emali.com' OR '1=1
     

    и пароль ничего ....

    Запрос будет анализироваться в системе только до:

     $query="select * from users where email='admin@emali.com' OR '1=1';
     

    Другая часть будет отброшена. Итак, что будет? Неавторизованный пользователь (хакер) сможет войти в систему как администратор без своего пароля. Теперь он может делать все, что может сделать администратор / адрес электронной почты. Смотрите, это очень опасно, если SQL-инъекция не предотвращается.

    ответ дан Manish Shrivastava, с репутацией 17323, 23.07.2012
  • 0 рейтинг

    Для тех, кто не знает, как использовать PDO (исходя из функций mysql_ ), я сделал очень и очень простой PDO-обертку, которая представляет собой один файл. Он существует, чтобы показать, насколько легко выполнять все обычные приложения, которые необходимо выполнить. Работает с PostgreSQL, MySQL и SQLite.

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

    Мне нужен один столбец

     $count = DB::column('SELECT COUNT(*) FROM `user`);
     

    Я хочу получить результаты массива (key => value) (т. Е. Для создания selectbox)

     $pairs = DB::pairs('SELECT `id`, `username` FROM `user`);
     

    Мне нужен результат с одной строкой

     $user = DB::row('SELECT * FROM `user` WHERE `id` = ?', array($user_id));
     

    Я хочу массив результатов

     $banned_users = DB::fetch('SELECT * FROM `user` WHERE `banned` = ?', array(TRUE));
     
    ответ дан Xeoncross, с репутацией 26506, 19.09.2012
  • 0 рейтинг

    Я пользуюсь хранимыми процедурамиMySQL была поддержка хранимых процедур с 5.0 ) с точки зрения безопасности - преимущества -

    1. Большинство баз данных (включая MySQL ) позволяют ограничить доступ пользователей к выполнению хранимых процедур. Четкое управление доступом к безопасности полезно для предотвращения эскалации атак привилегий. Это предотвращает возможность взлома приложений, которые могут быть запущены непосредственно с базой данных.
    2. Они абстрагируют исходный SQL-запрос из приложения, поэтому для приложения доступно меньше информации о структуре базы данных. Это затрудняет понимание людьми базовой структуры базы данных и разработку подходящих атак.
    3. Они принимают только параметры, поэтому существуют преимущества параметризованных запросов. Конечно, IMO вам все равно нужно дезинфицировать ваш вход, особенно если вы используете динамический SQL внутри хранимой процедуры.

    Недостатки -

    1. Они (хранимые процедуры) трудно поддерживать и имеют тенденцию к быстрому размножению. Это делает их проблемой.
    2. Они не очень подходят для динамических запросов - если они созданы для принятия динамического кода в качестве параметров, тогда многие преимущества сбрасываются.
    ответ дан Nikhil, с репутацией 3357, 3.11.2009