本文是翻译,版权归原作者所有



问题解读

我觉得,这个问题每年带来的成本可以高达数十亿美元了。本文就来谈谈,假定我们有如下 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 语法的规则。想要符合一组未知的规则,将是难以解决的问题。因此,攻击者通常无法得手。

注释

解决 SQL 注入的另类方法的更多相关文章

  1. 使用过滤器解决SQL注入和跨站点脚本编制

    1 SQL注入.盲注 1.1 SQL注入.盲注概述 Web 应用程序通常在后端使用数据库,以与企业数据仓库交互.查询数据库事实上的标准语言是 SQL(各大数据库供应商都有自己的不同版本).Web 应用 ...

  2. MySQL_(Java)使用preparestatement解决SQL注入的问题

    MySQL_(Java)使用JDBC向数据库发起查询请求 传送门 MySQL_(Java)使用JDBC创建用户名和密码校验查询方法 传送门 MySQL数据库中的数据,数据库名garysql,表名gar ...

  3. JDBC_08_解决SQL注入问题 (登录和注册)

    解决SQL注入问题 只要用户提供的信息不参与sql语句的编译过程,那么尽管用户输入的信息中含有sql关键字那么也不会起作用了 要想使用户提供信息不参与sql语句的编译过程,那么必须使用 java.sq ...

  4. IBatis.Net使用总结(一)-- IBatis解决SQL注入(#与$的区别)

    IBatis解决SQL注入(#与$的区别) 在IBatis中,我们使用SqlMap进行Sql查询时,需要引用参数,在参数引用中可以使用两种占位符#和$.这两种占位符有什么区别呢? (1):#***#, ...

  5. PreparedStatement解决sql注入问题

    总结 PreparedStatement解决sql注入问题 :sql中使用?做占位符 2.得到PreparedStatement对象 PreparedStatement pst=conn.prepar ...

  6. MyBatis是如何解决Sql注入的

    转:[转]mybatis如何防止sql注入 java中预处理PrepareStatement为什么能起到防止SQL注入的作用??!! 一.SQL注入 sql注入大家都不陌生,是一种常见的攻击方式,攻击 ...

  7. MySQL 及 SQL 注入与防范方法

    所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令. 我们永远不要信任用户的输入,我们必须认定用户输入的数据都是不安全的, ...

  8. jdbc 07: 解决sql注入

    jdbc连接mysql,解决sql注入问题 package com.examples.jdbc.o7_解决sql注入; import java.sql.*; import java.util.Hash ...

  9. Ibatis自动解决sql注入机制

    疑问1:为什么IBatis解决了大部分的sql注入?(实际上还有部分sql语句需要关心sql注入,比如like) 之前写Java web,一直使用IBatis,从来没有考虑过sql注入:最近写php( ...

随机推荐

  1. swift 获取文件的Md5值

    获取文件的Md5值的方法如下 func md5File(url: URL) -> String? { let bufferSize = 1024 * 1024 do { //打开文件 let f ...

  2. [算法题] Remove Duplicates from Sorted Array ii

    题目内容 本题来源LeetCode Follow up for "Remove Duplicates": What if duplicates are allowed at mos ...

  3. 小米wifi

    场景:把小米wifi插主机上,作为热点发射器:然后使用手机搜索到这个热点,建立wifi连接 驱动:当"把小米wifi插主机上"的时候,主机可能无法识别这个设备,所以需要前往官网下载驱动 下载地址:ht ...

  4. 数据结构-->栈

    首先,栈是什么? 在代码当中,栈主要是一种实现特殊功能的一种数据结构,而不是像数组.集合之类的数据存储工具.它最大的特点就是后进先出. 那么后进先出是什么? 假设有一个数组,我们向里面添加一个数据,再 ...

  5. OS作业模拟进程分配与回收

    OS的一个作业, 模拟进程的分配与管理 # initialize the memories and the process list(actually a dict) total_memory = 1 ...

  6. mac系统读写NTFS格式的移动硬盘

    Mac OS X默认情况下,对于NTFS的移动硬盘只能读不能写,可通过将移动硬盘格式化为exFAT 或者安装NTFS相关的工具,达到可读写的目的,但对于系统的安全性方面,以上方式得不到保证:在Mac ...

  7. MySQL触发器学习

    简介 MySQL从5.0.2版本开始支持触发器的功能.触发器是与表有关的数据库对象,在满足定义条件时触发,并执行触发器中定义的语句集合. 创建触发器 语法: CREATE TRIGGER trigge ...

  8. SpringMVC入门--编写一个SpringMVC小程序

    一.SpringMVC的优势 Spring 为展现层提供的基于 MVC 设计理念的优秀的Web 框架,是目前最主流的 MVC 框架之一.Spring3.0 后全面超越 Struts2,成为最优秀的 M ...

  9. 在配置wem.xml后,Tomcat遇到问题,启动失败的解决方法

    前两天在写程序时,碰到了Tomcat无法启动的问题,就是在配置完web.xml后.想必好多小伙伴都有遇到吧. 如图: 出现这个错误的原因是:在配置web.xml的时候出现了错误! 如图所示,没有修改这 ...

  10. JavaScript 中的相等性判断

    摘自:MDN https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Equality_comparisons_and_sameness: Ja ...