Создание подключения к MySQL, хорошо иметь проверку каждый раз? [Дубликат]

Не могу поверить, что никто еще не упомянул Барбару Лисков. Когда она разработала CLU в 1974 году, она столкнулась с этой же проблемой терминологии, и она придумала термин , разделив (также известный как вызов путем совместного использования объектов и вызов по объекту ) для этого конкретного случая «вызов по значению, где значение является ссылкой».

2781
задан 44 revs, 36 users 14% 1 October 2016 в 08:08
поделиться

28 ответов

Используйте подготовленные операторы и параметризованные запросы. Это операторы 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 real подготовленные операторы не используются по умолчанию. Чтобы исправить это, вы должны отключить эмуляцию подготовленных операторов. Пример создания соединения с использованием 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 n как PDOException s.

Однако обязательной является первая setAttribute() строка, которая сообщает PDO об отключении эмулируемых подготовленных операторов и использует подготовленные операторы real . Это гарантирует, что оператор и значения не будут разбираться с PHP перед отправкой на сервер MySQL (предоставление возможности злоумышленнику возможности внедрить вредоносный SQL).

Хотя вы можете установить charset в варианты конструктора, важно отметить, что «более старые» версии PHP (& lt; 5.3.6) молча игнорировали параметр charset в DSN.

Объяснение

Случается, что оператор SQL, который вы передаете prepare, анализируется и компилируется сервером базы данных. Указав параметры (либо ?, либо именованный параметр, такой как :name в примере выше), вы указываете механизм базы данных, в который вы хотите включить фильтр. Затем, когда вы вызываете execute, подготовленный оператор объединяется со значениями параметров, которые вы указываете.

Важно то, что значения параметров объединены с компилируемым оператором, а не с строкой SQL. SQL-инъекция работает, обманывая сценарий, включая вредоносные строки, когда он создает SQL для отправки в базу данных. Поэтому, отправляя фактический SQL отдельно от параметров, вы ограничиваете риск того, что закончите то, чего не намеревались. Любые параметры, которые вы отправляете при использовании подготовленного оператора, будут обрабатываться только как строки (хотя механизм базы данных может сделать некоторую оптимизацию, поэтому, конечно, параметры могут также оказаться как числа). В приведенном выше примере, если переменная $name содержит 'Sarah'; DELETE FROM employees, результатом будет просто поиск строки "'Sarah'; DELETE FROM employees", и вы не получите пустую таблицу .

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

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

$preparedStatement = $db->prepare('INSERT INTO table (column) VALUES (:column)');

$preparedStatement->execute(array('column' => $unsafeValue));

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

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

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

// Value whitelist
// $dir can only be 'DESC' otherwise it will be 'ASC'
if (empty($dir) || $dir !== 'DESC') {
   $dir = 'ASC';
}
7971
ответ дан 39 revs, 23 users 21% 15 August 2018 в 16:18
поделиться
  • 1
    Просто добавьте, потому что я не видел его где-то еще здесь, другая линия защиты - это брандмауэр веб-приложений (WAF), который может иметь правила для поиска атак на sql-инъекции: – jkerak 29 December 2015 в 21:11
  • 2
    Кроме того, официальная документация mysql_query позволяет только выполнить один запрос, поэтому любой другой запрос; игнорируется. Даже если это уже устарело, существует множество систем под PHP 5.5.0 и может использовать эту функцию. php.net/manual/en/function.mysql-query.php – Randall Valenciano 19 January 2016 в 18:40
  • 3
    Это плохая привычка, но решение для пост-проблем: не только для инъекций SQL, но и для любых типов инъекций (например, в F3 framework v2 было отверстие для инъекций шаблона просмотра), если у вас есть готовый старый веб-сайт или приложение от дефектов впрыска, одно решение состоит в том, чтобы переназначить значения ваших supperglobal предопределенных варов, таких как $ _POST, с экранированными значениями при загрузке. В PDO все еще можно избежать (также для сегодняшних фреймворков): substr ($ pdo- & gt; quote ($ str, \ PDO :: PARAM_STR), 1, -1) – Alix 24 January 2016 в 16:08
  • 4
    В этом ответе отсутствует объяснение того, что является подготовленным заявлением - одно - это удар производительности, если вы используете много подготовленных операторов во время вашего запроса, и иногда он учитывает поражение в 10 раз. Лучшим случаем будет использование PDO с отключением параметра, но подготовка инструкции отключена. – donis 18 November 2016 в 09:54
  • 5
    Использование PDO лучше, если вы используете прямой запрос, убедитесь, что вы используете mysqli :: escape_string – Kassem Itani 6 November 2017 в 09:17
