中防止sql注入的方法详解

更新时间为, 二零一七年二月二十五日, 十五时四十四分十秒, 作者是一只猿。

SQL注入属于较为常见的网络攻击方式当中的一种, 它并非借助操作系统的漏洞来达成攻击行径, 而是瞄准程序员在编程那会儿所出现的疏忽之处, 借助SQL语句, 达成无需账号便可登录, 甚至还能对数据库予以篡改, 下面的这一篇文章着重给大伙介绍了有关针对SQL注入的防范举措, 有所需求的朋友能够去参考一番。

前言

众多人理应都清楚当下web漏洞里排在首位的便是sql了, 不论运用哪一种语言来开展web后端开发, 只要用到了关系型数据库, 或许都会碰到sql注入攻击方面的问题。那么在web开发的整个进程当中sql注入到底是怎样出现的, 并且又是怎样去把这个问题给解决掉的?

当然, 我这儿可不打算去探讨别的语言究竟是怎样去避免sql注入这种情况发生的, 在网络上, 关于PHP(博主注: 据说这是世界上最厉害的语言)防止注入的各种各样的方法到处都有, 这些方法实际上是相似的, 在这儿我就通过举例来讲一下。

起因

造成漏洞的缘由, 最为常见的便是字符串拼接了, 当然, 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()

这段代码, 在我先前好多好多脚本当中, 都是可以见到的, 那些涉及对mysql数据库进行操作的脚本, 我都会把它写进这个类里面, 那么, 这个类存在问题吗?

答案是:有!

Python使用MySQLdb防止sql注入_Python防止sql注入方法_python sql注入

这样的一个类, 存在着缺陷, 极易致使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

该方法极其简易,是一种极为常见的查询语句, 竟也运用了最为简单的字符串拼接来构成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")

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


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注入情况的发生之举呢?

解决

两种方案

Python使用MySQLdb防止sql注入_python sql注入_Python防止sql注入方法

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

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

第一种方案, 实际上在诸多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()

这里在执行之际, 会传入两个参数, 其中第一个是经过参数化的sql语句, 第二个是与之对应的实际的参数值。函数内部会针对传入的参数值开展相应的处理, 以此避免sql被注入。实际运用的方法像下面这样。


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

以防 sql 注入, 如此行事便可, 于传入一列表后, 于模块内部, 会把该列表序列化为一个元组, 随后开展操作。

总结

我在之前部分脚本里运用了存在 sql 注入破绽的代码, 会逐步改好, 行了, 上面这些便是这篇文章的所有内容, 期望本文内容能给大家的学习或者工作带去一定的助力, 要是有疑问大家能够留言沟通。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