什么是 mysql_real_escape_string() 而addslashes() 没有?

Posted

技术标签:

【中文标题】什么是 mysql_real_escape_string() 而addslashes() 没有?【英文标题】:What does mysql_real_escape_string() do that addslashes() doesn't? 【发布时间】:2010-10-06 18:59:52 【问题描述】:

为什么我们需要一个特定于数据库的函数,比如 mysql_real_escape_string()? addlashes() 不能做什么?

暂时忽略参数化查询的优越替代方案,仅使用 addlashes() 的 web 应用仍然容易受到 SQL 注入的攻击,如果是,如何?

【问题讨论】:

【参考方案1】:

在处理多字节编码字符串时,Addslashes 通常不够好。

【讨论】:

任何以 0x5c 结尾的有效多字节字符的编码都可以在 addslashes() 后面加上引号。 Chris Shiflett 在他的博客上使用 GBK 提供了一个很好的例子。 shiflett.org/blog/2006/jan/… 恰恰相反——一般来说,addlashes 是可以的,但在极少数情况下,我们实际上需要 mres。【参考方案2】:

它添加斜线到:

\x00, \n, \r, \, ', " and \x1a. characters.

其中addslashes 只添加斜线

' \ and NUL

Ilias article 的功能也很详细

【讨论】:

【参考方案3】:

gs 被严厉否决的答案实际上是正确的。

标准 SQL 使用加倍来转义文字撇号。 MySQL 使用非标准反斜杠进行转义是默认设置,但它可以被禁用,而且经常被禁用,特别是在 sql_mode ANSI 中。

在这种情况下,只有双倍语法有效,并且您使用的任何应用程序都使用了 addlashes(或其他临时转义方法)将中断。 mysql_real_escape_string 将使用最适合连接的 sql_mode 的任何转义方法。

如果您仍在使用那些重复使用较低 128 个字符的讨厌的东亚编码,那么多字节编码问题也很重要,但您确实想改用 UTF-8。另一方面,\n-转义无关紧要,因为 MySQL 可以完美地处理语句中的原始换行符。

【讨论】:

【参考方案4】:

mysql_real_escape_string 比addslashes 做得更多

addslashes 在纯 ascii 上运行,对数据库一无所知。它逃脱了:

'\' "\" \\\ ASCII 0\0

mysql_real_escape_string 的目的是“创建一个可以在 SQL 语句中使用的合法 SQL 字符串”。 mysql_real_escape_string 考虑到连接的当前字符集(这就是为什么你必须始终传递一个有效的 $mysql 对象)。

它执行以下操作(取自 MySQL C API 文档):

以不会引起问题的方式编码:\'"、ASCII 0\n\rControl+Z 确保0 字节终止字符串(在 C api 中) 如果 $mysql 中链接的 DB 使用宽字符集,则可以执行多字节 (ascii) 到宽字符的转换。

我真的不知道 php 如何在内部存储字符串,但关键是当您使用 mysql_real_escape_string 时,所有这些都对 PHP 可用。我想主要区别在于mysql_real_escape_string 考虑连接的字符集,而addslashes 不能(它甚至不知道您连接到什么数据库)。

【讨论】:

大部分观点毫无意义。 addlashes 创建了同样合法的 SQL 字符串,不管它是什么意思。 mres 根本不进行字符转换。并且用 NUL 终止字符串是没有意义的。你从哪里弄来的? 直接来自文档。多字节可以转换为宽。 "The string pointed to by from must be length bytes long. You must allocate the to buffer to be at least length*2+1 bytes long. (In the worst case, each character may need to be encoded as using two bytes, and you need room for the terminating null byte.)"。我假设 PHP 库在后台调用 mysql_real_escape_string C API 函数。【参考方案5】:

somedb_real_escape_string() 是特定于数据库的,addslashes() 不是。

对于 MySQL,这意味着:

mysql_real_escape_string() 调用 MySQL的库函数 mysql_real_escape_string,其中 将反斜杠添加到以下内容 字符:\x00、\n、\r、\、'、" 和 \x1a.

(来自手册。)

【讨论】:

【参考方案6】:

为什么我们需要像 mysql_real_escape_string() 这样的特定于数据库的函数?

实际上,大多数时候我们不会。 一些极其罕见的编码需要此功能,并稍微美化 mysql 日志和转储。

仅使用 addlashes() 的 web 应用是否仍然容易受到 SQL 注入的攻击?