157
ответ дан 14 revs, 6 users 67%user1646111 15 August 2018 в 16:18
поделиться

Внимание: примерный код этого ответа (например, примерный код вопроса) использует расширение 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 в комментариях ниже. Этот случай более сложный, поскольку целые числа не будут окружены кавычками, поэтому вы можете справиться, подтвердив, что пользовательский ввод содержит только цифры.
  • Есть, вероятно, другие случаи, о которых я не знаю. Вы можете найти , этот является полезным ресурсом для некоторых более тонких проблем, с которыми вы можете столкнуться.
1516
ответ дан 17 revs, 11 users 73% 15 August 2018 в 16:18
поделиться
  • 1
    с помощью mysql_real_escape_string достаточно, или я тоже должен использовать параметризацию? – peiman F. 8 March 2018 в 22:29
  • 2
    @peimanF. сохраняйте хорошую практику использования параметризованных запросов, даже в локальном проекте. С параметризованными запросами вы гарантировали , что SQL-инъекция не будет. Но имейте в виду, что вы должны дезинформировать данные, чтобы избежать фиктивного поиска (например, внедрение XSS, например, размещение HTML-кода в тексте) с помощью htmlentities, например – Goufalite 9 March 2018 в 09:02
  • 3
    @peimanF. Хорошая практика для параметризованных запросов и привязки значений, но настоящая строка escape хороша на данный момент – Richard 4 April 2018 в 18:03

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

348
ответ дан 2 revs, 2 users 67% 15 August 2018 в 16:18
поделиться
  • 1
    В самом деле; запуск с включенными magic_quotes только поощряет плохую практику. Однако иногда вы не можете всегда контролировать среду на этом уровне - либо у вас нет доступа к управлению сервером, либо ваше приложение должно сосуществовать с приложениями, которые (дрожь) зависят от такой конфигурации. По этим причинам хорошо писать переносные приложения - хотя очевидно, что усилия теряются, если вы контролируете среду развертывания, например. потому что это внутреннее приложение или только будет использоваться в вашей конкретной среде. – Rob 24 April 2011 в 18:04
  • 2
    Начиная с PHP 5.4, мерзость, известная как «магические кавычки», была убита мертвой . И хорошее избавление от дурного мусора. – BryanH 17 January 2013 в 00:45

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

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

Недостатки -

  1. Они (хранимые процедуры) трудно поддерживать и стремиться к размножению очень быстро. Это делает их проблемой.
  2. Они не очень подходят для динамических запросов - если они созданы для принятия динамического кода в качестве параметров, тогда многие преимущества сбрасываются.
265
ответ дан 3 revs, 3 users 76% 15 August 2018 в 16:18
поделиться

Использование 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.

226
ответ дан 3 revs, 3 users 86% 15 August 2018 в 16:18
поделиться
  • 1
    Кроме того, нет абсолютно никакого смысла в проверке элементов массива $ _POST с помощью is_string () – Your Common Sense 18 January 2014 в 09:06
  • 2
    ПРЕДУПРЕЖДЕНИЕ! mysql_real_escape_string() не является непогрешимым . – eggyal 25 April 2014 в 15:54
  • 3
    mysql_real_escape_string теперь устарел, поэтому он больше не является жизнеспособным вариантом. Он будет удален из PHP в будущем. Лучше всего переходить на то, что рекомендуют PHP или MySQL. – jww 8 April 2015 в 06:53
  • 4
    Это один из немногих случаев, когда я использовал бы «экранированное значение», вместо подготовленного заявления. И преобразование целочисленного типа чрезвычайно эффективно. – HoldOffHunger 13 March 2016 в 23:29
  • 5
    Тема: Не доверяйте представленным данным пользователя. Все, что вы ожидаете, это данные мусора со специальными символами или логической логикой, которые сами должны стать частью SQL-запроса, который вы можете выполнять. Храните значения $ _POST только как данные, а не часть SQL. – Bimal Poudel 2 December 2017 в 08:39

