Python操作MySQL时防止SQL注入


下面是网上搜到的一篇关于SQL注入的文章。最近在项目中涉及到防止SQL注入的部分,但是由于使用的是PYTHON和MYSQL,使用不了JAVA代码中提供的一些现成的方法,而且MYSQLDB模块中的EXECUTE方法不支持表名使用占位符。

execute(self,query, args=None)

Execute a query.

query -- string, query to execute on serverargs -- optional sequence or mapping, parameters to use with query.

Note: If args is a sequence, then %s must be used as theparameter placeholder in the query. If a mapping is used,%(key)s must be used as the placeholder.

Returns long integer rows affected, if any

Placeholders are supposed to be used for *values*, not other parts of the SQL statement. To insert table names, column names and stuff like that, use Python-level formatting.

cur.execute("select * from %s where name=%s",('t1','xx'))   --python-level formatting,执行失败

cur.execute("select * from %s where name=%s"%('t1','xx'))  --execute()-level formatting,执行成功,但是并没有达到防止SQL注入的效果

下面是文档上的一个例子

To perform a query, you first need a cursor, and then you can executequeries on it:

  1. c=db.cursor()  
  2. max_price=5  
  3. c.execute("""SELECT spam, eggs, sausage FROM breakfast 
  4.           WHERE price < %s""", (max_price,))  

In this example, max_price=5 Why, then, use%s in thestring? Because MySQLdb will convert it to a SQL literal value, whichis the string '5'. When it's finished, the query will actually say,"...WHERE price < 5".

无奈之下手工实现,需要两步:

1、把变量值中的单引号逃逸掉

2、给变量值两端加上单引号

#######################
应该说,您即使没有处理 HTML 或 JavaScript 的特殊字符,也不会带来灾难性的后果,但是如果不在动态构造 SQL 语句时对变量中特殊字符进行处理,将可能导致程序漏洞、数据盗取、数据破坏等严重的安全问题。网络中有大量讲解 SQL 注入的文章,感兴趣的读者可以搜索相关的资料深入研究。

虽然 SQL 注入的后果很严重,但是只要对动态构造的 SQL 语句的变量进行特殊字符转义处理,就可以避免这一问题的发生了。来看一个存在安全漏洞的经典例子:

以上 SQL 语句根据返回的结果数判断用户提供的登录信息是否正确,如果 userName 变量不经过特殊字符转义处理就直接合并到 SQL 语句中,黑客就可以通过将 userName 设置为 “1' or '1'='1”绕过用户名/密码的检查直接进入系统了。

所 以除非必要,一般建议通过 PreparedStatement 参数绑定的方式构造动态 SQL 语句,因为这种方式可以避免 SQL 注入的潜在安全问题。但是往往很难在应用中完全避免通过拼接字符串构造动态 SQL 语句的方式。为了防止他人使用特殊 SQL 字符破坏 SQL 的语句结构或植入恶意操作,必须在变量拼接到 SQL 语句之前对其中的特殊字符进行转义处理。Spring 并没有提供相应的工具类,您可以通过 jakarta commons lang 通用类包中(spring/lib/jakarta-commons/commons-lang.jar)的 StringEscapeUtils 完成这一工作:

清单 4. SqlEscapeExample
 
  1. package com.baobaotao.escape;  
  2. import org.apache.commons.lang.StringEscapeUtils;  
  3. public class SqlEscapeExample {  
  4.     public static void main(String[] args) {  
  5.         String userName = "1' or '1'='1";  
  6.         String password = "123456";  
  7.         userName = StringEscapeUtils.escapeSql(userName);  
  8.         password = StringEscapeUtils.escapeSql(password);  
  9.         String sql = "SELECT COUNT(userId) FROM t_user WHERE userName='"  
  10.             + userName + "' AND password ='" + password + "'";  
  11.         System.out.println(sql);  
  12.     }  
  13. }  
事实上, StringEscapeUtils 不但提供了 SQL 特殊字符转义处理的功能,还提供了 HTML、XML、JavaScript、Java 特殊字符的转义和还原的方法。如果您不介意引入 jakarta commons lang 类包,我们更推荐您使用 StringEscapeUtils 工具类完成特殊字符转义处理的工作。

相关内容