from https://blog.ansheng.me/article/mysql-sql-injection
SQL注入
是一种代码注入技术,过去常常用于攻击数据驱动性的应用,比如将恶意的SQL代码注入到特定字段用于实施拖库攻击等。
SQL注入
的成功必须借助应用程序的安全漏洞,例如用户输入没有经过正确地过滤(针对某些特定字符串)或者没有特别强调类型的时候,都容易造成异常地执行SQL语句。
SQL注入
是网站渗透中最常用的攻击技术,但是其实SQL注入可以用来攻击所有的SQL数据库。
SQL注入的实现
1、初始化数据库
- 创建
SQLdb
数据库
CREATE DATABASE SQL_injection;
- 创建
user_info
表
CREATE TABLE `user_info` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) DEFAULT NULL,
`password` varchar(32) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
插入一条用户数据
测试的用户名是
ansheng
,密码as
insert into user_info(username,password) values("ansheng","as");
2、Python代码
app.py
文件
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web
import pymysql
class LoginHandler(tornado.web.RequestHandler):
def get(self, *args, **kwargs):
self.render('login.html')
def post(self, *args, **kwargs):
username = self.get_argument('username', None)
password = self.get_argument('password', None)
conn = pymysql.connect(host='127.0.0.1', port=3306, user='<user>', passwd='<password>', db='SQL_injection')
cursor = conn.cursor()
temp = "SELECT username FROM user_info WHERE username='%s' AND password = '%s'" %(username, password,)
effect_row = cursor.execute(temp)
result = cursor.fetchone()
conn.commit()
cursor.close()
conn.close()
if result:
self.write('Successfuly login.')
else:
self.write('Unable to login.')
application = tornado.web.Application([
(r"/login", LoginHandler),
])
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
3、HTML代码
login.html
与 app.py
文件在同一级目录下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/login" method="post">
<input type="text" name="username" placeholder="username" /><br>
<input type="text" name="pwd" placeholder="password" /><br>
<input type="submit" />
</form>
</body>
</html>
演示效果
- 打开终端,在项目目录下,输入命令
python app.py
打开浏览器,输入地址
http://127.0.0.1:8888/login
填写表单:
用户名:asas ' or 1 = 1-- asd
密码:s
(随便填写一串字母)
当点击
提交
的时候是否会跳转到登陆成功页面?如果你的代码和我一样,那么就会跳转到登陆成功页面
。
为什么出现这种问题?
出现这个问题的主要原因,是因为我们使用了 字符串拼接
的方式来进行SQL指令的拼接。
SQL指令拼接代码
temp = "SELECT username FROM user_info WHERE username='%s' AND password = '%s'" %(username, pwd,)
- 正常的SQL拼接出来的结果
SELECT username FROM user_info WHERE username='ansheng' AND password = 'as'
- 非正常的SQL拼接出来的结果
SELECT username FROM user_info WHERE username='asas' or 1 = 1 -- asd' AND password = 's'
由于在 sql 语句中:
--
之后的内容,全部视为注释
WHERE 1=1
或者WHERE 1
,表示条件永远成立(True)
所以,非正常拼接的 SQL,亦可以得到搜索结果。
如何防止?
通过 Python 的 pymysql
模块来进行 SQL
的执行,在 pymysql
模块内部会自动把 “'
” (单引号) 做一个特殊的处理,来预防上述的错误:
effect_row = cursor.execute("SELECT username FROM user_info WHERE username='%s' AND password = '%s'", (username, password))