通过 Bash 脚本转义 MYSQL 命令行

问题描述 投票:0回答:10

PHP 有

mysql_real_escape_string()
可以正确转义任何可能导致问题的字符。为 BASH 模拟此功能的最佳方法是什么?

有没有办法使用 bash 做准备好的 mysql 语句?这似乎是最好的方法。

我的大多数变量不会(不应该)有特殊字符,但是我给用户完全自由的密码。它可能包含 ' 和 " 等字符。

我可能会执行多个 SQL 语句,因此我想要制作一个接受参数然后运行该语句的脚本。这是我到目前为止所拥有的:

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

以及使用上述命令的示例:

示例.sh:

PASSWORD=$1
doSQL "INSERT INTO active_records (password) VALUES ('$PASSWORD')"

如果密码中包含单引号,显然这会失败。

mysql bash ssh escaping sh
10个回答
17
投票

在 Bash 中,

printf
可以为你进行转义:

$ a=''\''"\;:#[]{}()|&^$@!?, .<>abc123'
$ printf -v var "%q" "$a"
$ echo "$var"
\'\"\\\;:#\[\]\{\}\(\)\|\&\^\$@\!\?\,\ .\<\>abc123

我会让你来决定这是否足够激进。


6
投票

无论您使用什么引号,都无法逃脱以下构造:

function quoteSQL() {
    printf "FROM_BASE64('%s')" "$(echo -n "$1" | base64 -w0 )"
}

PASSWORD=$1
doSQL "INSERT INTO active_records (password) VALUES ($(quoteSQL "$PASSWORD"));"

# I would prefer piping
printf 'INSERT INTO active_records (password) VALUES (%s);\n' $(quoteSQL "$PASSWORD") | doSQL

5
投票

这似乎是使用错误工具完成工作的典型案例。

您还有大量工作要做,要在 bash 中实现由 mysql_real_escape_string()

 完成的转义。请注意,
mysql_real_escape_string()
实际上将转义委托给MySQL库,该库考虑了连接和数据库字符集。它之所以被称为“真实”,是因为它的前身
mysql_escape_string()
没有考虑字符集,并且可能被欺骗注入SQL。

我建议使用具有 MySQL 库的脚本语言,例如 Ruby、Python 或 PHP。

如果您坚持使用 bash,请使用

MySQL 准备语句 语法。


2
投票

mysql_real_escape_string()

 当然只转义要引用的单个字符串文字,而不是整个语句。您需要清楚该字符串在语句中的用途。根据 MySQL 手册中关于“字符串文字”的部分,要插入字符串字段,您只需要转义单引号和双引号、反斜杠和 NUL。但是,bash 字符串不能包含 NUL,因此以下内容就足够了:
#escape for MySQL single string PASSWORD=${PASSWORD//\\/\\\\} PASSWORD=${PASSWORD//\'/\\\'} PASSWORD=${PASSWORD//\"/\\\"}

如果您要在
LIKE
之后使用字符串,您可能还想转义

%

_
准备好的陈述是另一种可能性。并确保您不在 bash 中使用 
echo -e

另请参阅 
https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet

这将避开撇号

0
投票
a=$(echo "$1" | sed s/"'"/"\\\'"/g)

请注意 mysql_real_escape_string 也会转义 \x00, , 、 \、 " 和 \x1a。为了完全安全,请务必转义这些内容。

例如要转义 \x00:

a=$(echo "$1" | sed s/"\x00"/"\\\'"/g)

只要稍加努力,您就可以使用一个 sed 命令来逃避这些。
    

当然,为什么不直接使用真实的东西呢?

0
投票

脚本,任何地方,例如

〜/脚本/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); ?>

接下来,从 bash 终端运行:

chmod +x ~/script/mysqli_real_escape.php` ln -s ~/script/mysqli_real_escape.php /usr/bin/mysqli_real_escape

一切就绪!现在您可以在 bash 脚本中使用 
mysqli_real_escape


#!/bin/bash MyString="stringW@#)*special characters" MyString="$(printf "$MyString" | mysqli_real_escape )"

注意:据我了解,使用
"$(cmd ..."$var")"
的命令替换优于使用反引号。然而,由于不需要进一步的嵌套,所以两者都应该没问题。

进一步注意:当在命令替换中时,
"$(...)"

,会创建一个新的引用上下文。这就是变量周围的引号不会弄乱字符串的原因。


我就是这样做的,其中

0
投票
包含空格、换行符和引号:

IFS='' content=$(cat my-file.txt)
mysql <flags> -e "update table set column = $(echo ${content@Q} | cut -c 2-) where something = 123"

这是我编写的几个 Bash 函数,它们被分组到一个库中。

0
投票
它提供了正确引用/转义字符串和标识符的方法:

##### db library functions ##### # Executes SQL Queries on localhost's MySQL server # # @Env # $adminDBUser: The database user # $adminDBPassword: The database user's password # # @Params # $@: Optional MySQL arguments # # @Output # >&1: The MySQL output stream db::execute() { # Uncomment below to debug #tee --append debug.sql | mysql \ --batch \ --silent \ --user="${adminDBUser:?}" \ --password="${adminDBPassword:?}" \ --host=localhost \ "$@" } # Produces a quoted string suitable for inclusion in SQL statements. # # @Params # $1: The string to bo quoted # # @Output # >&1: The quoted identifier suitable for inclusion in SQL statements db::quoteString() { local -- string="${1:?}" local -- bas64String && bas64String=$(printf %s "${string}" | base64) db::execute <<< "SELECT QUOTE(FROM_BASE64('${bas64String}'));" } # Produces a quoted identifier suitable for inclusion in SQL statements. # # @Params # $1: The identifier to bo quoted # # @Output # >&1: The quoted identifier suitable for inclusion in SQL statements db::quoteIdentifier() { local -- identifier="${1:?}" local -- bas64Identifier && bas64Identifier=$(printf %s "${identifier}" | base64) db::execute <<< "SELECT sys.quote_identifier(FROM_BASE64('${bas64Identifier}'))" }

简短回答:使用 

0
投票
(转义字符)。

如果您的值具有美元字符,例如:
$p123$hello

,那么在 bash 中您可以通过

\

 来转义。那么字符串将是 
\$p123\$hello

以我为例,我已经这样更改密码:

mysql> update users set password='\$p123\$hello' where id = 1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0

这会起作用:

-2
投票
echo "John O'hara" | php -R 'echo addslashes($argn);'

将其传递给变量:

name=$(echo "John O'hara" | php -R 'echo addslashes($argn);')


© www.soinside.com 2019 - 2024. All rights reserved.