在数据库中执行增删改查等操作时,若SQL语句的部分内容由用户键盘录入,如果录入的为非法值,那么会给整个数据库带来很大的安全风险,这种情况我们称之为SQL的注入攻击.
以用户登录某系统为例,演示SQL的注入攻击:
- 在数据库中录入用户个人信息
# 创建用户信息表
create table user_info(
uid int primary key auto_increment,
uname varchar(20),
upasswd varchar(20),
remain_asset decimal(10,2)
);
# 录入用户个人信息
insert into user_info values (null,'xiaoming666','666888',40000),(null,'xiaohong888','888666',30000);
- 通过python的pymysql库交互
# 导包
import pymysql
# 用户键入账号和密码,为了演示注入攻击效果,不采用input语句,直接赋值
uname = 'djisjf'
upasswd = 'sfjie"or"1=1'
# 创建连接对象,以本机为例,host为本地回路地址
conn = pymysql.connect(
host = '127.0.0.1',
port = 3306,
user = 'xxxx', # 数据库账号
password = 'xxxx', # 数据库密码
database = 'xxxx', # 要连接的数据库
charset = 'utf8'
);
# 创建游标对象
cur = conn.cursor()
# 执行sql语句,获取结果集
sql = 'select * from xxxx where uname = "{uname}" and upasswd = "{upasswd}";' # 由于用户的非法录入,获取了所有账户的个人信息
data = cur.execute(sql)
# 遍历结果集
for line in data:
print(line)
# 释放资源
cur.close()
conn.close()
那么如何应对SQL注入攻击呢?我们采用占位符来进行预编译,确保用户不管输入何值,整体都是一个字符,具体见下:
# 导包
import pymysql
# 用户键入账号和密码,为了演示注入攻击效果,不采用input语句,直接赋值
uname = 'djisjf'
upasswd = 'sfjie"or"1=1'
# 创建连接对象,以本机为例,host为本地回路地址
conn = pymysql.connect(
host = '127.0.0.1',
port = 3306,
user = 'xxxx', # 数据库账号
password = 'xxxx', # 数据库密码
database = 'xxxx', # 要连接的数据库
charset = 'utf8'
);
# 创建游标对象
cur = conn.cursor()
# 执行sql语句,获取结果集
sql = 'select * from xxxx where uname = %s and upasswd = %s;'
params = [uname,upasswd]
data = cur.execute(sql,params) # 此时用户的任何输入,都会以字符的形式放入预先编译好的sql语句中
# 遍历结果集
for line in data:
print(line)
# 释放资源
cur.close()
conn.close()