只要它使用任何单字节字符集或 utf8 - addslashes() 绝对安全。

addslashes() 不能做什么?

它可以保护 SQL 字符串字面量,以防一些罕见的编码。

但是,它不能自己完成。必须首先使用mysql_set_charset() 函数设置正确的编码。如果未使用此函数,mysql_real_escape_string() 在字符集处理方面的行为与addslashes() 完全相同 - 根本没有区别

【讨论】:

只要它使用任何单字节字符集或 utf8 - 使用 addlashes() 是完全安全的。为什么你会使用addslashes 作为一种做法,而一旦你使用 Unicode,就突然不得不改变你的做法? 不幸的是,从 PHP 你必须set the character set at the server level or use mysqli_set_charset。 C 中的情况并非如此。 @bobobobo “[addslashes 对 utf8 来说是完全安全的……如果你在使用 Unicode 后突然不得不改变你的做法,为什么还要使用 addslashes?”你误会了; UTF-8 Unicode。唯一易受攻击的情况是 non-Unicode 字符集,例如 GBK。也就是说,对于任何使用 Unicode 的人来说,addslashes() 都是完全安全的,而只有那些选择使用奇怪的国家字符集代替 Unicode 的人才不安全。 客观地解决addslashes() 案例的极其罕见答案之一。普通常识【参考方案7】:

我知道的唯一真正的区别是 mysql_real_escape_string() 在转义输入字符串时会考虑数据库的字符集。这两个函数都不会转义通配符 % 和 _,这仍然会使脚本对某些 SQL 注入开放。

【讨论】:

%和_与SQL注入无关。 在 MySQL 中,% 可以用作 GRANT 语句中的通配符。 MySQL 还将 _ 视为语句中的单个字符通配符。 %和_与SQL注入无关。【参考方案8】:

根据PHP manual:

mysql_real_escape_string() 调用 MySQL 的库函数 mysql_real_escape_string,该函数在以下字符前添加反斜杠:\x00、\n、\r、\、'、" 和 \x1a。

【讨论】:

【参考方案9】:

PHP 的 mysql_real_escape_string 函数或多或少会询问 mysql 哪些字符需要转义,其中的addslashses 函数只会在前面添加一个反斜杠和任何单引号 (') 、双引号 (")、反斜杠 () 或 NUL(NULL 字节)字符。

这两个实际效果是,addslashes 往往不适用于多字节字符,更重要的是,通过询问 mysql 需要转义哪些字符,可以避免未来可能的兼容性。使用 assslashes 有点像将几个特定字符硬编码到转义序列中。

【讨论】:

【参考方案10】:

它应该以其他引用工具没有的方式为 MySQL 转义字符串。

然而,更可取的是使用 mysqli 接口,并使用参数化的准备查询,而不是尝试确保所有字符串都正确转义。使用参数化查询避免了对这种混乱的字符串工作的需要,并大大降低了 SQL 注入的风险。

编辑:我将澄清一下为什么我考虑引用一个坏主意:很容易忘记何时何地需要引用 - 无论您的变量是字符串还是数字,是否已经被引用,等等。参数化查询没有这些问题,并且完全不需要引用。

【讨论】:

我想我应该澄清一下,我非常清楚参数化查询的优越性:)【参考方案11】:

根据我的理解 mysql_real_escape_string() 更精确地完成工作,因为它与 db 通信以首先检查需要编码的内容,然后进行相应的编码,不是吗?因此,它可以更有效地工作

为什么你想先做addslashes然后你会在显示数据之前删除那个slashes并且仍然addslashes不如mysql_real_escape_string高效,如果你使用mysql_query之类的db函数进行查询,请使用mysql_real_escape_string,或者我认为PDO与prepare是更好的方法,因为 mysql_real_escape_string 是特定于数据库的

【讨论】:

以上是关于什么是 mysql_real_escape_string() 而addslashes() 没有?的主要内容,如果未能解决你的问题,请参考以下文章

使用 mysql_real_escape_string 存储后保持 textarea 输入格式

MySQL QUOTE() 与 mysql_real_escape_string()?

mysql_real_escape_string() 坏了吗?

警告:mysql_real_escape_string():拒绝用户''@'localhost'的访问(使用密码:否)

sqli-labs less36 GET- Bypass MYSQL_real_escape_string (GET型绕过MYSQL_real_escape_string的注入)

如何在 PDO 中使用/编写 mysql_real_escape_string? [复制]