首页 | 新闻 | 交流 | 问吧 | 文档 | 手册 | 下载 | 博客

PHP与MySQL中的SQL注入式漏洞

作者:  时间: 2011-06-08

SQL注入式漏洞是许多PHP程序的主要安全危害,产生的原因是在向数据库执行插入等语句时,web开发者允许最终用户操作变量(例如根据表单提交内容显示相应信息),通常是_GET、_POST或_SESSION等全局变量。

让我们看以下的代码:

  1. <?php
  2. query = "Select news_title, news_text "
  3. query .= "FROM news"
  4. query .= "Where news_id=". _GET['id']; 
  5. mysql_query(query); 
  6. ?> 

如果认为其中的_GET[‘id’]会永远是个数值型的值那将是很严重的错误。最终用户可以改变这个变量的值,例如"0; Delete FROM news;",那么query语句就会变成下面的值:

Select news_title, news_text FROM news Where news_id=0; Delete FROM news;

这将产生很严重的后果。


验证数值型数据

数值型数据是最容易验证的,PHP有一个自带的函数叫 is_numeric()可以返回ture值来判断是否是数值型,这个函数并不是MySQL自带的,因此可在任何数据库平台的php程序中用于验证数字。

下面是修改后的代码:

  1. <?PHP 
  2. if (!is_numeric(_GET['id'])) 
  3. // id's not numeric? 
  4. // kill the script before the query can run 
  5. die("The id must be numeric!"); 
  6. query = "Select news_title, news_text "
  7. query .= "FROM news"
  8. query .= "Where news_id=". _GET['id']; 
  9. mysql_query(query); 
  10. ?> 

 

验证非数值型数据


非数值型数据的验证稍有点麻烦。PHP有个叫Magic Quotes的特殊功能。当它激活时,PHP会自动过滤掉_GET和_POST全局变量中的反斜线符号(\),双引号(”),单引号(’)和空白字符。问题是并不是所有的服务器都能打开了这个功能,所以必须检测服务器是否开通了这个功能。可以使用get_magic_quotes_gpc()函数来判定maigc quotes功能是否打开。
在MySQL查询语句可以使用mysql_real_escape_string()函数来增强安全性,代码如下:

  1. <?PHP 
  2. // Fix a _POST variable called firstName for MySQL 
  3. firstName = _POST['firstName']; 
  4. if (get_magic_quotes_gpc()) 
  5. // If magic quotes is enabled - turn the string back into an unsafe string 
  6. firstName = stripslashes(firstName); 
  7. // Now convert the unsafe string into a MySQL safe string 
  8. firstName= mysql_real_escape_string(firstName); 
  9. // firstName should now be safe to insert into a query 
  10. ?> 

 

输出到页面

为正确显示字符中的引号和反斜线,应使用stripslashes()函数

  1. <?PHP 
  2. firstName = _POST['firstName']; 
  3. if (get_magic_quotes_gpc()) 
  4. // If magic quotes is enabled - turn the string back into an unsafe string 
  5. firstName = stripslashes(firstName); 
  6. // Now convert the unsafe string into a MySQL safe string 
  7. firstName = mysql_real_escape_string(firstName); 
  8. // Safe query 
  9. mysql_query("Insert INTO Names VALUES('". firstName ."')"); 
  10. // Page output should look proper 
  11. echo "Hello ". htmlentities(stripslashes(firstName)); 
  12. ?> 

 

最终整合

最后可以建立一个简单的函数来解决在PHP中如果安全的进行MySQL查询字符。值得注意的是,如果要输出到WEB页面上还需要使用stripslashes。

  1. <?PHP 
  2. function VerifyInput(input, forceInt = false) 
  3. if (is_numeric(input)) 
  4. return input; 
  5. elseif (!forceInt) 
  6. if (get_magic_quotes_gpc()) 
  7. // if magic quotes is enabled, get rid of those 
  8. // pesky slashes 
  9. input = stripslashes(input); 
  10. // convert the input variable into a MySQL safe string. 
  11. input = mysql_real_escape_string(input); 
  12. return input; 
  13. else 
  14. // if input not an integer and forceInt = true, 
  15. // kill script 
  16. die("Invalid Input"); 
  17. // _POST['name'] should be a string 
  18. // _POST['id'] should be an integer, if not the script dies 
  19. id = _POST['id']; 
  20. name = _POST['name']; 
  21. query = "Update users SET name=". VerifyInput(name) ." "
  22. query .= "Where id=". VerifyInput(id, true); 
  23. // query should be safe to run 
  24. mysql_query(query); 
  25. ?>