SQL injection - как санировать предложение sql, сгенерированное программой?

в стандартном Ajax,where и order by SQL предложения предоставляются программой (не пользователем), например

var url = ".select?dd=emp&where="+escape("emp_tp='abc' and hire_dt<current_date-'2 years' and super_emp_id is distinct from emp_id")

ответил на сервере

$where = (isset($_GET['where'])) ? pureClause($_GET['where']) : null;
$order = (isset($_GET['order'])) ? pureClause($_GET['order']) : null;
...
$query = $query.(($where)?" where $where":'').(($order)?" order by $order":'');

вопрос в том, что должна функция pureClause выглядеть?

прямо сейчас pureClause просто вызывает ошибку, если любой из следующих причин:

; select insert update delete drop create truncate

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

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

пояснения:

  • подготовленные операторы в Postgres, хотя и очень быстрые, являются болью для настройки и обслуживания - они в порядке для хорошо используемых запросов, но не пользовательских запросов.
  • создание подготовленного оператора для каждой транзакции является огромный db hit. гораздо предпочтительнее, если безопасность может быть достигнута на уровне приложения.

наконец, рассмотрим, где пункт

emp_tp='abc' and hire_dt=current_dt-'2 years' and super_emp_id is distinct from emp_id

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


первичные факты:

  • не практические написания парсера выражение SQL для параметризованных подготовленные заявления
  • не практические написать выражение SQL дезинфектор, что гарантии нет вред

устранение:

для выбора, где случайный SQL может быть проблемой: поскольку слишком сложно защитить базу данных, пусть база данных защищает себя! у разных пользователей разные роли / разрешения. для выбора используйте пользователя только для чтения. для обычного SQL это гарантирует отсутствие DML из этих операторов.

рекомендации: четыре пользователь обращений к БД

  1. developer, все сделаем (никогда использовать в качестве подключения в веб-приложение)
  2. dml - можно выбрать / dml почти на все (необходимо использовать для dml)
  3. read - можно выбрать (использовать для всех выбирает, будь то подготовленный или текст)
  4. login - может выполнять только функции логина/пароля (используется в процессе входа в систему)

защита секретности пароля:

  • dml и read не может получить доступ к данным пароля, либо через select или dml
  • login должны получить доступ к данным пароль только через защищенные функции, например,
     function login( username, password ) - returns user_id
     function set_password( usr_id, password ) - sets password
  • только login на login() и set_password() функции
  • в зависимости от вашей базы данных, login мая нужен доступ sql к столбцам паролей
  • в зависимости от вашей базы данных,password столбец может быть защищен сам; если нет, то должен быть перемещен из user таблицы в собственная безопасная таблица

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

4 ответов


то, что вы делаете, - это само определение SQL-инъекции и не может быть дезинфицировано. Вы не можете пройти в WHERE предложение в безопасном режиме точка конец истории. Эту часть запроса необходимо построить на стороне сервера. Тот факт, что вы не узнали это означает, что вы должны подробнее о SQL-инъекции, явно спрашивая StackOverflow является небезопасным подходом к этой проблеме. Страх в том, что вы никогда не узнаете основы этого уязвимость.

$order можно сделать безопасным способом с белым списком. Например:

if(in_array($_GET['order'],$list_of_rows)){
   $order=$_GET['order'];
}

Если вы передаете имя таблицы или имя столбца, убедитесь, что вы проверяете его против белого списка, или это будет SQL-инъекция.


всегда использовать подготовленные операторы. Он будет обрабатывать экранирование ввода и избегать SQL-инъекции. Там не будет необходимости в хаки, как pureClause. Проверьте mysqli_stmt::prepare()


Как предложил @Stephen, укажите WHERE в качестве объекта, затем проанализируйте объект и создайте безопасный SQL var, где = { emp_tp: { условие: равный значение: 'АВС' } ВАР порядке = { emp_tp: 'ASC' }

отправить его как json:

var params = {
  w: where,
  o: order
}
$.post(url,params,function(result){...}, 'json');

и в PHP

$where = isset($_POST['w']) ? json_decode($_POST['w') : array();
if (!empty($where)) {
  foreach ($where as $field => $data) {
     // validate that field exists
     // validate that operator is valid
     $sql .= sprintf('%s %s "%s"', $field, $data->operator, mysql_escape_string($data->value));
  }
}

понял! Маршрутизация всех этих запросов через пользователя базы данных (соединение), которому были предоставлены только права выбора в базе данных!

попытка DML задохнется. Это не предотвращает DoS-атаки (много способов сделать это!), но защищает данные. Ни для безопасного запросы, как войти. Но для клиента, созданного WHERE и ORDER, с целью предотвращения DML, это должно работать просто отлично.

десять/пятнадцать лет назад всегда настройте разных пользователей для разных ролей, но с app layer и т. д. и т. д. вышли из привычки. Это, вероятно, хорошая идея, чтобы повторно инвестировать в эти принципы.

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