相关文章推荐
卖萌的鸡蛋面  ·  SQL Server 2005 ...·  2 年前    · 
从容的排球  ·  ES6、ES7、ES8、ES9、ES10新特 ...·  2 年前    · 
眉毛粗的水桶  ·  可以模拟刷ROM的安卓模拟器_百度知道·  2 年前    · 
风度翩翩的钱包  ·  2句代码轻松实现WPF最大化不遮挡任务栏并且 ...·  2 年前    · 
Code  ›  以Java的视角来聊聊SQL注入-阿里云开发者社区
mybatis sql注入 sql语言 sql注入攻击
https://developer.aliyun.com/article/930058
霸气的沙滩裤
2 年前
产品 解决方案 文档与社区 权益中心 定价 云市场 合作伙伴 支持与服务 了解阿里云
备案 控制台 登录/注册
开发者社区
首页
探索云世界
新手上云 云上应用构建 云上数据管理 云上探索人工智能
云计算 弹性计算 无影 存储 网络 倚天
云原生 容器 serverless 中间件 微服务 可观测 消息队列
数据库 关系型数据库 NoSQL数据库 数据仓库 数据管理工具 PolarDB开源 向量数据库

热门

Modelscope模型即服务 弹性计算 云原生 数据库 物联网 云效DevOps 龙蜥操作系统 平头哥 钉钉开放平台
大数据 大数据计算 实时数仓Hologres 实时计算Flink E-MapReduce DataWorks Elasticsearch 机器学习平台PAI 智能搜索推荐
人工智能 机器学习平台PAI 视觉智能开放平台 智能语音交互 自然语言处理 多模态模型 pythonsdk 通用模型
开发与运维 云效DevOps 钉钉宜搭 支持服务 镜像站 码上公益
探索云世界
云上快速入门,热门云上应用快速查找
了解更多
问产品
动手实践
考认证
TIANCHI大赛
活动广场
活动广场
丰富的线上&线下活动,深入探索云世界
任务中心
做任务,得社区积分和周边
高校计划
让每位学生受益于普惠算力
训练营
资深技术专家手把手带教
话题
畅聊无限,分享你的技术见解
开发者评测
最真实的开发者用云体验
乘风者计划
让创作激发创新
阿里云MVP
遇见技术追梦人
直播
技术交流,直击现场
下载
下载
海量开发者使用工具、手册,免费下载
镜像站
极速、全面、稳定、安全的开源镜像
技术资料
开发手册、白皮书、案例集等实战精华
插件
为开发者定制的Chrome浏览器插件
本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《 阿里云开发者社区用户服务协议 》和 《 阿里云开发者社区知识产权保护指引 》。如果您发现本社区中有涉嫌抄袭的内容,填写 侵权投诉表单 进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

什么是SQL注入


SQL注入是影响企业运营最具有破坏性的漏洞之一。

应用程序向后台数据库进行SQL查询时,如果为攻击者提供了影响该查询的能力,就会引起SQL注入。


1靶场准备


首先我们来准备一个web接口服务,该服务可以提供管理员的信息查询,这里我们采用springboot + jersey 来构建web服务框架,数据库则采用最常用的mysql。下面,我们来准备测试环境,首先建立一张用户表jwtk_admin,SQL如下:


image.png


然后插入默认的管理员:


image.png


这样我们就有了两位系统内置管理员了,管理员密码采用MD5进行Hash,当然这是一个很简单的为了作为研究靶场的表,所以没有很全的字段。


接下来,我们创建 spring boot + jersey 构建的 RESTFul web 服务,这里我们提供了一个通过管理员用户名查询管理员具体信息的接口,如下:



image.png


2SQL注入测试


首先我们以开发者正向思维向web服务发送管理员查询请求,这里我们用PostMan工具发送一个GET请求,请求与结果如下图所示:


image.png


不出我们和开发者所料,Web接口返回了我们想要的结果,用户名为admin的管理员信息。OK,现在开发任务完成,Git Push,Jira任务点为待测试,那么这样的接口就真的没有问题了吗?现在我们发送这样一条GET请求:

image.png

