MySQL解决SQL注入的另类方法详解

本文实例讲述了MySQL解决SQL注入的另类方法。分享给大家供大家参考,具体如下:

问题解读

我觉得,这个问题每年带来的成本可以高达数十亿美元了。本文就来谈谈,假定我们有如下 SQL 模板语句:

select * from T where f1 = '{value1}' and f2 = {value2}

现在我们需要根据用户输入值填充该语句:

value1=hello
value2=5

我们得到了下面的 SQL 语句,我们再提交给数据库:

select * from T where f1='hello' and f2=5

问题在于,攻击者可以构造如下的用户输入值:

value1=anything' or 1=1 or f1='whatever
value2=5

拼接好的最终语句就变成了:

select * from T where f1='anything' or 1=1 or f1='whatever' and f2=5

攻击者成功地改变了模板语句的语义。这种问题不单单发生在 SQL 上,还出现在通常使用模板的任何语言上,比如 HTML 和 shell 脚本。

常规解决方案的说明

SQL 是具备任意性和一致性的公理,token 和派生规则构成其公理化基础。要注意的一个词语是「任意性」。与 SQL 等价的公理化数不胜数。对于这种任意等价的表示,每一条合法的语句都能被准确地映射到 SQL 里的合法语句,其它语言亦然。在这种任意等价表示中,如果某语句是不合法的,那么它在 SQL 里也是不合法的。攻击者不可能构造出可以满足任何可能的、任意与 SQL 等价的规则。

策略1:根据不同的派生规则,用另一种语法扩展模板语句

例子1:前缀语言

SQL 使用中缀表示法注1。中缀表示法等价于 lisp 风格的前缀表示法注2。中缀与前缀:

a OP1 b OP2 c <=> (OP1 a (OP2 b c))

a、b、c 是标识符或值,OP1、OP2 是操作符或功能。

前缀表示法的示例语句:

(select * T (and (= f1 '{value1}') (= f2 {value2})))

该语句是等价的。它们在语义上属于外延。自动把 SQL 的中缀表示法转换成前缀表示法或其它表示法,都不算问题了。然而,攻击者的注入在前缀语法方面就是不合法的:

代码如下:

(select * T (and (= f1  'anything' or 1=1 or a='whatever') (= f2 5)))

语法错误。攻击者想要的是:

代码如下:

(select * T (or (= f1 'anything') (or (=1 1) (and (= a 'whatever') (= f2 5)))))

这是不同的。攻击者的注入不能输出合法的前缀语言。

例子2:欧拉表示法

另一个替代方法将数得着欧拉表示法了。从中缀表示法到欧拉:

a OP1 b OP2 c <=> OP1(a,OP2(b,c))

例子中的语句:

select( *,T,and(=(f1,'{value1}'),=(f2,{value2})))

而注入的语句将出现语法错误:

代码如下:

select( *,T,and(=(f1,'anything' or 1=1 or a='whatever'),=(f2,5)))

攻击者本来是想写成:

代码如下:

select( *,T,or(=(f1,'anything',or(=(1,1),and(=(a,'whatever'),=(f2,5))))))

攻击者正在做错误的事情。他的注入根本就没有注意到所选的任意标记法。

例子3:对象标记法(object notation)

还有一种替代方法,对象标记法。从前缀表示法到对象:

a OP1 b OP2 c <=> a.OP1(b).OP2(c)

例子的代码:

T.where(f1.=('{value1}').and(f2.=({value2})).select(*)

注入再一次折戟于语法:

T.where(f1.=('anything' or 1=1 or a='whatever').and(f2.=5)).select(*)

我不再提供正确答案了,读者可以当做练习,看看攻击者应该写成什么样子。

策略2:为 SQL 选择其它任意 token

keyword 常常是一门语言里的任意 token。重要的是它们在派生规则里的位置、而非它们的任意体现。你总是可以用其它 keyword 替换现有 keyword,并且来回转换。举个例子,我们可以将下面 SQL 语句中的 keyword 转换成我们姑且称为「任意的 brainfuck」:

代码如下:

{"select":"iph0ohKi", "*":"ieZoh4xa", "from":"aeZi5uja", "where":"OoJ4aX4n", "=":"eeQu2Zad", "(":"eiD5aera",")":"Soo2uach", "or":"Ocaig5Es"}

为了论证起见,我们将把操作数映射为 半任意的结构化序列:

T <=> @phai1Oa6@T@
hello <=> @phai1Oa6@hello@

phai1Oa6 是任意选取的字符序列。对于当前情形,例子:

select * from T where f1 = '{value1}' and f2 = {value2}

变成了:

iph0ohKi ieZoh4xa aeZi5uja @phai1Oa6@T@ OoJ4aX4n @phai1Oa6@f1@ eeQu2Zad '{value1}' @phai1Oa6@and@ @phai1Oa6@f2@ eeQu2Zad {value2}

这是合法的、任意的 brainfuck 语言。经过注入之后,我们得到了:

iph0ohKi ieZoh4xa aeZi5uja @phai1Oa6@T@ OoJ4aX4n @phai1Oa6@f1@ eeQu2Zad 'anything' or 1=1 or a='whatever' @phai1Oa6@and@ @phai1Oa6@f2@ eeQu2Zad 5

你可以看到,它包含的 token 有 'or' 和 '=',它们在任意的 brainfuck 语言中是不合法的。我们的语法说,你必须这样使用:

or <=> Ocaig5Es
= <=> eeQu2Zad

这些 token 也不是操作数,因为它们将只能被视作:

or <=> @phai1Oa6@or@
= <=> @phai1Oa6@=@

换句话说,注入之后的语句就变得不合法、也不可用了。

策略3:验证不变量

你数数下面模板语句例子中的 token 有几个?

[1] select [2] * [3] from [4] T [5] where [6] f1 [7] = [8] '{value1}' [9] and [10] f2 [11] = [12] {value2}
12 个。模板填充之后,总数必须仍然为 12,但是我们却看到了攻击者所引发的结果:

[1] select [2] * [3] from [4] T [5] where [6] f1 [7] = [8] 'anything' [9] or [10] 1 [11] = [12] 1 [13] or [14] a [15] = [16] 'whatever' [17] and [18] f2 [19] = [20] 5

现在有 20 个 token 。违反这种不变量,就暴露了有问题的地方。同样适用于相同语句的表示,除了任意的、brainfuck 语言。模板的填充根本不可能导致 token 数量的变化。

事实上,你可以试着使用其它不变量,并在填充之后进行验证。攻击者必须和它们保持一致。

结论

有些人提倡,程序员在填充 SQL 模板时,应该更加小心。应对 SQL 注入问题,只是需要在编程方面多加小心。很明显,这种方式算不上解决方案。人们仍然在校验用户输入值方面出现错误,最终接受了带有恶意的用户输入值。换句话说,单凭我们所有人更努力地工作,是无法根本解决这种问题的。

真正的解决方案在于,SQL 语句本身的任意性,并要求所有现存不变量都符合任意的等价结构的规则。无需程序员的干预,就能自动完成。

攻击者不得不符合一种未知的、任意的 brainfuck 语法的规则。想要符合一组未知的规则,将是难以解决的问题。因此,攻击者通常无法得手。

更多关于MySQL相关内容感兴趣的读者可查看本站专题:《MySQL日志操作技巧大全》、《MySQL事务操作技巧汇总》、《MySQL存储过程技巧大全》、《MySQL数据库锁相关技巧汇总》及《MySQL常用函数大汇总》

希望本文所述对大家MySQL数据库计有所帮助。

(0)

相关推荐

  • Mysql数据库使用concat函数执行SQL注入查询

    SQL注入语句有时候会使用替换查询技术,就是让原有的查询语句查不到结果出错,而让自己构造的查询语句执行,并把执行结果代替原有查询语句查询结果显示出来. 例如:原本查询语句是 复制代码 代码如下: select username,email,content from test_table where user_id=uid; 其中uid,是用户输入的.正常显示结果会出现用户名,用户邮箱,用户留言内容.但是如果uid过滤不严,我们可以构造如下SQL语句来获得任意数据表信息. 复制代码 代码如下: u

  • Pyhton中防止SQL注入的方法

    复制代码 代码如下: c=db.cursor() max_price=5 c.execute("""SELECT spam, eggs, sausage FROM breakfast           WHERE price < %s""", (max_price,)) 注意,上面的SQL字符串与后面的tuple之间的分隔符是逗号,平时拼写SQL用的是%. 如果按照以下写法,是容易产生SQL注入的: 复制代码 代码如下: c.execut

  • 分享两段简单的JS代码防止SQL注入

    1.URL地址防注入: //过滤URL非法SQL字符 var sUrl=location.search.toLowerCase(); var sQuery=sUrl.substring(sUrl.indexOf("=")+1); re=/select|update|delete|truncate|join|union|exec|insert|drop|count|'|"|;|>|<|%/i; if(re.test(sQuery)) { alert("请勿

  • MySQL 及 SQL 注入与防范方法

    所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令. 我们永远不要信任用户的输入,我们必须认定用户输入的数据都是不安全的,我们都需要对用户输入的数据进行过滤处理. 1.以下实例中,输入的用户名必须为字母.数字及下划线的组合,且用户名长度为 8 到 20 个字符之间: if (preg_match("/^\w{8,20}$/", $_GET['username'], $matches)) { $result =

  • 防御SQL注入的方法总结

    SQL 注入是一类危害极大的攻击形式.虽然危害很大,但是防御却远远没有XSS那么困难. SQL 注入可以参见:https://en.wikipedia.org/wiki/SQL_injection SQL 注入漏洞存在的原因,就是拼接 SQL 参数.也就是将用于输入的查询参数,直接拼接在 SQL 语句中,导致了SQL 注入漏洞. 1. 演示下经典的SQL注入 我们看到:select id,no from user where id=2; 如果该语句是通过sql字符串拼接得到的,比如: Strin

  • ASP.NET防范SQL注入式攻击的方法

    一.什么是SQL注入式攻击?  SQL注入式攻击就是攻击者把SQL命令插入到Web表单的输入域或页面请求的查询字符串,欺骗服务器执行恶意的SQL命令.在某些表单中,用户输入的内容直接用来构造(或者影响)动态SQL命令,或作为存储过程的输入参数,这类表单特别容易受到SQL注入式攻击.常见的SQL注入式攻击过程类如: ⑴ 某个ASP.NET Web应用有一个登录页面,这个登录页面控制着用户是否有权访问应用,它要求用户输入一个名称和密码. ⑵ 登录页面中输入的内容将直接用来构造动态的SQL命令,或者直

  • MySQL解决SQL注入的另类方法详解

    本文实例讲述了MySQL解决SQL注入的另类方法.分享给大家供大家参考,具体如下: 问题解读 我觉得,这个问题每年带来的成本可以高达数十亿美元了.本文就来谈谈,假定我们有如下 SQL 模板语句: select * from T where f1 = '{value1}' and f2 = {value2} 现在我们需要根据用户输入值填充该语句: value1=hello value2=5 我们得到了下面的 SQL 语句,我们再提交给数据库: select * from T where f1='h

  • PHP防范SQL注入的具体方法详解(测试通过)

    一个优秀的PHP程序员除了要能顺利的编写代码,还需要具备使程序处于安全环境下的能力.今天我们要向大家讲解的是有关PHP防范SQL注入的相关方法. 说到网站安全就不得不提到SQL注入(SQL Injection),如果你用过ASP,对SQL注入一定有比较深的理解,PHP的安全性相对较高,这是因为MYSQL4以下的版本不支持子语句,而且当php.ini里的 magic_quotes_gpc 为On 时. 提交的变量中所有的 ' (单引号), " (双引号), \ (反斜线) and 空字符会自动转为

  • Mysql优化order by语句的方法详解

    本篇文章我们将了解ORDER BY语句的优化,在此之前,你需要对索引有基本的了解,不了解的老少爷们可以先看一下我之前写过的索引相关文章.现在让我们开始吧. MySQL中的两种排序方式 1.通过有序索引顺序扫描直接返回有序数据 因为索引的结构是B+树,索引中的数据是按照一定顺序进行排列的,所以在排序查询中如果能利用索引,就能避免额外的排序操作.EXPLAIN分析查询时,Extra显示为Using index. 2.Filesort排序,对返回的数据进行排序 所有不是通过索引直接返回排序结果的操作都

  • mysql表名忽略大小写配置方法详解

    linux下mysql默认是要区分表名大小写的.mysql是否区分大小写设置是由参数lower_case_table_names决定的,其中: 1)lower_case_table_names = 0  区分大小写(即对大小写不敏感),默认是这种设置.这样设置后,在mysql里创建的表名带不带大写字母都没有影响,都可以正常读出和被引用. 2)lower_case_table_names = 1  不区分大小写(即对大小写敏感).这样设置后,表名在硬盘上以小写保存,MySQL将所有表名转换为小写存

  • Redis解决Session共享问题的方法详解

    企业项目中,一般都是将项目部署到多台服务器上,用nginx做负载均衡.这样可以减轻单台服务器的压力,不过这样也带来一些问题,例如之前单机部署的话,session存取都是直接了当的,因为请求就只到这一台服务器上,不需要考虑数据共享.接下来分别用8000和8001端口启动同一个项目,做一个简单演示: 测试接口代码: package com.wl.standard.controller; import cn.hutool.core.util.StrUtil; import com.wl.standar

  • SpringBoot统计、监控SQL运行情况的方法详解

    目录 1 基本概念 2 添加依赖 3 配置相关属性 3.1 如何配置 Filter 4 监控页面 5 sql监控 6 慢sql记录 7 spring 监控 8 去 Ad(广告) (1) 直接手动注释这段代码 (2) 使用过滤器过滤 9 获取 Druid 的监控数据 总结 1 基本概念 Druid 是Java语言中最好的数据库连接池. 虽然 HikariCP 的速度稍快,但是,Druid能够提供强大的监控和扩展功能,也是阿里巴巴的开源项目. Druid是阿里巴巴开发的号称为监控而生的数据库连接池,

  • PHP+mysql+ajax轻量级聊天室实现方法详解

    本文实例讲述了PHP+mysql+ajax轻量级聊天室实现方法.分享给大家供大家参考,具体如下: 做了一个QQ聊天交友网站,想加个聊天的功能,于是做完用PHP做了简单又强大的聊天室 1. 创建mysql数据库表: 复制代码 代码如下: create table chat( id bigint AUTO_INCREMENT,username varchar(20), chatdate datetime,msg varchar(500), primary key(id)); 2.编写建议连接数据库函

  • mysql主从复制读写分离的配置方法详解

    一.说明 前面我们说了mysql的安装配置,mysql语句使用以及备份恢复mysql数据;本次要介绍的是mysql的主从复制,读写分离;及高可用MHA; 环境如下: master:CentOS7_x64 mysql5.721 172.16.3.175 db1 slave1:CentOS7_x64 mysql5.7.21 172.16.3.235 db2 slave2:CentOS7_x64 mysql5.7.21 172.16.3.235 db3 proxysql/MHA:CentOS7_x64

  • Mysql账户管理原理与实现方法详解

    本文实例讲述了Mysql账户管理原理与实现方法.分享给大家供大家参考,具体如下: 账户管理 在生产环境下操作数据库时,绝对不可以使用root账户连接,而是创建特定的账户,授予这个账户特定的操作权限,然后连接进行操作,主要的操作就是数据的crud MySQL账户体系:根据账户所具有的权限的不同,MySQL的账户可以分为以下几种 服务实例级账号:,启动了一个mysqld,即为一个数据库实例:如果某用户如root,拥有服务实例级分配的权限,那么该账号就可以删除所有的数据库.连同这些库中的表 数据库级别

随机推荐