Для тех, кто не знает, как использовать 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));
205
ответ дан 3 revs, 3 users 90% 15 August 2018 в 16:18
поделиться

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

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 не вызывает проблем, если замена содержит эти токены.

78
ответ дан 4 revs, 2 users 99% 15 August 2018 в 16:18
поделиться

Параметрированный запрос И проверка ввода - это путь. Существует множество сценариев, в которых может произойти 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 (при эвакуации Недостаточно)

331
ответ дан 4 revs, 3 users 86% 15 August 2018 в 16:18
поделиться
  • 1
    Вы можете предотвратить внедрение SQL, если вы примете метод проверки ввода, в котором пользовательский ввод аутентифицирован против набора определенных правил для длины, типа и синтаксиса, а также против бизнес-правил. – Josip Ivic 15 September 2015 в 08:07

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

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

MySQLi

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

Пример:

$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
188
ответ дан 4 revs, 3 users 88% 15 August 2018 в 16:18
поделиться
  • 1
    Вопрос очень общий. Несколько отличных ответов выше, но большинство из них предлагает подготовленные заявления. MySQLi async не поддерживает подготовленные операторы, поэтому sprintf выглядит как отличный вариант для этой ситуации. – Dustin Graham 23 April 2016 в 22:33

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

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

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

771
ответ дан 4 revs, 4 users 43% 15 August 2018 в 16:18
поделиться
  • 1
    не PDO обертывает mysqli для MySQL DB? В этом случае, конечно, это не может быть быстрее, чем mysqli. Я бы порекомендовал его. Это намного лучший интерфейс, который поддерживает API mysqli. – Peter Bagnall 26 May 2016 в 13:32
  • 2
    Использование параметризованных запросов - это ускорение запросов. Технически mysqli может быть еще быстрее с очень небольшим отрывом. Фактическое количество времени, которое сервер принимает для ответа на запрос, затмевает любую разницу в сроках, которые могут произойти, потому что вы используете обертку. Но mysqli привязан к базе данных. Если вы хотите использовать другой механизм базы данных, вам нужно изменить все вызовы, которые используют mysqli. Не так для PDO. – Kibbee 26 May 2016 в 13:35
  • 3
    PDO не поддерживает динамический order by, к сожалению :( – Horse 18 January 2018 в 17:35

Есть так много ответов для 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);
123
ответ дан 4 revs, 4 users 56% 15 August 2018 в 16:18
поделиться

Используя эту функцию 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
205
ответ дан 4 revs, 4 users 80% 15 August 2018 в 16:18
поделиться

Хорошей идеей является использование «объектно-реляционного картографа», подобного 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-инъекций, но и от синтаксических ошибок! Также поддерживает коллекции моделей с цепочкой методов для фильтрации или применения действий к нескольким результатам сразу и нескольких подключений.

117
ответ дан 4 revs, 4 users 90% 15 August 2018 в 16:18
поделиться

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

158
ответ дан 5 revs, 4 users 29% 15 August 2018 в 16:18
поделиться
  • 1
    Я думаю, что весь вопрос заключается в том, чтобы сделать это без использования такой структуры. – Sanke 2 January 2018 в 17:16

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

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

213
ответ дан 5 revs, 4 users 35% 15 August 2018 в 16:18
поделиться

Существует множество способов предотвращения 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-инъекция не предотвращается.

262
ответ дан 5 revs, 4 users 68% 15 August 2018 в 16:18
поделиться

** Предупреждение: подход, описанный в этом ответе, применим только к очень конкретным сценариям и не является безопасным, поскольку атаки 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, история , браузера или любой другой конфиденциальной информации, поэтому вы можете иметь дело с ними позже, запретив их учетную запись или контактные органы.

