您当前的位置:首页 > 电脑百科 > 数据库 > MYSQL

怎么使用Python攻击SQL数据库

时间:2019-12-11 15:40:26  来源:  作者:

这次我们将介绍怎么防止Python注入SQL攻击。有上一篇的铺垫,我们废话不多说,开搞。。。

制作安全查询参数

在上一篇中,我们看到了入侵者如何利用系统并通过使用 字符串获得管理权限。问题是,我们允许直接执行从客户端传递的值到数据库,却不执行任何类型的检查或验证,所以SQL注入就是依赖于这种类型的漏洞。

在数据库查询中使用用户输入时,可能存在SQL注入漏洞。防止PythonSQL注入的关键是确保该值是不是我们的意愿使用。在前面的示例中,我们打算username用作字符串。实际上,它被用作原始SQL语句。

为了防止入侵者将原始SQL注入字符串参数的位置,可以转义引号:

>>> # BAD EXAMPLE. DON'T DO THIS!>>> username = username.replace("'", "''")

这只是一个例子。在试图阻止Python SQL注入时,需要考虑许多特殊的字符和情况。还好,数据库适配器提供了内置的工具,可以通过使用查询参数来防止Python SQL注入。它们代替普通的字符串插值来组成一个带有参数的查询。

注意:不同的适配器、数据库和编程语言以不同的名称引用查询参数。常见的名称包括绑定变量、替换变量和替换变量。

 

现在我们对这个漏洞有了更好的理解,我们可以用查询参数代替字符串插值来重写函数了:

def is_admin(username: str) -> bool: with connection.cursor() as cursor: cursor.execute(""" SELECT admin FROM users WHERE username = %(username)s """, { 'username': username }) result = cursor.fetchone()
 if result is None: # User does not exist return False
 admin, = result return admin

 

在第9行,我们使用了一个命名参数username来指示用户名应该放在哪里。注意,参数username不再被单引号包围。

在第11行,我们将username的值作为第二个参数传递给了sor.execute()。在数据库中执行查询时,连接将使用username的类型和值。

 

测试这个函数,尝试一些有效和无效的值,包括危险的字符串:

>>> is_admin('haki')False>>> is_admin('ran')True>>> is_admin('foo')False>>> is_admin("'; select true; --")False

该函数返回所有值都是预期的结果。更重要的是,无效的用户名已经不再起作用了。可以通过检查execute()生成的查询来看原因:

>>> with connection.cursor() as cursor:... cursor.execute("""... SELECT... admin... FROM... users... WHERE... username = %(username)s... """, {... 'username': "'; select true; --"... })... print(cursor.query.decode('utf-8'))SELECT adminFROM usersWHERE username = '''; select true; --'

 

该连接将username的值视为字符串,并终止Python SQL注入的字符可能转义该字符串的可能。

 

传递安全的查询参数

数据库适配器通常提供几种传递查询参数的方法。命名占位符通常是可读性最好的,但是一些实现可能从使用其他选项中获得。

 

让我们快速查看一下使用查询参数的一些正确和错误的方法。下面的代码块显示了希望避免的查询类型:

# BAD EXAMPLES. DON'T DO THIS!cursor.execute("SELECT admin FROM users WHERE username = '" + username + '");cursor.execute("SELECT admin FROM users WHERE username = '%s' % username);cursor.execute("SELECT admin FROM users WHERE username = '{}'".format(username));cursor.execute(f"SELECT admin FROM users WHERE username = '{username}'");

这些每一条语句都将用户名从客户机直接传递到数据库,而不执行任何检查或验证。这种代码适合引入Python SQL注入。

 

相比之下,这些类型的查询执行起来应该是安全的:

cursor.execute("SELECT admin FROM users WHERE username = %s'", (username, ));cursor.execute("SELECT admin FROM users WHERE username = %(username)s", {'username': username});

在这些语句中,用户名作为命名参数传递。数据库将在执行查询时使用用户名的指定类型和值,从而避免Python SQL注入。

 

使用SQL组成

到目前为止,我们已经将参数用于诸如数字、字符串和日期之类的值。但是,如果有一个需要组合不同查询,比如表名或列名,该怎么办呢?

 

受前一个示例的启发,让我们实现一个函数,该函数接受表的名称并返回该表中的行数:

# BAD EXAMPLE. DON'T DO THIS!def count_rows(table_name: str) -> int: with connection.cursor() as cursor: cursor.execute(""" SELECT count(*) FROM %(table_name)s """, { 'table_name': table_name, }) result = cursor.fetchone()
 rowcount, = result return rowcount

执行用户表:

Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 9, in count_rowspsycopg2.errors.SyntaxError: syntax error at or near "'users'"LINE 5: 'users'

该命令无法生成SQL。数据库适配器将变量视为字符串或文字,但是表名不是普通的字符串。所以这就是SQL组合的用武之地。

 

现在已经知道使用字符串插值表达式来编写SQL是不安全的。幸好,Psycopg提供了一个名为Psycopg的模块。帮助我们安全地编写sql查询。让我们使用psycopg.sql()重写这个函数:

from psycopg2 import sql
def count_rows(table_name: str) -> int: with connection.cursor() as cursor: stmt = sql.SQL(""" SELECT count(*) FROM {table_name} """).format( table_name = sql.Identifier(table_name), ) cursor.execute(stmt) result = cursor.fetchone()
 rowcount, = result return rowcount

现在有两个不同之处。首先,使用sql()来组合查询。然后,使用sql.Identifier()来注释参数值table_name。(标识符是列或表名。)

现在,尝试执行用户表上的函数:

>>> count_rows('users')2

接下来,让我们看看当表不存在时会发生什么:

>> count_rows('foo')Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 11, in count_rowspsycopg2.errors.UndefinedTable: relation "foo" does not existLINE 5: "foo" 

该函数抛出UndefinedTable异常。在接下来的步骤中,我们将使用这个异常来表明函数不会受到Python SQL注入攻击。

为了将它们放在一起,添加一个选项来将表中的行数计数到一定的限制, 这个特性对非常大的表很有用。要实现这一点,在查询中添加一个LIMIT子句,以及LIMIT值的查询参数:

from psycopg2 import sql
def count_rows(table_name: str, limit: int) -> int: with connection.cursor() as cursor: stmt = sql.SQL(""" SELECT COUNT(*) FROM ( SELECT 1 FROM {table_name} LIMIT {limit} ) AS limit_query """).format( table_name = sql.Identifier(table_name), limit = sql.Literal(limit), ) cursor.execute(stmt) result = cursor.fetchone()
 rowcount, = result return rowcount

在这个代码块中,使用sql.Literal()注释了limit。与前面的示例一样,psycopg在使用时将所有查询参数绑定为文字。但是,在使用sql()时,需要使用sql.Identifier()或sql.Literal()显式地注释每个参数。

执行该功能,以确保运行正常:


>> count_rows('users', 1)1>>> count_rows('users', 10)2


运行正常,确保也是安全的:

>> count_rows("(select 1) as foo; update users set admin = true where name = 'haki'; --", 1)Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 18, in count_rowspsycopg2.errors.UndefinedTable: relation "(select 1) as foo; update users set admin = true where name = '" does not existLINE 8: "(select 1) as foo; update users set adm...

此返回显示psycopg转义了该值,并且数据库将其视为表名。由于不存在具有此名称的表,因此引发了UndefinedTable异常,攻击失败了


私信小编01 领取完整项目代码

结论

我们已经成功地实现了一个组成动态SQL的函数,系统面临Python SQL注入的风险也没有了!

我们在查询中既使用了字面值,又使用了标识符,没有影响安全性。



Tags:Python   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
大家好,我是菜鸟哥,今天跟大家一起聊一下Python4的话题! 从2020年的1月1号开始,Python官方正式的停止了对于Python2的维护。Python也正式的进入了Python3的时代。而随着时间的...【详细内容】
2021-12-28  Tags: Python  点击:(1)  评论:(0)  加入收藏
学习Python的初衷是因为它的实践的便捷性,几乎计算机上能完成的各种操作都能在Python上找到解决途径。平时工作需要在线学习。而在线学习的复杂性经常让人抓狂。费时费力且效...【详细内容】
2021-12-28  Tags: Python  点击:(1)  评论:(0)  加入收藏
Python 是一个很棒的语言。它是世界上发展最快的编程语言之一。它一次又一次地证明了在开发人员职位中和跨行业的数据科学职位中的实用性。整个 Python 及其库的生态系统使...【详细内容】
2021-12-27  Tags: Python  点击:(2)  评论:(0)  加入收藏
菜单驱动程序简介菜单驱动程序是通过显示选项列表从用户那里获取输入并允许用户从选项列表中选择输入的程序。菜单驱动程序的一个简单示例是 ATM(自动取款机)。在交易的情况下...【详细内容】
2021-12-27  Tags: Python  点击:(4)  评论:(0)  加入收藏
近日只是为了想尽办法为 Flask 实现 Swagger UI 文档功能,基本上要让 Flask 配合 Flasgger, 所以写了篇 Flask 应用集成 Swagger UI 。然而不断的 Google 过程中偶然间发现了...【详细内容】
2021-12-23  Tags: Python  点击:(6)  评论:(0)  加入收藏
有不少同学学完Python后仍然很难将其灵活运用。我整理15个Python入门的小程序。在实践中应用Python会有事半功倍的效果。01 实现二元二次函数实现数学里的二元二次函数:f(x,...【详细内容】
2021-12-22  Tags: Python  点击:(32)  评论:(0)  加入收藏
Verilog是由一个个module组成的,下面是其中一个module在网表中的样子,我只需要提取module名字、实例化关系。module rst_filter ( ...); 端口声明... wire定义......【详细内容】
2021-12-22  Tags: Python  点击:(9)  评论:(0)  加入收藏
运行环境 如何从 MP4 视频中提取帧 将帧变成 GIF 创建 MP4 到 GIF GUI ...【详细内容】
2021-12-22  Tags: Python  点击:(6)  评论:(0)  加入收藏
面向对象:Object Oriented Programming,简称OOP,即面向对象程序设计。类(Class)和对象(Object)类是用来描述具有相同属性和方法对象的集合。对象是类的具体实例。比如,学生都有...【详细内容】
2021-12-22  Tags: Python  点击:(9)  评论:(0)  加入收藏
所谓内置函数,就是Python提供的, 可以直接拿来直接用的函数,比如大家熟悉的print,range、input等,也有不是很熟,但是很重要的,如enumerate、zip、join等,Python内置的这些函数非常...【详细内容】
2021-12-21  Tags: Python  点击:(5)  评论:(0)  加入收藏
▌简易百科推荐
作者:雷文霆 爱可生华东交付服务部 DBA 成员,主要负责Mysql故障处理及相关技术支持。爱好看书,电影。座右铭,每一个不曾起舞的日子,都是对生命的辜负。 本文来源:原创投稿 *爱可生...【详细内容】
2021-12-24  爱可生    Tags:MySQL   点击:(7)  评论:(0)  加入收藏
生成间隙(gap)锁、临键(next-key)锁的前提条件 是在 RR 隔离级别下。有关Mysql记录锁、间隙(gap)锁、临键锁(next-key)锁的一些理论知识之前有写过,详细内容可以看这篇文章...【详细内容】
2021-12-14  python数据分析    Tags:MySQL记录锁   点击:(18)  评论:(0)  加入收藏
binlog 基本认识 MySQL的二进制日志可以说是MySQL最重要的日志了,它记录了所有的DDL和DML(除了数据查询语句)语句,以事件形式记录,还包含语句所执行的消耗的时间,MySQL的二...【详细内容】
2021-12-14  linux上的码农    Tags:mysql   点击:(13)  评论:(0)  加入收藏
为查询优化你的查询 大多数的MySQL服务器都开启了查询缓存。这是提高性最有效的方法之一,而且这是被MySQL的数据库引擎处理的。当有很多相同的查询被执行了多次的时候,这些查...【详细内容】
2021-12-09  元宇宙iwemeta    Tags:mysql   点击:(15)  评论:(0)  加入收藏
测试的目的和原因,公司有很多程序员,每个程序员对数据库和表结构都有自己的理解。而且每个程序员的理解往往是以效率考虑。既然都是为了效率考虑,那么我就来测试一下究竟哪种使...【详细内容】
2021-12-08  吴彬的分享    Tags:Mysql数据库   点击:(14)  评论:(0)  加入收藏
当你们考虑项目并发的时候,我在部署环境,当你们在纠结使用ArrayList还是LinkedArrayList的时候,我还是在部署环境。所以啊,技术不止境,我在部环境。今天这篇文章缕一下在同一台服...【详细内容】
2021-12-08  秃头码哥    Tags:MySQL数据库   点击:(17)  评论:(0)  加入收藏
对于数据分析来说,MySQL使用最多的是查询,比如对数据进行排序、分组、去重、汇总及字符串匹配等,如果查询的数据涉及多个表,还需要要对表进行连接,本文就来说说MySQL中常用的查询...【详细内容】
2021-12-06  笨鸟学数据分析    Tags:MySQL   点击:(21)  评论:(0)  加入收藏
在学习SQL语句之前,首先需要区分几个概念,我们常说的数据库是指数据库软件,例如MySQL、Oracle、SQL Server等,而本文提到的数据库是指数据库软件中的一个个用于存储数据的容器。...【详细内容】
2021-11-24  笨鸟学数据分析    Tags:SQL语句   点击:(23)  评论:(0)  加入收藏
概述以前参加过一个库存系统,由于其业务复杂性,搞了很多个应用来支撑。这样的话一份库存数据就有可能同时有多个应用来修改库存数据。比如说,有定时任务域xx.cron,和SystemA域...【详细内容】
2021-11-05  Java云海    Tags:分布式锁   点击:(32)  评论:(0)  加入收藏
MySQL的进阶查询 一、 按关键字排序 使用ORDERBY语句来实现排序排序可针对一个或多个字段ASC:升序,默认排序方式 【升序是从小到大】DESC:降序 【降序是从大到小】ORDER BY的...【详细内容】
2021-11-05  Java热点    Tags:SQL语句   点击:(28)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条