Выход из командной строки MYSQL с помощью Bash Scripting
У PHP есть mysql_real_escape_string()
, чтобы правильно избежать любых символов, которые могут вызвать проблемы. Каков наилучший способ имитировать эту функциональность для BASH?
Есть ли способ сделать подготовленные операторы mysql с помощью BASH? Кажется, это лучший способ.
Большинство моих переменных не будут (не должны) иметь специальные символы, однако я предоставляю пользователю полную свободу для их пароля. Он может содержать символы типа "и".
Я могу делать несколько операторов SQL, поэтому я хочу сделать script, который принимает параметры, а затем запускает оператор. Это то, что у меня есть до сих пор:
doSQL.sh:
#!/bin/sh
SQLUSER="root"
SQLPASS="passwor339c"
SQLHOST="localhost"
SQL="$1"
SQLDB="$2"
if [ -z "$SQL" ]; then echo "ERROR: SQL not defined"; exit 1; fi
if [ -z "$SQLDB" ]; then SQLDB="records"; fi
echo "$SQL" | mysql -u$SQLUSER -p$SQLPASS -h$SQLHOST $SQLDB
и пример с использованием указанной команды:
example.sh:
PASSWORD=$1
doSQL "INSERT INTO active_records (password) VALUES ('$PASSWORD')"
Очевидно, что это не сработает, если пароль пароля содержит в себе одну цитату.
Ответы
Ответ 1
В Bash, printf
может выполнить экранирование для вас:
$ a=''\''"\;:#[]{}()|&^[email protected]!?, .<>abc123'
$ printf -v var "%q" "$a"
$ echo "$var"
\'\"\\\;:#\[\]\{\}\(\)\|\&\^\[email protected]\!\?\,\ .\<\>abc123
Я оставлю это вам, чтобы решить, достаточно ли это достаточно агрессивно.
Ответ 2
Это похоже на классический случай использования неправильного инструмента для задания.
У вас впереди много работы, чтобы реализовать ускорение, выполненное mysql_real_escape_string()
в bash. Обратите внимание, что mysql_real_escape_string()
фактически делегирует экранирование в библиотеку MySQL, которая учитывает набор символов соединения и базы данных. Он назывался "реальным", потому что его предшественник mysql_escape_string()
не учитывал набор символов и мог быть обманут в инъекции SQL.
Я бы предложил использовать язык сценариев с библиотекой MySQL, такой как Ruby, Python или PHP.
Если вы настаиваете на bash, используйте синтаксис MySQL Prepared Statement.
Ответ 3
mysql_real_escape_string()
, конечно, избегает только строкового литерала для цитирования, а не целого оператора. Вам нужно четко указать, для какой цели будет использоваться строка в инструкции. Согласно разделу руководства MySQL по строковым литералам, для вставки в поле строки вам нужно только избежать одиночных и двойных кавычек, обратных косых черт и NUL. Однако строка bash не может содержать NUL, поэтому должно быть достаточно следующего:
#escape for MySQL single string
PASSWORD=${PASSWORD//\\/\\\\}
PASSWORD=${PASSWORD//\'/\\\'}
PASSWORD=${PASSWORD//\"/\\\"}
Если вы будете использовать строку после LIKE
, вы также, вероятно, захотите выйти %
и _
.
Подготовленные утверждения - еще одна возможность. И убедитесь, что вы не используете echo -e
в своем bash.
См. также https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet
Ответ 4
Это позволит избежать апострофов
a=$(echo "$1" | sed s/"'"/"\\\'"/g)
Обратите внимание на то, что mysql_real_escape_string также ускользает от \x00,\n,\r, \, "и\x1a. Обязательно избегайте их для полной безопасности.
Чтобы выйти из \x00, например:
a=$(echo "$1" | sed s/"\x00"/"\\\'"/g)
С небольшим усилием вы, возможно, избежите их с помощью одной команды sed.
Ответ 5
Конечно, почему бы просто не использовать реальную вещь?
A script, anywhere, such as
~/scripts/mysqli_real_escape.php
#!/bin/php
<?php
$std_input_data = '';
$mysqli = new mysqli('localhost', 'username', 'pass', 'database_name');
if( ftell(STDIN) !== false ) $std_input_data = stream_get_contents(STDIN);
if( empty($std_input_data) ) exit('No input piped in');
if( mysqli_connect_errno( ) ) exit('Could not connect to database');
fwrite ( STDOUT,
$mysqli->real_escape_string($std_input_data)
);
exit(0);
?>
Next, run from bash terminal:
chmod +x ~/script/mysqli_real_escape.php'
ln -s ~/script/mysqli_real_escape.php /usr/bin/mysqli_real_escape
Все готово! Теперь вы можете использовать mysqli_real_escape
в своих скриптах bash!
#!/bin/bash
MyString="[email protected]#)*special characters"
MyString="$(printf "$MyString" | mysqli_real_escape )"
Примечание. Из того, что я понимаю, подстановка команд с использованием "$(cmd ..."$var")"
предпочтительнее, чем использование обратных галочек. Тем не менее, так как в дальнейшем не требуется вложенности, все должно быть в порядке.
Примечание: когда внутри подстановки команд, "$(...)"
, создается новый контекст цитаты. Вот почему кавычки вокруг переменных не портят строку.
Ответ 6
Это будет работать:
echo "John O'hara" | php -R 'echo addslashes($argn);'
Чтобы передать его переменной:
name=$(echo "John O'hara" | php -R 'echo addslashes($argn);')