132
ответ дан 6 revs, 4 users 58% 15 August 2018 в 16:18
поделиться

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

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

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

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

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

$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) many (4) отвечает (5) , в том числе второй наиболее ответный ответ , предлагающий вам ручное стирание строки - устаревший подход, который оказался небезопасным.

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

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

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

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

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

Если вы все еще не уверены, вот пошаговое объяснение, которое я написал, The Hitchhiker's Guide на SQL Injection Prevention , где я подробно объяснил все эти вопросы и даже составил раздел, полностью посвященный плохим практикам и их раскрытию.

948
ответ дан 7 revs, 3 users 87% 15 August 2018 в 16:18
поделиться
  • 1
    Отличная, продуманная статья. Я мог бы добавить, что использование фильтров Sanitize PHP - это (но не совсем) белый список. Например, FILTER_SANITIZE_NUMBER_INT разрешает только числовые символы, тем самым белые листинговые символы, а не целые строки. В сочетании с подготовленными заявлениями он делает хороший «пояс и подтяжки», подход. – Sablefoste 20 January 2016 в 18:12
  • 2
    @Sablefoste вам не нужен белый список здесь. Любая дезинфекция будет излишней. Чем меньше правил следовать, тем меньше ошибок вы сделаете. Хотя вы можете делать какие-либо проверки, делайте это ради логики приложения, но не для базы данных. – Your Common Sense 20 January 2016 в 18:54

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

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

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

FLUSH PRIVILEGES; 

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

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

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

Подробнее о GRANT .

169
ответ дан 7 revs, 7 users 51% 15 August 2018 в 16:18
поделиться
  • 1
    Этот ответ является по существу неправильным , поскольку он не помогает предотвратить профилактику инъекций, а просто пытается смягчить последствия. Напрасно. – Your Common Sense 20 May 2016 в 11:00
  • 2
    Правильно, это не дает решения, но это то, что вы можете сделать перед собой, чтобы избежать вещей. – Apurv Nerlekar 25 May 2016 в 18:25
  • 3
    @Apurv Если моя цель - прочитать личную информацию из вашей базы данных, то отсутствие разрешения DELETE ничего не значит. – Alex Holsgrove 5 October 2016 в 14:03
  • 4
    @AlexHolsgrove: Успокойся, я просто предлагал хорошие практики для смягчения последствий. – Apurv Nerlekar 14 October 2016 в 20:59
  • 5
    @Apurv Вы не хотите «смягчать последствия», вы хотите сделать все возможное для защиты от него. Справедливости ради следует сказать, что правильная настройка доступа пользователей важна, но не совсем то, о чем просит ОП. – Alex Holsgrove 14 October 2016 в 21:08

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

Я столкнулся с этой проблемой, но я думаю, что решил ее в очень сложном пути - как хакеры используют, чтобы избежать использования кавычек. Я использовал это в сочетании с эмулированными подготовленными заявлениями. Я использую его, чтобы предотвратить все возможные типы инъекций 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), что то же самое.
  • hex метод часто используется при передаче двоичных данных, но я не вижу причин, почему бы не использовать его во всех данных для предотвращения атак 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, и т. д. Кроме того, его использование немного сложно, если вы собираетесь вставить пустую строку. Вам придется полностью заменить его на '', или вы получите сообщение об ошибке.

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


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

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

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

"SELECT title FROM article WHERE id = " . mysql_real_escape_string($_GET["id"])

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

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

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

Но если кодер инъекционного сайта будет шестнадцатеричным, инъекция не будет возможна, потому что запрос будет выглядеть следующим образом: SELECT ... WHERE id = UNHEX('2d312075...3635')

