关于 SQL 注入攻击

关于 SQL 注入攻击

引言

读了知乎帖子如何从根本上防止 SQL 注入,结合 python 的 exec 语句说说我的理解。

注入攻击示例

模拟数据库

class DataBase:
    
    def __init__(self):
        self.log = []
        self.data = []
    
    def execute(self, sql):
        self.log += [sql]
        exec(sql)

数据库先记录所执行的查询,再执行查询。这里所谓的“查询”就是对self.data操作的 python 语句。

模拟界面

class UI:
    
    sql = """self.data += [%s]"""
    
    def __init__(self):
        self.db = DataBase()
        
    def form(self):
        a = input('❤')
        self.db.execute(self.sql % a)
        print('谢谢~')

可以把这段代码想象为一个网站的后端,它有事先编写好的 SQL 语句模板,等待用户输入数据,然后向数据库发送拼接之后的语句。

实验

正常情况下:

ui = UI()
ui.form()110
> 谢谢~

ui.db.data
> [110]
ui.db.log
> ['self.data += [110]']

注入攻击:

ui.form()
❤]; del self.data[-1]; del self.log[-1]; #
> 谢谢~

ui.db.data
> []
ui.db.log
> ['self.data += [110]']

注入攻击破坏了原来的数据,还清除了日志。

参数化查询

类型 SQL

修改数据库,编辑locals改变 SQL 的运行环境。在这种情况下,用户无论输入什么都不会被当做代码被编译成 python 字节码。

class TypedDataBase:
    
    def __init__(self):
        self.log = []
        self.data = []
    
    def execute_with_args(self, sql, arguments):
        self.log += [sql]
        exec(sql, locals().update(arguments))

界面

class NewUI:
    
    sql = """self.data += [user_string]"""
    
    def __init__(self):
        self.db = TypedDataBase()
    
    def form(self):
        a = input('❤')
        self.db.execute_with_args(self.sql, {'user_string': a})

实验

nui = NewUI()
nui.form()123

nui.db.data
> ['123']
nui.db.log
> ['self.data += [user_string]']

nui.form()]; del self.data[-1]; del self.log[-1]; #

for d in nui.db.data:
    print(d)
> 123
> ]; del self.data[-1]; del self.log[-1]; #

nui.db.log
> ['self.data += [user_string]', 'self.data += [user_string]']

可见,注入攻击失效了。

并非“一切都是字符串”

注入攻击的根本原因是,服务器与数据库通信时,没有区分代码和数据。区分代码和数据的工作是数据库的 SQL 解析器完成的,是解析器从 SQL 字符串中推断出来的,这就给注入攻击留了机会。

如果将程序与数据(进程的变量空间)分开传送,就能从根本上防止注入攻击。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值