addslashes() Versus mysql_real_escape_string()

本文展示了如何利用GBK编码特性绕过addslashes()函数进行SQL注入攻击,通过改变字符编码,使得单引号在数据库查询中成功注入,强调了使用mysql_real_escape_string()等更安全的方法的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Last month, I discussed Google's XSS Vulnerability and provided an example that demonstrates it. I was hoping to highlight why character encoding consistency is important, but apparently the addslashes() versus mysql_real_escape_string()debate continues. Demonstrating Google's XSS vulnerability is pretty easy. Demonstrating an SQL injection attack that is immune to addslashes() is a bit more involved, but still pretty straightforward.

In GBK0xbf27 is not a valid multi-byte character, but 0xbf5c is. Interpreted as single-byte characters, 0xbf27 is 0xbf (¿) followed by 0x27 ('), and 0xbf5c is 0xbf(¿) followed by 0x5c (\).

How does this help? If I want to attempt an SQL injection attack against a MySQL database, having single quotes escaped with a backslash is a bummer. If you're usingaddslashes(), however, I'm in luck. All I need to do is inject something like 0xbf27, and addslashes() modifies this to become 0xbf5c27, a valid multi-byte character followed by a single quote. In other words, I can successfully inject a single quote despite your escaping. That's because 0xbf5c is interpreted as a single character, not two. Oops, there goes the backslash.

I'm going to use MySQL 5.0 and PHP's mysqli extension for this demonstration. If you want to try this yourself, make sure you're using GBK. I just changed /etc/my.cnf, but that's because I'm testing locally:

TOGGLE CODE VIEW

  1. [client]
  2. default-character-set=GBK

Create a table called users:

TOGGLE CODE VIEW

  1. CREATE TABLE users (
  2. username VARCHAR(32) CHARACTER SET GBK,
  3. password VARCHAR(32) CHARACTER SET GBK,
  4. PRIMARY KEY (username)
  5. );

The following script mimics a situation where only addslashes() (ormagic_quotes_gpc) is used to escape the data being used in a query:

TOGGLE CODE VIEW

  1. <?php
  2.  
  3. $mysql= array();
  4.  
  5. $db=mysqli_init();
  6. $db->real_connect('localhost','myuser','mypass','mydb');
  7.  
  8. /* SQL Injection Example */
  9. $_POST['username'] = chr(0xbf) .
  10. chr(0x27) .
  11. ' OR username = username /*';
  12. $_POST['password'] = 'guess';
  13.  
  14. $mysql['username'] = addslashes($_POST['username']);
  15. $mysql['password'] = addslashes($_POST['password']);
  16.  
  17. $sql="SELECT *
  18. FROM users
  19. WHERE username = '{$mysql['username']}'
  20. AND password = '{$mysql['password']}'";
  21.  
  22. $result=$db->query($sql);
  23.  
  24. if ($result->num_rows) {
  25. /* Success */
  26. } else {
  27. /* Failure */
  28. }
  29.  
  30. ?>

Despite the use of addslashes(), I'm able to log in successfully without knowing a valid username or password. I can simply exploit the SQL injection vulnerability.

To avoid this type of vulnerability, use mysql_real_escape_string()prepared statements, or any of the major database abstraction libraries.

This type of attack is possible with any character encoding where there is a valid multi-byte character that ends in 0x5c, because addslashes() can be tricked into creating a valid multi-byte character instead of escaping the single quote that follows. UTF-8 does not fit this description.

<think>好的,用户正在寻找SQL注入防护相关的内置过滤函数,特别是提到了mysql_escape_string、str_replace、intval、addslashes这几个函数。我需要根据提供的引用内容,整理出这些函数的使用方法和注意事项。 首先,我需要回顾每个引用中的相关信息。引用1提到mysql_real_escape_string必须在PHP4>=4.3.0和PHP5中使用,否则用mysql_escape_string,但两者有区别,前者考虑连接字符集。引用2指出,即使使用PDO的模拟预处理,如果PHP版本低且未指定charset,仍然可能有注入漏洞,建议升级PHP并设置charset。引用4展示了一个post_check函数,里面用到了addslashes、str_replace等函数,并处理了magic_quotes_gpc的情况。引用5给出了使用mysql_real_escape_string的示例。引用3提到了MySQL的报错函数,可能和注入攻击有关,但用户的问题是关于防护函数,所以这部分可能暂时不用。 接下来,我需要将每个函数的信息整理出来。mysql_real_escape_string需要考虑连接字符集,比mysql_escape_string更安全,但已弃用。addslashes用于转义特殊字符,但依赖于magic_quotes_gpc的设置,引用4中的函数处理了这个情况。str_replace用于过滤特定字符,如%和_。intval用于确保数值类型,防止注入。同时,PDO的参数绑定和预处理语句是更推荐的方法,如引用2提到的设置EMULATE_PREPARES为false,并指定charset。 需要注意的是,用户可能想知道这些函数的适用场景、限制以及最佳实践。比如,虽然某些函数可以过滤,但单独使用可能不够,需要组合其他方法。例如,引用4中的函数不仅用了addslashes,还处理了magic_quotes_gpc,替换了%和_,并进行HTML转义。这可能超出SQL注入的范围,但用户可能关心整体输入过滤。 另外,用户提到的函数中有mysql_escape_string,但根据引用1,这个函数已经过时,推荐使用mysql_real_escape_string,而后者在PHP7中也被移除,所以最终应该建议使用PDO或MySQLi的参数化查询。 可能还需要提到,过滤函数虽然有用,但参数化查询才是更根本的解决方案,因为过滤容易遗漏,而参数化能从根本上分离数据和指令。引用2中提到的PDO设置就是一个例子。 总结:需要分点列出每个函数的作用、注意事项,并强调参数化查询的重要性。同时,引用相关的内容来支持每个点,比如引用1和5关于mysql_real_escape_string,引用4关于addslashes和str_replace,引用2关于PDO的设置。</think>### SQL注入防护常用内置过滤函数及注意事项 #### 1. **`mysql_real_escape_string`** 用于转义字符串中的特殊字符(如单引号、双引号、反斜杠等),需基于当前数据库连接的字符集处理[^1]。 - **适用场景**:拼接SQL语句时对字符串参数进行转义。 - **注意事项**: - 仅在PHP 4.3.0+和PHP 5+版本可用,且需确保已建立数据库连接。 - PHP 7中已弃用,建议改用参数化查询(如PDO或MySQLi)。 示例: ```php $username = mysql_real_escape_string($_POST['username']); $sql = "SELECT * FROM users WHERE username='$username'"; ``` --- #### 2. **`addslashes`** 自动转义单引号、双引号、反斜杠和NULL字符,但依赖`magic_quotes_gpc`配置[^4]。 - **适用场景**:兼容旧代码时,需手动判断`magic_quotes_gpc`状态[^4]。 - **注意事项**: - 若`magic_quotes_gpc=On`,重复转义会导致数据错误。 - 无法防御多字节编码注入(如GBK宽字节漏洞)。 示例(结合`magic_quotes_gpc`判断): ```php if (!get_magic_quotes_gpc()) { $input = addslashes($input); } ``` --- #### 3. **`str_replace`** 用于过滤特定危险字符(如`%`、`_`),常用于模糊查询场景。 - **适用场景**:防止LIKE子句中的通配符滥用。 - **注意事项**: - 需手动定义需过滤的字符列表。 - 不能替代参数化查询或转义函数。 示例: ```php $input = str_replace(array("%", "_"), array("\%", "\_"), $input); ``` --- #### 4. **`intval`** 将变量强制转换为整数类型,用于处理数值型参数[^5]。 - **适用场景**:确保ID、年龄等参数为整数。 - **注意事项**: - 仅适用于纯数字输入,对字符串无效。 示例: ```php $id = intval($_GET['id']); $sql = "SELECT * FROM articles WHERE id=$id"; ``` --- #### 5. **`PDO参数化查询`**(推荐) 通过预处理语句分离数据与SQL指令,从根本上防御注入[^2]。 - **注意事项**: - 需设置`PDO::ATTR_EMULATE_PREPARES=false`并指定DSN字符集,避免模拟预处理漏洞。 示例: ```php $pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'user', 'pass'); $stmt = $pdo->prepare("SELECT * FROM users WHERE email = :email"); $stmt->execute(['email' => $email]); ``` --- ### 综合建议 1. **优先使用参数化查询**(PDO或MySQLi),避免手动拼接SQL[^2]。 2. 若必须拼接SQL,组合使用过滤函数(如`intval`+`mysql_real_escape_string`)并严格校验输入格式。 3. 升级到PHP 5.3.6+,并在DSN中指定字符集(如`charset=utf8`)。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值