SQL注入是应用程序遭受的最常见的攻击类型之一。鉴于其常见性及潜在的破坏性,需要在了解原理的基础上探讨如何保护应用程序免受其害。
什么是SQL注入
SQL注入(也称为SQLi)是指攻击者成功篡改Web应用输入,并在该应用上执行任意SQL查询。此种攻击通常会利用编程语言用来括住字符串的转义字符。攻击者想方设法用表单字段或URL参数向应用注入额外的SQL代码进而获得在目标数据库上执行未经授权的操作的能力。
图1:SQL注入原理
SQL注入的影响
实现SQL注入的攻击者可以更改目标数据库中的数据。如果目标应用使用的数据库连接字符串授予用户写入权限,SQL注入可能会造成重大破坏:攻击者可以删除大量数据,甚至删除表本身。
此外,即使攻击者只能获得对数据库的读取权限,也可能会导致敏感数据泄露,如财务信息或行业机密等业务敏感信息,以及客户的私人信息等。随着隐私法规越来越完善,数据泄露也是SQL注入最危险的后果之一。
Java中的SQL注入
Java语言已经存在了几十年。尽管开发人员拥有包含稳定的应用框架和可靠的ORM的丰富生态系统,仍不足以保护Java免于SQL注入攻击。以Ruby为例。尽管Rails是一个稳定的开发框架,但是SQL注入仍构成了Ruby应用70%的安全威胁。
以如下Java代码片段为例:
String sql = "select "
+ "id, title, excerpt, body"
+ "from Posts where slug = '"
+ slug
+ "'";
代码通过关联用户以某种方式输入的值(可能是URL参数)来组装SQL查询。
这段代码的问题在于通过用户提供的值进行关联。假设这个Web应用的基URL是
https://example.com/posts
如果我们将my-first-java-project添加到URL中,它变为
example.com/posts/my-first-java-projec
相应的SQL代码会变为
selectid, title, excerpt,bodyfromPostswhereslug ='my-first-java-project'
这段代码看起来似乎没什么问题。
进一步地,假设一个不太善意的用户将URL设置为
https://example.com/posts/whatever%27%20or%20%271%27=%271
其中实际传递的参数是
‘whatever’or‘1’=’1′
得出的SQL代码是
selectid, title, excerpt,bodyfromPostswhereslug ='whatever'or'1'='1'
现在攻击者已经成功注入了未经授权的代码。SQL查询的where子句有了一个判断' 1 '是否等于' 1 '的附加条件。鉴于1=1是真命题,所有POST请求都可以被取回。
这看起来不是什么大问题;但如果对象是敏感的客户信息,也即获取敏感信息只需要一点点SQL注入,问题就不容忽视了。
防御Java SQL注入的技术
尽管SQL注入攻击很常见,而且具有潜在的破坏性,但它们并非无法防御。被利用的漏洞大多源于编码错误,改进方向有以下几种:。
1.使用参数化查询
针对Java中的SQL注入,可以从使用参数化查询入手。下面的例子基于前一节中提到的查询语句进行了改动
String sql = "selectid, title, excerpt,bodyfromPostswhereslug = ?";
用一个问号形式的占位符替换了关联信息。下一步是创建一个预编译语句,并给它绑定参数值
Connectionconnection = dataSource.getConnection();PreparedStatementp = c.prepareStatement(sql);p.setString(1,slug);
通过使用参数化查询,我们可以以一种安全的方式组装查询语句与用户提交的值。
2.允许列表输入验证
这种方法是使用参数化查询的补充。
白名单输入验证是指将输入限制为预先编译的已知有效值列表,并对其余输入进行拦截。这包括使用正则表达式来验证某些类型的信息、验证数值参数是否符合预期范围以及检查参数是否符合预期数据类型。
建议对所有类型的用户输入进行URL参数、表单字段、导入文件的内容等验证。
3.以最小授权执行查询
SQL注入一旦成功,需确保应用使用的连接字符串给予用户最小授权。在应用的特定部分,唯一需要的数据库权限是读取权限。这里推荐使用只有读取权限的连接字符串;即便攻击者能够注入未经授权的代码,至少无法更改或删除数据。
4.利用Java持久化
防御SQL注入的另一种方法是使用JPQL (Java持久性查询语言)。JPA (Java Persistence API)有几种实现方式,最流行的是Spring Data JPA和Hibernate。它们为应用提供了额外的数据层,有助于降低SQL注入成功的概率。
Java安全漏洞概述
SQL注入是Web应用最常遭受攻击类型之一;此外,还有许多安全威胁是Java开发人员应该注意的,包括:
(1) 恶意Jar
(2) XSS注入
(3) Java LDAP注入
(4) XPath注入
(5) SecurityManager漏洞
以下是一些增强Java应用安全性的建议:
1、识别第三方漏洞。现代应用通常对第三方库和工具有很多依赖。使用SCA(软件成分分析)工具对代码进行检测,并形成软件物料清单(SBOM),盘点代码中引入的第三方组件及这些组件引入的漏洞风险,并围绕SBOM建立安全管理流程。
图2:SCA图例
2、安全左移。在SDLC中尽早引入安全管理,使用自动化工具及相应的管理流程来支持安全编码实践。
3、敏捷右移。应用上线后进入安全运营阶段,使用监控和保护应用安全的工具是关键,RASP能结合应用的逻辑及上下文,以函数级的精度对访问应用系统的每一段代码进行检测,实时监控安全状况、记录并阻断攻击,而无需人工干预。
图3:RASP原理
SQL注入并不复杂,但其影响却不容小觑。本文介绍了一些防御手段,以避免Java应用成为SQL注入的牺牲品。安全理念、自动化工具及有效的安全管理流程共同构成了保护应用免于安全威胁的终极保障。