Python中防止sql注入的方法详解


Posted in Python onFebruary 25, 2017

前言

大家应该都知道现在web漏洞之首莫过于sql了,不管使用哪种语言进行web后端开发,只要使用了关系型数据库,可能都会遇到sql注入攻击问题。那么在Python web开发的过程中sql注入是怎么出现的呢,又是怎么去解决这个问题的?

当然,我这里并不想讨论其他语言是如何避免sql注入的,网上关于PHP(博主注:据说是世界上最?诺挠镅裕┓雷⑷氲母髦址椒ǘ加校?ython的方法其实类似,这里我就举例来说说。

起因

漏洞产生的原因最常见的就是字符串拼接了,当然,sql注入并不只是拼接一种情况,还有像宽字节注入,特殊字符转义等等很多种,这里就说说最常见的字符串拼接,这也是初级程序员最容易犯的错误。

首先咱们定义一个类来处理mysql的操作

class Database:
 aurl = '127.0.0.1'
 user = 'root'
 password = 'root'
 db = 'testdb'
 charset = 'utf8'

 def __init__(self):
  self.connection = MySQLdb.connect(self.aurl, self.user, self.password, self.db, charset=self.charset)
  self.cursor = self.connection.cursor()

 def insert(self, query):
  try:
   self.cursor.execute(query)
   self.connection.commit()
  except Exception, e:
   print e
   self.connection.rollback()

 def query(self, query):
  cursor = self.connection.cursor(MySQLdb.cursors.DictCursor)
  cursor.execute(query)
  return cursor.fetchall()

 def __del__(self):
  self.connection.close()

这段代码在我之前很多脚本里面都会看见,涉及到Python操作mysql数据库的脚本我都会写进去这个类,那么这个类有问题吗?
答案是:有!

这个类是有缺陷的,很容易造成sql注入,下面就说说为何会产生sql注入。

为了验证问题的真实性,这里就写一个方法来调用上面的那个类里面的方法,如果出现错误会直接抛出异常。

def test_query(articleurl):
 mysql = Database()
 try:
  querySql = "SELECT * FROM `article` WHERE url='" + articleurl + "'"
  chanels = mysql.query(querySql)
  return chanels
 except Exception, e:
  print e

这个方法非常简单,一个最常见的select查询语句,也使用了最简单的字符串拼接组成sql语句,很明显传入的参数 articleurl 可控,要想进行注入测试,只需要在articleurl的值后面加上单引号即可进行sql注入测试,这个不多说,肯定是存在注入漏洞的,脚本跑一遍,看啥结果

(1064, "You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''t.tips''' at line 1")

回显报错,很眼熟的错误,这里我传入的测试参数是

t.tips'

下面再说一种导致注入的情况,对上面的方法进行稍微修改后

def test_query(articleurl):
 mysql = Database()
 try:
  querySql = ("SELECT * FROM `article` WHERE url='%s'" % articleurl)
  chanels = mysql.query(querySql)
  return chanels
 except Exception, e:
  print e

这个方法里面没有直接使用字符串拼接,而是使用了 %s 来代替要传入的参数,看起来是不是非常像预编译的sql?那这种写法能不能防止sql注入呢?测试一下便知道,回显如下

(1064, "You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''t.tips''' at line 1")

和上面的测试结果一样,所以这种方法也是不行的,而且这种方法并不是预编译sql语句,那么怎么做才能防止sql注入呢?

解决

两种方案

     1> 对传入的参数进行编码转义

     2> 使用Python的MySQLdb模块自带的方法

第一种方案其实在很多PHP的防注入方法里面都有,对特殊字符进行转义或者过滤。

第二种方案就是使用内部方法,类似于PHP里面的PDO,这里对上面的数据库类进行简单的修改即可。

修改后的代码

class Database:
 aurl = '127.0.0.1'
 user = 'root'
 password = 'root'
 db = 'testdb'
 charset = 'utf8'

 def __init__(self):
  self.connection = MySQLdb.connect(self.aurl, self.user, self.password, self.db, charset=self.charset)
  self.cursor = self.connection.cursor()

 def insert(self, query, params):
  try:
   self.cursor.execute(query, params)
   self.connection.commit()
  except Exception, e:
   print e
   self.connection.rollback()

 def query(self, query, params):
  cursor = self.connection.cursor(MySQLdb.cursors.DictCursor)
  cursor.execute(query, params)
  return cursor.fetchall()

 def __del__(self):
  self.connection.close()

这里 execute 执行的时候传入两个参数,第一个是参数化的sql语句,第二个是对应的实际的参数值,函数内部会对传入的参数值进行相应的处理防止sql注入,实际使用的方法如下

preUpdateSql = "UPDATE `article` SET title=%s,date=%s,mainbody=%s WHERE id=%s"
mysql.insert(preUpdateSql, [title, date, content, aid])

这样就可以防止sql注入,传入一个列表之后,MySQLdb模块内部会将列表序列化成一个元组,然后进行escape操作。

总结

我之前的一些脚本中使用了存在sql注入漏洞的代码会慢慢改过来,好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

Python 相关文章推荐
Python 拷贝对象(深拷贝deepcopy与浅拷贝copy)
Sep 06 Python
Python ORM框架SQLAlchemy学习笔记之映射类使用实例和Session会话介绍
Jun 10 Python
Python字符串中查找子串小技巧
Apr 10 Python
python监控进程脚本
Apr 12 Python
Python判断两个list是否是父子集关系的实例
May 04 Python
使用Python处理BAM的方法
Sep 28 Python
Python利用递归实现文件的复制方法
Oct 27 Python
python实现nao机器人手臂动作控制
Apr 29 Python
python GUI库图形界面开发之PyQt5菜单栏控件QMenuBar的详细使用方法与实例
Feb 28 Python
使用Django xadmin 实现修改时间选择器为不可输入状态
Mar 30 Python
Python爬虫:Request Payload和Form Data的简单区别说明
Apr 30 Python
Django路由层如何获取正确的url
Jul 15 Python
Python 数据结构之旋转链表
Feb 25 #Python
Python数据结构之翻转链表
Feb 25 #Python
浅析python中SQLAlchemy排序的一个坑
Feb 24 #Python
python函数的5种参数详解
Feb 24 #Python
Python实现读取文件最后n行的方法
Feb 23 #Python
Python基础教程之tcp socket编程详解及简单实例
Feb 23 #Python
Python命令启动Web服务器实例详解
Feb 23 #Python
You might like
一个php作的文本留言本的例子(三)
2006/10/09 PHP
php实现对两个数组进行减法操作的方法
2015/04/17 PHP
php实现网站文件批量压缩下载功能
2015/10/28 PHP
php 实现Hash表功能实例详解
2016/11/29 PHP
快速解决PHP调用Word组件DCOM权限的问题
2017/12/27 PHP
javascript小数四舍五入多种方法实现
2012/12/23 Javascript
使用VS开发 Node.js指南
2015/01/06 Javascript
jquery实现红色竖向多级向右展开的导航菜单效果
2015/08/31 Javascript
JS+DIV+CSS排版布局实现美观的选项卡效果
2015/10/10 Javascript
JavaScript代码轻松实现网页内容禁止复制(代码简单)
2015/10/23 Javascript
angular基于路由控制ui-router实现系统权限控制
2016/09/27 Javascript
使用Nuxt.js改造已有项目的方法
2018/08/07 Javascript
JS实现十分钟倒计时代码实例
2018/10/18 Javascript
详解JavaScript原生封装ajax请求和Jquery中的ajax请求
2019/02/14 jQuery
vue踩坑记录之数组定义和赋值问题
2019/03/20 Javascript
探索JavaScript中私有成员的相关知识
2019/06/13 Javascript
JS立即执行的匿名函数用法分析
2019/11/04 Javascript
[01:10]DOTA2次级职业联赛 - Fly战队宣传片
2014/12/01 DOTA
Python中django学习心得
2017/12/06 Python
python实现图片识别汽车功能
2018/11/30 Python
搭建python django虚拟环境完整步骤详解
2019/07/08 Python
Python笔试面试题小结
2019/09/07 Python
python retrying模块的使用方法详解
2019/09/25 Python
CSS3结构性伪类选择器九种写法
2012/04/18 HTML / CSS
美国领先的奢侈手表在线零售商:WatchMaxx
2017/12/17 全球购物
巴西最好的男鞋:Rafarillo
2018/05/25 全球购物
Myprotein意大利官网:欧洲第一运动营养品牌
2018/11/22 全球购物
Ramy Brook官网:美国现代女装品牌
2019/06/18 全球购物
Notino罗马尼亚网站:购买香水和化妆品
2019/07/20 全球购物
C#面试常见问题
2013/02/25 面试题
环保公益策划方案
2014/08/15 职场文书
2014年维修电工工作总结
2014/11/20 职场文书
实习班主任自我评价
2015/03/11 职场文书
先进个人事迹材料(2016推荐版)
2016/03/01 职场文书
如何书写读后感?(附范文)
2019/07/26 职场文书
Golang 入门 之url 包
2022/05/04 Golang