发送该请求后,我们发现PostMan没有接收到返回结果,而Web服务后台却开始抛 MySQLSyntaxErrorException 异常了,错误如下:


You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''xxxx''' at line 1


原因是在我们查询的 xxxx' 处sql语句语法不正确导致。这里我们先不讨论SQL语法问题,我们继续实验,再次构造一条GET查询请求:


image.png

此时,我们可以惊讶的发现,查询接口非但没有报错,反而将我们数据库 jwti_admin 表中的所有管理员信息都查询出来了:


image.png


这是什么鬼,难道管理员表中还有 name=xxxx'or'a'='a 的用户?这就是 SQL Injection 。


3注入原理分析



在接口中接受了一个String类型的name参数,并且通过字符串拼接的方式构建了查询语句。在正常情况下,用户会传入合法的name进行查询,但是黑客却会传入精心构造的参数,只要参数通过字符串拼接后依然是一句合法的SQL查询,此时SQL注入就发生了。正如我们上文输入的 name= xxxx'or'a'='a 与我们接口中的查询语句进行拼接后构成如下SQL语句:

image.png


当接口执行此句SQL后,系统后台也就相当于拱手送给黑客了,黑客一看到管理员密码这个hash,都不用去 cmd5 查了,直接就用123456密码去登录你的后台系统了。Why?因为123456的md5哈希太常见了,别笑,这就是很多中小网站的现实,弱口令横行,不见棺材不落泪!


好了,现在我们应该明白了,SQL Injection原因就是由于传入的参数与系统的SQL拼接成了合法的SQL而导致的,而其本质还是将用户输入的数据当做了代码执行。在系统中只要有一个SQL注入点被黑客发现,那么黑客基本上可以执行任意想执行的SQL语句了,例如添加一个管理员,查询所有表,甚至“脱裤” 等等,当然本文不是讲解SQL注入技巧的文章,这里我们只探讨SQL注入发生的原因与防范方法。


4JDBC的预处理


在上文的接口中,DAO使用了比较基础的JDBC的方式进行数据库操作,直接使JDBC构建DAO在比较老的系统中还是很常见的,但这并不意味着使用JDBC就一定不安全,如果我将传入的参数 xxxx'or'a'='a 整体作为参数进行name查询,那就不会产生SQL注入。在JDBC中,提供了 PreparedStatement (预处理执行语句)的方式,可以对SQL语句进行查询参数化,使用预处理后的代码如下:


image.png


同样,我们使用上文的注入方式注入 , 此时我们发现,SQL注入没能成功。现在,我们来打印一下被被预处理后的SQL, 看看 有什么变化:


image.png

看到了吗?所有的 ' 都被 \' 转义掉了,从而可以确保SQL的查询参数就是参数,不会被恶意执行,从而防止了SQL注入。


5Mybatis下注入防范


MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架, 其 几乎 避免了所有的 JDBC 代码和手动设置参数以及获取结果集。同时,MyBatis 可以对配置和原生Map使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录,因此mybatis现在在市场中采用率也非常高。这里我们定义如下一个mapper,来实现通过用户名查询管理员的接口:



image.png


同样提供Web访问接口:


image.png

接下来,我们尝试SQL注入name字段,可以发现注入并没有成功,通过打印mybatis的Log可以看到mybatis框架对参数进行了预处理处理,从而防止了注入:


image.png


那是否只要使用了mybatis就一定可以避免SQL注入的危险?我们把mapper做如下修改,将参数 #{name} 修改为 ${name} ,并使用 name='xxxx' or 'a'='a' 作为 GET请求的 参数,可以发现SQL注入还是发生了:


image.png


那这是为什么,mybatis ${} 与 #{} 的差别在哪里?

原来在mybatis中如果以 ${} 形式声明为SQL传递参数,mybatis将不会进行参数预处理,会直接动态拼接SQL语句,此时就会存在被注入的风险,所以在使用mybatis作为持久框架时应尽量避免采用 ${} 的形式进行参数传递,如果无法避免 (有些SQL如 like 、 in 、 order by 等,程序员可能依旧会选择 ${} 的方式传参) ,那就需要对传入参数自行进行转义过滤。


6JPA注入防范​


JPA 是Sun公司用来整合ORM技术,实现天下归一的ORM标准而定义的 Java Persistence API (java持久层API),JPA只是一套接口,目前引入JPA的项目都会采用 Hibernate 作为其具体实现,随着无配置Spring Boot框架的流行,JPA越来越具有作为持久化首选的技术,因为其能让程序员写更少的代码,就能完成现有的功能,例如强大的 JpaRepository ,常规的SQL查询只需按照命名规则定义接口,便可以不写SQL( JPQL/SQL )就可以实现数据的查询操作,从SQL注入防范的角度来说,这种将安全责任抛给框架远比依靠程序员自身控制来的保险。因此如果项目使用JPA作为数据访问层,基本上可以很大程度的消除SQL注入的风险。但是话不能说的太死,在我见过的一个Spring Boot项目中,虽然采用了JPA作为持久框架,但是有一位老程序员不熟悉于使用JPQL来构建查询接口,依旧使用字符串拼接的方式来实现业务,而为项目安全埋下了隐患。

安全需要一丝不苟, 安全是100 - 1 = 0的业务,即使你防御了99%的攻击,那还不算胜利,只要有一次被入侵了,那就有可能给公司带来很严重的后果 。

关于JPA的SQL注入,我们就不详细讨论了,因为框架下的注入漏洞属于框架漏洞范畴(如CVE-2016-6652),程序员只要遵循JPA的 开发规范,就无需担心注入问题,框架都为你做好幕后工作了。


7SQL注入的其他防范办法



很多公司都会存在老系统中有大量SQL注入风险代码的问题,但是由于其已稳定支持公司业务很久,不宜采用大面积代码更新的方式来消除注入隐患,所以需要考虑其采用他方式来防范SQL注入。除了在在SQL执行方式上防范SQL注入,很多时候还可以通过架构上,或者通过其他过滤方式来达到防止SQL注入的效果。

  • 一切输入都是不安全的:对于接口的调用参数,要进行格式匹配,例如admin的通过name查询的接口,与之匹配的Path应该使用正则匹配(因为用户名中不应该存在特殊字符),从而确保传入参数是程序控制范围之内的参数,即只接受已知的良好输入值,拒绝不良输入。注意:验证参数应将它与输出编码技术结合使用。
  • 利用分层设计来避免危险:前端尽量静态化,尽量少的暴露可以访问到DAO层的接口到公网环境中,如果现有项目,很难修改存在注入的代码,可以考虑在web服务之前增加WAF进行流量过滤,当然代码上就不给hacker留有攻击的漏洞才最好的方案。也可以在拥有nginx的架构下,采用OpenRestry做流量过滤,将一些特殊字符进行转义处理。
  • 尽量使用预编译SQL语句:由于动态SQL语句是引发SQL注入的根源。应使用预编译语句来组装SQL查询。
  • 规范化:将输入安装规定编码解码后再进行输入参数过滤和输出编码处理;拒绝一切非规范格式的编码。


小结

其实随着ORM技术的发展,Java web开发在大趋势上已经越来越远离SQL注入的问题了,而有着Entity Framework框架支持的ASP.NET MVC从来都是高冷范。在现在互联网中,使用PHP和Python构建的web应用是目前SQL注入的重灾区。本文虽然是从JAVA的角度来研究SQL注入的问题,但原理上同样适用于其他开发语言,希望读者可以通过此文,触类旁通。


珍爱数据,远离拼接,有输入的地方就会有江湖...




 
推荐文章
卖萌的鸡蛋面  ·  SQL Server 2005 Mirror_ITPUB博客
2 年前
从容的排球  ·  ES6、ES7、ES8、ES9、ES10新特性一览 - 掘金
2 年前
眉毛粗的水桶  ·  可以模拟刷ROM的安卓模拟器_百度知道
2 年前
风度翩翩的钱包  ·  2句代码轻松实现WPF最大化不遮挡任务栏并且具有边框调节效果-阿里云开发者社区
2 年前
今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
删除内容请联系邮箱 2879853325@qq.com
Code - 代码工具平台
© 2024 ~ 沪ICP备11025650号