SQL-инъекция - как дезинфицировать программу SQL-предложения? - PullRequest
6 голосов
/ 03 сентября 2011

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

Наконец, рассмотрим предложение where

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

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

Основные факты:

  • не практично для написания парсера SQL-предложения для параметризованных подготовленных операторов
  • не практично для написанияОбеззараживающее средство SQL, гарантирующее отсутствие вреда

Решение:

для SELECTS, где случайный 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 ]

5 голосов
/ 04 сентября 2011

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

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

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

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

2 голосов
/ 04 сентября 2011

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

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

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

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

1 голос
/ 03 сентября 2011

Как предложил @Stephen, укажите WHERE как объект, затем проанализируйте объект и сгенерируйте безопасный SQL вар где = { emp_tp: { условие: равно значение: 'abc' } var order = { 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));
  }
}
1 голос
/ 03 сентября 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...