SQL注入介绍

SQL注入会引发什么问题?
SQL注入是一种对数据库的恶意攻击,注入进去的恶意指令就会被误认为是正常的SQL指令而执行,因此遭到破坏或是入侵。
什么是SQL注入?
SQL注入(英语:SQL injection),也称SQL注入SQL注码,是发生于应用程序与数据库层的安全漏洞。简而言之,是在输入的字符串之中注入SQL指令,在设计不良的程序当中忽略了字符检查,那么这些注入进去的恶意指令就会被数据库服务器误认为是正常的SQL指令而执行,因此遭到破坏或是入侵。
为什么会发生SQL注入?
在设计不良的应用程序中,对用户输入数据的合法性并没有判断或过滤不严导致。

 

图片[1]-SQL注入介绍 - 知识库-知识库
如图中所示,没有对客户端用户输入的数据合法性进行检查或过滤,导致客户端用户可以任意构造自己想要的参数,达成SQL注入条件,最终引发严重的后果,如果在账号登录成功SQL注入,那么就可以成功登录他人的账号,使用对他人的账号进行一系列破环手段,比如黑客通过SQL注入成功登录你的微信,可以使用你微信里面的余额,给你的家人朋友发钓鱼链接等等。
当然SQL注入的危害远不止可以成功登录他人的账号,还有可能造成的伤害如下
  • 资料表中的资料外泄,例如企业及个人机密资料,账户资料,密码等。

  • 数据结构被黑客探知,得以做进一步攻击(例如SELECT * FROM sys.tables)。

  • 数据库服务器被攻击,系统管理员账户被窜改(例如ALTER LOGIN sa WITH PASSWORD=’xxxxxx’).

  • 获取系统较高权限后,有可能得以在网页加入恶意链接、恶意代码以及Phishing等。

  • 经由数据库服务器提供的操作系统支持,让黑客得以修改或控制操作系统(例如

    xp_cmdshell “net stop iisadmin”可停止服务器的IIS服务)。

  • 攻击者利用数据库提供的各种功能操纵文件系统,写入Webshell,最终导致攻击者攻陷系统

  • 破坏硬盘资料,瘫痪全系统(例如xp_cmdshell “FORMAT C:”)。

  • 获取系统最高权限后,可针对企业内部的任一管理系统做大规模破坏,甚至让其企业倒闭。

    网站主页被窜改,导致声誉受到损害。

  • 总之作为程序设计者,需要保证程序的健壮性避免被SQL注入攻击。

如何避免SQL注入?

  1. 所有的查询语句都使用数据库提供的参数化查询(Parameterized Query)接口,参数化的语句使用参数而不是将用户输入变量嵌入到 SQL语句中,当前几乎所有的数据库系统都提供了参数化 SQL语句执行接口,使用此接口可以非常有效的防止 SQL注入攻击。
    set @name := xxx;
    set @pwd := xxx;
    select id from users where name = @name and pwd = @pwd
  2. 在组合SQL字符串时,先针对所传入的参数加入其他字符(对进入数据库的特殊字符('<>&*;等)进行转义处理)。
  3. 确认每种数据的类型,比如数字型的数据就必须是数字,数据库中的存储字段必须对应为int型。
    try:
    pwd = int(param.get("pwd"))
    except (TypeError, ValueError):
    return "pwd type must be int"
    
  4. 数据长度应该严格规定,能在一定程度上防止比较长的SQL注入语句无法正确执行。

    name_max_length = 12
    if len(param.get("name", "")) > name_max_length:
    return "name length cannot be greater than 12"
    

     

     
  5. 网站每个数据层的编码统一,建议全部使用 UTF-8编码,上下层编码不一致有可能导致一些过滤模型被绕过。
  6. 严格限制网站用户的数据库的操作权限,给此用户提供仅仅能够满足其工作的权限,从而最大限度的减少注入攻击对数据库的危害
  7. 避免网站显示 SQL错误信息,比如类型错误、字段不匹配等,防止攻击者利用这些错误信息进行一些判断。

案例

这里分析一个案例

1.数据库中先创建用户表及数据

-- 创建一张用户表
CREATE TABLE `users` (
`id` INT(11) NOT NULL AUTO INCREMENT,
`username` VARCHAR(20),
`password` VARCHAR(50),
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
-- 插入数据
INSERT INTO users(username,`password`) VALUES('张三','456123'),('李
四','qqatfv'),('王五','Qwe123');
INSERT INTO users(username,`password`) VALUES('小张','987456'),('小
王','ngjplg'),('小李','!@#$%^');
-- 查看数据
SELECT * FROM users;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | 张三	| 456123 |
| 2 | 李四	| qqatfv |
| 3 | 王五	| Qwe123 |
| 4 | 小张	| 987456 |
| 5 | 小王	| ngjplg |
| 6 | 小李	| !@#$%^ |
+----+----------+----------+
6 rows in set (0.00 sec)

2.编写一个登录程序

import pymysql
def login():
# 打开数据库连接
db = pymysql.connect(host='127.0.0.1', port=3306, user='root',
passwd='12345', db='test', charset='utf8')
# 使用 cursor() 方法创建一个游标对象 cursor
cursor = db.cursor()
username = input('请输入用户名:')
password = input('请输入密码:')
sql = "select * from users where username = '%s' and password =
'%s'" % (username, password)
print(sql)
# 执行SQL语句
cursor.execute(sql)
results = cursor.fetchone()
if results:
print('登录成功')
else:
print('登录失败')
# 关闭数据库连接
db.close()

2.1.正常登录

>>> login()
请输入用户名:>? 张三
请输入密码:>? 456123
select * from users where username = '张三' and password = '456123'
登录成功, 你好:张三

2.2.登录失败

>>> login()
请输入用户名:>? 张三
请输入密码:>? 123456
select * from users where username = '张三' and password = '123456'
用户名或密码错误,请重新输入

2.3.模拟注入

此处我们给SQL注入了一个or '1' = '1' 的条件,此时不管密码是否正确都可以成功登录
login()
请输入用户名:>? 张三
请输入密码:>? 123456' or '1' = '1
select * from users where username = '张三' and password = '123456' or
'1' = '1'
登录成功, 你好:张三

3.解决方法,采用参数化查询

import pymysql
def login():
# 打开数据库连接
db = pymysql.connect(host='127.0.0.1', port=3306, user='root',
passwd='12345', db='test', charset='utf8')
# 使用 cursor() 方法创建一个游标对象 cursor
cursor = db.cursor()
username = input('请输入用户名:')
password = input('请输入密码:')
sql = "select * from users where username = %s and password = %s"
# 执行SQL语句
cursor.execute(sql, (username, password))
results = cursor.fetchone()
if results:
print('登录成功, 你好:', username)
else:
print('用户名或密码错误,请重新输入')
# 关闭数据库连接
db.close()

3.1.正常登录

>>> login()
请输入用户名:>? 张三
请输入密码:>? 456123
登录成功, 你好:张三

3.2.登录失败

>>> login()
请输入用户名:>? 张三
请输入密码:>? 123456
用户名或密码错误,请重新输入

3.3.继续模拟注入

此处我们给SQL注入了一个 or '1' = '1' 的条件,此时我们使用的是参数化查询方式有效的防止了SQL注入

login()
请输入用户名:>? 张三
请输入密码:>? 123456' or '1' = '1
用户名或密码错误,请重新输入

 

 
 
© 版权声明
THE END
喜欢就支持一下吧
点赞15赞赏 分享
评论 抢沙发

请登录后发表评论

    请登录后查看评论内容