502
ответ дан 8 revs, 6 users 79% 15 August 2018 в 16:18
поделиться
  • 1
    @SumitGupta Да, ты сделал. MySQL не объединяется с +, а с CONCAT. И к производительности: я не думаю, что это влияет на производительность, потому что mysql должен анализировать данные, и не имеет значения, является ли происхождение строкой или шестнадцатеричным – Zaffy 2 June 2013 в 00:49
  • 2
    @YourCommonSense Какие ошибки вы встречаете? Быть конкретной. – Zaffy 1 July 2013 в 14:52
  • 3
    @YourCommonSense Вы не понимаете концепцию ... Если вы хотите иметь строку в mysql, вы приводите ее так, как это 'root', или вы можете ее использовать 0x726f6f74, но если вы хотите номер и отправить его как строку, вы, вероятно, 42 'не CHAR (42) ...' 42 'в hex будет 0x3432 не 0x42 – Zaffy 1 July 2013 в 15:07
  • 4
    @YourCommonSense Мне нечего сказать ... просто lol ... если вы все еще хотите попробовать hex в числовых полях, см. Второй комментарий. Держу пари с тобой, что это сработает. – Zaffy 1 July 2013 в 15:24
  • 5
    @YourCommonSense вы все еще не понимаете? Вы не можете использовать 0x и concat, потому что если строка пустая, вы закончите с ошибкой. Если вам нужна простая альтернатива вашему запросу, попробуйте этот SELECT title FROM article WHERE id = UNHEX(' . bin2hex($_GET["id"]) . ') – Zaffy 1 August 2013 в 13:33

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

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

$stmt = $conn->prepare("INSERT INTO tbl VALUES(:id, :name)");
$stmt->bindValue(':id', $id);
$stmt->bindValue(':name', $name);
$stmt->execute();
568
ответ дан Imran 15 August 2018 в 16:18
поделиться
  • 1
    Из wikipedia : Подготовленные утверждения устойчивы к SQL-инъекции, потому что значения параметров, которые передаются позже с использованием другого протокола, не обязательно должны быть экранированы. Если исходный шаблон инструкции не получен из внешнего ввода, SQL-инъекция не может произойти. – Imran 9 July 2016 в 20:08

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

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

282
ответ дан Johannes Fahrenkrug 15 August 2018 в 16:18
поделиться
  • 1
    Я думаю, что ваш первый параграф важен. Понимание является ключевым. Кроме того, все не работают в компании. Для большого круга людей рамки действительно противоречат идее понимания . Знакомство с основами не может быть оценено во время работы в установленные сроки, но сами по себе люди получают грязные руки. Разработчики рамок не настолько привилегированы, что все остальные должны поклониться и предположить, что они никогда не ошибаются. Власть принимать решения по-прежнему важна. Кто скажет, что мои рамки не вытеснят какую-либо другую схему в будущем? – Anthony Rutledge 4 January 2017 в 17:32
  • 2
    @AnthonyRutledge Вы абсолютно правы. Очень важно понимать , что происходит и почему. Тем не менее, вероятность того, что испробованная и активно используемая и развитая инфраструктура столкнулась с множеством проблем и решила много проблем, уже достаточно высока. Это хорошая идея, чтобы посмотреть на источник, чтобы почувствовать качество кода. Если это непроверенный беспорядок, это, вероятно, небезопасно. – Johannes Fahrenkrug 4 January 2017 в 19:38
  • 3
    Вот. Вот. Хорошие моменты. Однако согласитесь ли вы, что многие люди могут учиться и учиться принимать систему MVC, но не каждый может воспроизвести ее вручную (контроллеры и сервер). С этим можно зайти слишком далеко. Должен ли я понять мою микроволновую печь, прежде чем нагреть мое печенье из арахисового масла, которое сделала моя подруга? ;-) – Anthony Rutledge 4 January 2017 в 20:30
  • 4
    @AnthonyRutledge Я согласен! Я думаю, что прецедент тоже имеет значение: создаю ли фотогалерею для своей личной домашней страницы или создаю веб-приложение для онлайн-банкинга? В последнем случае очень важно понять детали безопасности и то, как я использую фреймворк. – Johannes Fahrenkrug 4 January 2017 в 21:35
  • 5
    Ах, исключение безопасности, чтобы сделать это самостоятельно. Понимаете, я склонен рисковать всем и идти за слом. :-) Шутка. С достаточным временем люди могут научиться делать довольно надежное защищенное приложение. Слишком много людей в спешке. Они поднимают руки и предполагают, что фреймворки безопаснее . В конце концов, у них не хватает времени, чтобы проверить и разобраться. Кроме того, безопасность - это поле, которое требует специального изучения. Это не то, что просто программисты знают глубоко в силу понимания алгоритмов и шаблонов проектирования. – Anthony Rutledge 4 January 2017 в 21:48

