Выход из командной строки 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);')