Как предотвратить SQL-инъекцию в интерфейсе командной строки командной строки MySQL?
Я использую shell script для связи с базой данных MySQL. MySQL поддерживает указание запроса как аргумент оболочки, например:
mysql my_db -B -N -e "select id from Table"
Однако, если у меня есть параметр, который я хотел бы использовать в запросе, как я могу получить защиту от инъекций?
Наивный способ - просто вставить значение переменной в запрос, но это не очень безопасно:
mysql my_db -B -N -e "select id from Table where name='$PARAM'"
Есть ли какие-либо трюки или документированные интерфейсы для создания безопасных запросов в командной строке?
Ответы
Ответ 1
Вы можете кодировать значение base64, а затем base64 декодировать его в MySQL. В MySQL используются UDF для преобразования данных Base64 в общие данные. Кроме того, большинство систем либо имеют uuencode, либо команду base64 для данных кодировки base64.
Ответ 2
Ваше приложение восприимчиво к атаке SQL Injection при каждом построении SQL путем конкатенации параметров (как в вашем примере). В wikipedia есть запись об этом по ссылке: http://en.wikipedia.org/wiki/SQL_injection
Я подозреваю, что вам захочется написать unix-фильтр для создания вашего SQL-запроса с помощью функции mysql_real_escape_string
, упомянутой в статье.
Рассмотрите возможность передачи SQL как первого параметра и переменной (ов) в качестве последующих параметров, а затем возврата построенного SQL. Если вы назовете ваш фильтр "blobbo", команда, подобная вашему примеру, может выглядеть так:
blobbo "выберите id из таблицы, где name=% s" $PARAM
Ответ 3
Вам не только нужно защищать от SQL-инъекции, но и от инъекции оболочки. Возможно, вы захотите написать запрос (после дезинфекции любых динамических частей) в файл, а затем перенаправить этот файл в mysql, вместо того чтобы надеяться, что запрос не сломает оболочку. Рассмотрим:
PARAM="name'\"; rm -rf / ; echo 'pwn3d U"
становится
mysql my_db -B -N -e "select id from Table where name='name'"; rm -rf / ; echo 'pwn3d U'
или
command 1: mysql my_db -B -N -e "select id from Table where name='name'"
command 2: rm -rf /
command 3: echo 'pwn3d U'
Вместо этого сделайте что-нибудь вроде:
cat <<EOT > query.sql
select .... blah blaah blah .... sanitized query here
EOT
mysql my_db -B -N < query.sql
Это предотвратит появление каких-либо данных, заданных пользователем, в самой команде оболочки, предотвратит хотя бы один уровень уязвимости в отношении инъекций. Но тогда вам все равно придется обрабатывать проблему с SQL-инъекцией.
Ответ 4
Ответ Саргун Дхиллон указал мне в правильном направлении. К сожалению, FROM_BASE64 недоступен до MySQL 5.6, поэтому я пошел с UNHEX.
Ниже приведено script ниже, чтобы запросить детали пользователя Redmine из оболочки. Я все еще не спал бы хорошо, если бы недоверенные пользователи имели доступ к этому script, но в моем случае это достаточно безопасно. (Он также ограничен строковыми значениями, и вы не должны иметь вопросительный знак в своем запросе, но эти ограничения в порядке со мной.)
#!/bin/bash
MYSQL_OPTS='--defaults-file=/etc/redmine/mysql.cnf'
mysql_query() {
local db=$1
local sql=$2
shift 2 || return 1
declare -a args=("[email protected]")
sql=${sql//[%]/%%}
sql=${sql//[?]/UNHEX('%s')}
for ((i=0; i<${#args[@]}; i++)); do
args[$i]=$(echo -n "${args[$i]}" | hexdump -v -e '/1 "%02X"')
done
sql=$(printf "$sql" "${args[@]}")
mysql $MYSQL_OPTS "$db" -e "$sql" || return $?
}
for u in "[email protected]"; do
mysql_query redmine 'select * from users where login=?\G' "$u"
done
Если вы обнаружите какие-либо инъекции SQL или Shell, которые я пропустил, прокомментируйте.