ВАЖНО

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

Существуют библиотеки, такие как Aura.Sql и EasyDB , которые позволяют разработчикам легче использовать подготовленные инструкции. Чтобы узнать больше о том, почему подготовленные операторы лучше в останавливать SQL-инъекцию , см. этот mysql_real_escape_string() обход и недавно зафиксированные уязвимости Unicode SQL Injection в 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 .

456
ответ дан rahularyansharma 15 August 2018 в 16:18
поделиться
  • 1
    Это лучшее, что вы можете сделать с устаревшим расширением mysql. Для нового кода рекомендуется переключиться на mysqli или PDO. – Álvaro González 26 February 2013 в 14:42
  • 2
    Я не согласен с этой «специально созданной функцией для предотвращения этих атак». Я думаю, что цель mysql_real_escape_string заключается в создании правильного SQL-запроса для каждой входной строки данных. Предотвращение sql-инъекции является побочным эффектом этой функции. – sectus 9 July 2013 в 06:01
  • 3
    вы не используете функции для записи правильных строк входных данных. Вы просто пишете правильные, которые не нуждаются в экранировании или уже сбежали. mysql_real_escape_string () может быть спроектирован с целью, о которой вы говорите, но его единственное значение - предотвращение инъекций. – Nazca 13 March 2014 в 00:38
  • 4
    ПРЕДУПРЕЖДЕНИЕ! mysql_real_escape_string() не является непогрешимым . – eggyal 25 April 2014 в 15:50
  • 5
    mysql_real_escape_string теперь устарел, поэтому он больше не является жизнеспособным вариантом. Он будет удален в будущем из PHP. Лучше всего переходить на то, что рекомендуют PHP или MySQL. – jww 8 April 2015 в 06:41

Я думаю, что если кто-то захочет использовать 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% для подготовленных.

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

241
ответ дан RDK 15 August 2018 в 16:18
поделиться

Я использую три разных способа предотвращения уязвимости моего веб-приложения для 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.

Изменить:

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

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

string mysqli_real_escape_string ( mysqli $link , string $escapestr )

Пример:

$iId = $mysqli->real_escape_string("1 OR 1=1");
$mysqli->query("SELECT * FROM table WHERE id = $iId");
163
ответ дан Soumalya Banerjee 15 August 2018 в 16:18
поделиться

Security Warning: этот ответ не соответствует лучшим рекомендациям по безопасности. Эвакуация неадекватна для предотвращения 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 . "')");

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

413
ответ дан Tanerax 15 August 2018 в 16:18
поделиться
  • 1
    Я попробовал ваш пример, и это отлично работает для меня. Не могли бы вы это понять? Это не решит каждую проблему & quot; – Chinook 22 April 2012 в 21:31
  • 2
    Если вы не процитируете эту строку, она все же может быть использована для инъекций. Возьмите $q = "SELECT col FROM tbl WHERE x = $safe_var";, например. Установка $safe_var на 1 UNION SELECT password FROM users работает в этом случае из-за отсутствия кавычек. Также возможно вставить строки в запрос с помощью CONCAT и CHR. – Polynomial 16 April 2013 в 19:06
  • 3
    @Polynomial Полностью правы, но я видел бы это просто как неправильное использование. Пока вы используете его правильно, это определенно будет работать. – glglgl 10 July 2013 в 08:30
  • 4
    ПРЕДУПРЕЖДЕНИЕ! mysql_real_escape_string() не является непогрешимым . – eggyal 25 April 2014 в 15:46
  • 5
    mysql_real_escape_string теперь устарел, поэтому он больше не является жизнеспособным вариантом. Он будет удален в будущем из PHP. Лучше всего переходить на то, что рекомендуют PHP или MySQL. – jww 8 April 2015 в 06:37
230
ответ дан 3 revs, 3 users 86% 5 September 2018 в 15:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: