如何防止SQL注入攻击¶
SQL是指结构化查询语言,在关系型数据库中,使用SQL来操作数据库。
SQL注入攻击是伪造一些特殊请求字符串,来操作数据库。产生一些和程序员预期行为不一致的结果。
例如用户登录,通常有几种实现方法,假定设计用户认证表为包含三个字段,id, user_name, passwd, 表中含有三条记录:
1, zhang abcdef
2, wang 666666
3, zhao 999999
如果某个用户登录,我们的python代码如下:
import sqlite3
class DatabaseConn:
def __init__(self, sql_db):
self.conn = sqlite3.connect(sql_db)
self.conn.row_factory = sqlite3.Row
self.c = self.conn.cursor()
self.c.execute('''CREATE TABLE IF NOT EXISTS users (user_name text, passwd text)''')
def query(self, username, passwd):
"""不安全的用法"""
sql = "select * from users where user_name='{}' and passwd='{}'".format(username, passwd)
print(sql)
self.c.execute(sql)
r = self.c.fetchone()
print("row type:", type(r))
def query2(self, username, passwd):
"""安全用法,在传入参数时,使用?来格式化执行"""
self.c.execute("select * from users where user_name=? and passwd=? ", [username, passwd])
r = self.c.fetchone()
print("row type:", type(r))
def __del__(self):
self.conn.close()
conn = DatabaseConn('newdict.db')
conn.query("zhang", "abcdef")
conn.query("zhang", "123456")
conn.query("zhang", "' or 1!='")
conn.query2("zhang", "abcdef")
conn.query2("zhang", "123456")
conn.query2("zhang", "' or 1!='")
我们使用DatabaseConn对象来管理sqlite数据库连接,对象创建时连接数据库。 释放时关闭数据库。通过query,query2方法来对数据进行查询,我们对比一下 两个方法的差异。
如果我们使用query方法来查询用户账号和密码,如果是正确的密码,会找到记录 ,允许登录。如果是错误的密码,例如123456,找不到记录,不允许登录。 假设用户输入密码为带有单引号字符”’ or 1!=’”, 也会执行找到记录, 因为sql语句会转换为:
select * from users where user_name='zhang' and passwd='' or 1!=''
这就是 sql 注入攻击,利用了我们代码实现的缺陷来对平台进行操作,甚至销毁数据库等等。 因此我们要防范数据库注入攻击。
使用 query2 方法可以避免这种sql注入攻击。它会把参数进行编译,只是当做一个参数, 而不会当做sql关键字来执行。