网络安全零基础都能看的SQL注入

news2024/11/16 11:43:31

1.1 .Sql 注入攻击原理

SQL 注入漏洞可以说是在企业运营中会遇到的最具破坏性的漏洞之一,它也是目前被利用得最多的漏洞。要学会如何防御 SQL 注入,首先我们要学习它的原理。

针对 SQL 注入的攻击行为可描述为通过在用户可控参数中注入 SQL 语法,破坏原有 SQL 结构,达到编写程序时意料之外结果的攻击行为。其成因可以归结为以下两个原因叠加造成的:

程序编写者在处理应用程序和数据库交互时,使用字符串拼接的方式构造 SQL 语句。未对用户可控参数进行足够的过滤便将参数内容拼接进入到 SQL 语句中。注入攻击的本质,是把用户输入的数据当做代码执行。这里有两个关键条件:用户能够控制输入。原本程序要执行的代码,拼接了用户输入的数据。

1.2 .Sql 审计方法

手动找的话,可以直接找到 sqlmapper.xml 文件或者直接搜索 select、update、delete、insert “String sql=”等关键词,定位 SQL xml 配置文件。

如果 sql 语句中有出现 $ 进行参数拼接,则存在 SQL 注入风险。

当找到某个变量关键词有 SQL 注入风险时,可以再根据调用链找到该存在注入风险的业务逻辑代码,查看参数来源是否安全、是否有配置 SQL 危险参数过滤的过滤器,最终确认是否存在 SQL 注入。以下给出可能造成 sql 注入攻击的关键字,审计时可根据实际情况进项查找

常见 SQL 语句关键词

【一一帮助安全学习,所有资源一一】①网络安全学习路线②20 份渗透测试电子书③安全攻防 357 页笔记④50 份安全攻防面试指南⑤安全红队渗透工具包⑥网络安全必备书籍⑦100 个漏洞实战案例⑧安全大厂内部教程

1.3Sql 注入漏洞危害

1 、 攻击者可以做到

  • 业务运营的所有数据被攻击

  • 对当前数据库用户拥有的所有表数据进行增、删、改、查等操作

  • 若当前数据库用户拥有 file_priv 权限,攻击者可通过植入木马的方式进一步控制 DB 所在服务器

  • 若当前数据库用户为高权限用户,攻击者甚至可以直接执行服务器命令从而通过该漏洞直接威胁整个内网系统

2、可能对业务造成的影响

① 用户信息被篡改

② 攻击者偷取代码和用户数据恶意获取

线上代码被非法篡改,并造成为恶意攻击者输送流量或其他利益的影响

1.4 Sql 注入漏洞代码示例

Java 代码动态构建 SQL

Statement stmt = null;
ResultSet rs = null;
try{
String userName = ctx.getAuthenticatedUserName(); //this is a constant
String sqlString = "SELECT * FROM t_item WHERE owner='" + userName + "' AND itemName='" + request.getParameter("itemName") + "'";
stmt = connection.createStatement();
rs = stmt.executeQuery(sqlString);
// ... result set handling
}
catch (SQLException se){
// ... logging and error handling
}

复制代码

这里将查询字符串常量与用户输入进行拼接来动态构建 SQL 查询命令。仅当 itemName 不包含单引号时,这条查询语句的行为才会是正确的。如果一个攻击者以用户名 wiley 发起一个请求,并使用以下条目名称参数进行查询:

name' OR 'a' = 'a

复制代码

那么这个查询将变成:

SELECT * FROM t_item WHERE owner = 'wiley' AND itemname = 'name' OR 'a'='a';

复制代码

此处,额外的 OR 'a'='a'条件导致整个 WHERE 子句的值总为真。那么,这个查询便等价于如下非常简单的查询:

SELECT * FROM t_item

复制代码

这个简化的查询使得攻击者能够绕过原有的条件限制:这个查询会返回 items 表中所有储存的条目,而不管它们的所有者是谁,而原本应该只返回属于当前已认证用户的条目。

在存储过程中动态构建 SQL

Java 代码:

CallableStatement = null
ResultSet results = null;
try
{
String userName = ctx.getAuthenticatedUserName(); //this is a constant
String itemName = request.getParameter("itemName");
cs = connection.prepareCall("{call sp_queryItem(?,?)}");
cs.setString(1, userName);
cs.setString(2, itemName);
results = cs.executeQuery();
// ... result set handling
}
catch (SQLException se)
{
// ... logging and error handling
}
SQL Server存储过程:
CREATE PROCEDURE sp_queryItem
@userName varchar(50),
@itemName varchar(50)
AS
BEGIN
DECLARE @sql nvarchar(500);
SET @sql = 'SELECT * FROM t_item
WHERE owner = ''' + @userName + '''
AND itemName = ''' + @itemName + '''';
EXEC(@sql);
END
GO

复制代码

在存储过程中,通过拼接参数值来构建查询字符串,和在应用程序代码中拼接参数一样,同样是有 SQL 注入风险的。

Hibernate 动态构建 SQL/HQL

原生 SQL 查询:

String userName = ctx.getAuthenticatedUserName(); //this is a constant
String itemName = request.getParameter("itemName");
Query sqlQuery = session.createSQLQuery("select * from t_item where owner = '" + userName + "' and itemName = '" + itemName + "'");
List<Item> rs = (List<Item>) sqlQuery.list();

复制代码

HQL 查询:

String userName = ctx.getAuthenticatedUserName(); //this is a constant
String itemName = request.getParameter("itemName");
Query hqlQuery = session.createQuery("from Item as item where item.owner = '" + userName + "' and item.itemName = '" + itemName + "'");
List<Item> hrs = (List<Item>) hqlQuery.list();

复制代码

即使是使用 Hibernate,如果在动态构建 SQL/HQL 查询时包含了不可信输入,同样也会面临 SQL/HQL 注入的问题。

HQL 代码中,session.createQuery 使用 HQL 语句将查询到的数据存到到 list 集合中,需要时在拿出来使用。而参数中 itemName 是通过 request.getParameter 直接获取。攻击者若在此处写入恶意语句,程序将恶意语句查询出来的数据存放在 list 集合中,再通过某处调用成功将数据显示在前台。

Mybatis 注入分析

Mybatis 框架下易产生 SQL 注入漏洞的情况主要分为以下三种:

1)模糊查询 like

例如对人员姓名检索进行模糊查询,如果考虑安全编码规范问题,其对应的 SQL 语句如下:

Select * from user where name like '%#{name}%'

复制代码

但由于这样写程序会报错,研发人员将 SQL 查询语句修改如下:

Select * from user where name like '%${name}%'

复制代码

在这种情况下我们发现程序不再报错,但是此时产生了 SQL 语句拼接问题,如果 java 代码层面没有对用户输入的内容做处理势必会产生 SQL 注入漏洞。

2)in 之后的参数

例如对人员姓名进行同条件多值检索的时候,如当用户输入 001,002,003...时,如果考虑安全编码规范问题,其对应的 SQL 语句如下:

Select * from name where id in (#{id})

复制代码

但由于这样写程序会报错,研发人员将 SQL 查询语句修改如下:

Select * from name where id in (${id})

复制代码

修改 SQL 语句之后,程序停止报错,但是却引入了 SQL 语句拼接的问题,如果没有对用户输入的内容做过滤,势必会产生 SQL 注入漏洞。

3)order by 之后(重点和区分点)

当根据姓名、id 序号等信息用户进行排序的时候,如果考虑安全编码规范问题,其对应的 SQL 语句如下:

Select * from user where name = 'qihoo' order by #{id} desc

复制代码

但由于发布时间 id 不是用户输入的参数,无法使用预编译。研发人员将 SQL 查询语句修改如下:

Select * from user where name = 'qihoo' order by ${id} desc

复制代码

修改之后,程序未通过预编译,但是产生了 SQL 语句拼接问题,极有可能引发 SQL 注入漏洞。

1.5 .实战案例-OFCMS SQL 注入漏洞分析

本文中使用 ofcms 进行 SQL 注入漏洞讲解,此 CMS 算是对新手学习代码审计比较友好的 CMS。

上述为安装成功页面,如何安装 CMS 本章不在赘述。

后台页面:http://localhost:8080/ofcms-admin/admin/index.html

漏洞点:

ofcms-admin/src/main/java/com/ofsoft/cms/admin/controller/system/SystemGeneratrController.java
create方法
| 
/**
* 创建表
*/
public void create() {
try {
String sql = getPara("sql");
Db.update(sql);
rendSuccessJson();
} catch (Exception e) {
e.printStackTrace();
rendFailedJson(ErrorCode.get("9999"), e.getMessage());
}
}

复制代码

上述代码中使用 getpara 获取 sql 的参数值,并 update,跟进一下 getpara 和 update 方法。

跳转至 jfinal-3.2.jar/com/jfinal/core/controller.class

public String getPara(String name) {
return this.request.getParameter(name);
}

复制代码

上述代码无特殊用意,就是获取参数值,继续跟进 Db.update 方法。

跳转至 jfinal-3.2.jar/com/jfinal/plugin/activerecord/Db.class

public static int update(String sql) {
return MAIN.update(sql);
}

复制代码

发现调用 MAIN.update , 继续跟进。

跳转至 jfinal-3.2.jar/com/jfinal/plugin/activerecord/DbPro.class

public int update(String sql) {
return this.update(sql, DbKit.NULL_PARA_ARRAY);
}

复制代码

继续跟进到最后,发现华点。

public int update(String sql, Object... paras) {
Connection conn = null;
int var4;
try {
conn = this.config.getConnection();//连接
var4 = this.update(this.config, conn, sql, paras);//调用update更新
} catch (Exception var8) {
throw new ActiveRecordException(var8);
} finally {
this.config.close(conn);
}
return var4;
}

复制代码

重点:Object...

Object 是所有类的基类,而 Object... 是不确定方法参数情况下的一种多态表现形式(可以传递多个参数)。

再继续跟进 update ,同文件代码

int update(Config config, Connection conn, String sql, Object... paras) throws SQLException {
PreparedStatement pst = conn.prepareStatement(sql);
config.dialect.fillStatement(pst, paras);
int result = pst.executeUpdate();
DbKit.close(pst);
return result;
}

复制代码

上述代码执行 SQL 语句,并返回结果。

至此,整个功能流程结束,在我们跟进的过程中,代码中无任何过滤语句,获取参数值,调用 update 方法更新,更新成功后返回结果。

漏洞验证

漏洞点打上断点,网页中输入 poc 进行验证

update of_cms_topic set topic_url=updatexml(1,concat(0x7e,(user())),0) where topic_id = 1

复制代码

根据如上截图可看出我们传入的 SQL 语句是被完整的接收,并未做任何过滤直接带入数据库执行,所以此处直接写入漏洞代码爆出当前数据库账户为 root。

上述为 sqlmap 工具跑出来的注入点。

1.6 漏洞修复方法

添加全局过滤器,过滤特殊字符

SQLFilter.java 中:

PreparedStatement 参数化

如果使用参数化查询,则在 SQL 语句中使用占位符表示需在运行时确定的参数值。参数化查询使得 SQL 查询的语义逻辑被预先定义,而实际的查询参数值则等到程序运行时再确定。参数化查询使得数据库能够区分 SQL 语句中语义逻辑和数据参数,以确保用户输入无法改变预期的 SQL 查询语义逻辑。

在 Java 中,可以使用 java.sql.PreparedStatement 来对数据库发起参数化查询。在这个正确示例中,如果一个攻击者将 itemName 输入为 name' OR 'a' = 'a,这个参数化查询将免受攻击,而是会查找一个 itemName 匹配 name' OR 'a' = 'a 这个字符串的条目。

PreparedStatement stmt = null
ResultSet rs = null
try
{
String userName = ctx.getAuthenticatedUserName(); //this is a constant
String itemName = request.getParameter("itemName");
// ...Ensure that the length of userName and itemName is legitimate
// ...
String sqlString = "SELECT * FROM t_item WHERE owner=? AND itemName=?";
stmt = connection.prepareStatement(sqlString);
stmt.setString(1, userName);
stmt.setString(2, itemName);
rs = stmt.executeQuery();
// ... result set handling
}
catch (SQLException se)
{
// ... logging and error handling
}

复制代码

存储过程参数化

这个存储过程使用参数化查询,而未包含不安全的动态 SQL 构建。数据库编译此存储过程时,会生成一个 SELECT 查询的执行计划,只允许原始的 SQL 语义被执行。任何参数值,即使是被注入的 SQL 语句也不会被执行,因为它们不是执行计划的一部分。

CallableStatement = null
ResultSet results = null;
try
{
String userName = ctx.getAuthenticatedUserName(); //this is a constant
String itemName = request.getParameter("itemName");
// ... Ensure that the length of userName and itemName is legitimate
// ...
cs = connection.prepareCall("{call sp_queryItem(?,?)}");
cs.setString(1, userName);
cs.setString(2, itemName);
results = cs.executeQuery();
// ... result set handling
}
catch (SQLException se)
{
// ... logging and error handling
}

复制代码

Hibernate 参数化查询

Hibernate 支持 SQL/HQL 参数化查询。为了防止 SQL 注入以及改善性能,以上这些示例使用了参数化绑定 的方式来设置查询参数。

String userName = ctx.getAuthenticatedUserName(); //this is a constant
String itemName = request.getParameter("itemName");
Query hqlQuery = session.createQuery("from Item as item where item.owner = ? and item.itemName = ?");
hqlQuery.setString(1, userName);
hqlQuery.setString(2, itemName);
List<Item> rs = (List<Item>) hqlQuery.list();

复制代码

HQL 基于名称的参数化查询

String userName = ctx.getAuthenticatedUserName(); //this is a constant
String itemName = request.getParameter("itemName");
Query hqlQuery = session.createQuery("from Item as item where item.owner = :owner and item.itemName = :itemName");
hqlQuery.setString("owner", userName);
hqlQuery.setString("itemName", itemName);
List<Item> rs = (List<Item>) hqlQuery.list();

复制代码

原生参数化查询

String userName = ctx.getAuthenticatedUserName(); //this is a constant
String itemName = request.getParameter("itemName");
Query sqlQuery = session.createSQLQuery("select * from t_item where owner = ? and itemName = ?");
sqlQuery.setString(0, owner);
sqlQuery.setString(1, itemName);
List<Item> rs = (List<Item>) sqlQuery.list();

复制代码

MyBatis 框架的修复方案

尽量使用 #描述参数,如果一定要使用 $,则需要自己过滤用户输入

模糊查询 like SQL 注入修复建议

按照新闻标题对新闻进行模糊查询,可将 SQL 查询语句设计如下:

select * from news where name like concat(‘%’,#{name }, ‘%’)

复制代码

采用预编译机制,避免了 SQL 语句拼接的问题,从根源上防止了 SQL 注入漏洞的产生。

in 之后的参数 SQL 注入修复建议

在对新闻进行同条件多值查询的时候,可使用 Mybatis 自带循环指令解决 SQL 语句动态拼接的问题:

select * from news where id in<foreach collection="ids" item="item" open="("separator="," close=")">#{item} </foreach>

复制代码

order by SQL 注入修复建议

在 Java 层面做映射预编译机制只能处理查询参数,其他地方还需要研发人员根据具体情况来解决。如前面提到的排序情景:

Select * from news where title =‘淘宝’ order by #{time} asc,

复制代码

这里 time 不是查询参数,无法使用预编译机制,只能这样拼接:

Select * from news where title =‘淘宝’ order by ${time} asc

复制代码

针对这种情况研发人员可以在 java 层面做映射来进行解决。如当存在发布时间 time 和点击量 click 两种排序选择时,我们可以限制用户只能输入 1 和 2。

当用户输入 1 时,我们在代码层面将其映射为 time,当用户输入 2 时,将其映射为 click。而当用户输入 1 和 2 之外的其他内容时,我们可以将其转换为默认排序选择 time(或者 click)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/642539.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

高压脉冲电源和高压放大器应用领域的区别

在之前的科普中我们讲解了高压脉冲电源和高压放大器的定义及二者区别&#xff0c;其实除此之外&#xff0c;它们在应用上也是有不同倾向性的&#xff0c;那么今天让安泰测试Agitek为大家分享高压脉冲电源和高压放大器应用领域究竟有什么不同&#xff1f; 高压脉冲电源的应用领…

躺不平摆不烂的测试员如何自救?

随着测试从业年龄的增加&#xff0c;毕业的概率大增&#xff0c;而机会骤减&#xff0c;从而使测试员陷入躺不平、摆不烂的状态。 相较于开发员&#xff0c;测试员是没有资格躺平的&#xff0c;毕竟测试员没可能从短短几年黄金时间&#xff0c;从工作中积累到足以躺平的财富&a…

wordpress去除分类URL的categpory

前言 在日常使用Wordpress搭建网站时&#xff0c;发现文章或者分类页的URL地址中默认带有Category&#xff0c;URL层级过长会影响我们网站SEO的优化&#xff0c;也不利于用户体验。这里讲一下如何去除URL中categpory的方法。 操作 第一步先登录到WordPress后台&#xff0c;然…

前端样式网站(前端css框架)

1. Bootstrap:Bootstrap The most popular HTML, CSS, and JS library in the world.Bootstrap 是最流行的 CSS 框架,提供了丰富的前端样式和组件,非常适合开发响应式网站和应用程序。 2. Bulma:Bulma: Free, open source, and modern CSS framework based on FlexboxBulma 是…

nodejs 版本切换(windows版)

一、按健winR弹出窗口&#xff0c;键盘输入cmd,然后敲回车。然后进入命令控制行窗口&#xff0c;并输入where node查看之前本地安装的node的路径。 二、找到上面找到的路径&#xff0c;将node.exe所在的父目录里面的所有东西都删除。 三、从官网下载安装包 https://github.com/…

一文看懂!shell编程-【提取IP地址、文件归档、发送消息】

【引言】 您是否曾经遇到过需要提取大量IP地址、归档文件、发送消息等烦琐的工作&#xff1f; 如果是&#xff0c;那么您一定不能错过这篇文章&#xff01; 在本文中&#xff0c;我们将探讨Shell编程的各种技巧和方法&#xff0c;帮助您轻松完成这些任务。无需任何编程基础&…

这些常用的IC专业术语,你了解多少?

IC工程师在日常的学习和工作中或多或少会都遇到一些专业的IC词汇。下面就来为大家盘点一下各个岗位的专业高频名词。&#xff08;文档内持续更新&#xff0c;全文档文末可领&#xff09; 数字功能验证高频名词 CIN (Carry INput)&#xff1a;进位输入 COUT(Carry OUTput)&…

关于数据库分库分表的一点想法

1 开篇 面对数据的激增&#xff0c;相信大家也都有分库分表的一些方案&#xff0c;这次的这个分享&#xff0c;算是自己的一个想法&#xff0c;可以当做一个参考方案&#xff0c;也欢迎相互讨论。 话不多说&#xff0c;直接进入主题。 日常开发中&#xff0c;实现数据库的分库…

系统稳定性与高可用保障

一、前言 高并发、高可用、高性能被称为互联网三高架构&#xff0c;这三者都是工程师和架构师在系统架构设计中必须考虑的因素之一。今天我们就来聊一聊三 H 中的高可用&#xff0c;也是我们常说的系统稳定性。 > 本篇文章只聊思路&#xff0c;没有太多的深入细节。阅读全…

“海底长城”合龙!揭秘深中海底隧道中的无损检测技术

作为工业大国&#xff0c;近年来国家在各类“大国工程”中投入巨大&#xff0c;同时也获得了喜人的成果&#xff0c;从长江三峡水利枢纽造福全国人民&#xff0c;到天问落火、空间站核心舱在轨开工&#xff0c;天舟二号货运飞船稳靠太空港&#xff0c;神舟十二号载人飞船成功发…

博睿数据应邀出席第五届双态IT北京用户大会,分享《如何帮助用户构建高级可观测性》

6月10日&#xff0c;第五届双态IT北京用户大会在北京召开&#xff0c;来自IT行业的各位专家齐聚一堂&#xff0c;分享行业理念、发展趋势、运维方法以及最佳实践。 博睿数据应邀出席大会&#xff0c;作《如何帮助用户构建高级可观测性》主题演讲&#xff0c;从云原生带来的挑战…

vue-cli3搭建项目实现移动端自适应----- flexible和 postcss-px2rem

1、安装 flexible和 postcss-px2rem npm i lib-flexible postcss-px2rem --save 2.在项目入口文件main.js 中引入lib-flexible import lib-flexible 3. 把目录 public/index.html 中的这个标签注释&#xff01;由于flexible会动态给页面header中添加标签 4.配置postcss-px2r…

不一样的ECS U实例

不一样的ECS U实例 ECS U实例U实例入门开通U实例服务远程连接U实例重置密码远程连接 安装Mysql安装Mysql并启动Mysql数据库操作本地远程连接Mysql 安装Nginx安装Nginx启动Nginx 安装JDK安装Tomcat 体验感受操作上适用场景上体验建议 参与ECSU实例评测&#xff0c;申请免费体验机…

操作系统原理 —— 文件的逻辑结构(二十三)

文件的逻辑结构 这里说的逻辑结构&#xff0c;就是指在用户看来&#xff0c;文件内部的数据应该是如何组织起来的&#xff0c;而 物理结构 指的是在操作系统看来&#xff0c;文件的数据是如何被存放的。 从逻辑结构结构来看&#xff0c;我们可以打开一个记事本&#xff0c;里…

渲染案例 | 《妈妈的牵牛花》荣获厦门国际动漫节金奖

2023年5月25日&#xff0c;第十五届厦门国际动漫节“金海豚奖”动画组获奖名单公布。其中&#xff0c;蓝海创意云《青团计划》优秀代表作品——《妈妈的牵牛花》荣获最佳学生动画金奖。 蓝海创意云作为行业内知名的影视动画渲染服务商&#xff0c;深度参与《妈妈的牵牛花》的后…

NAS文件管理拷贝速度很慢?大文件还是得用它!

有时候我们上传文件&#xff0c;个位数的传输速度实在让我们抓耳挠腮&#xff0c;不禁疑惑&#xff0c;有什么办法可以快速地传输文件呢&#xff1f; 就拿铁威马来说吧&#xff0c;铁威马的TOS 桌面上的 “文件管理” 是一款基于浏览器的网页版文件管理工具&#xff0c;该工具…

pytorch低版本找到并安装torch_geometric对应版本

一、找到官网的安装命令 不同版本的torch_geometric 对应的安装命令不完全一致&#xff0c;因此我们需要首先找到所需torch_geometric版本的正确安装命令。然后再去找对应的版本。 目前torch_geometric官网上只有pytorch 2.0.* 和1.13.* 版本的 torch_geometric 版本对应关系…

聊一聊性能测试

提到性能测试&#xff0c;很多从业相关人员可能会感觉比较混淆。 性能测试&#xff0c;它是属于测试领域一个专业细分领域&#xff0c;和软件测试一样&#xff0c;性能测试涉及到的范围和所需要的技能是非常广而精的&#xff0c;如果从大的类型来划分的话性能测试可以被分为&a…

Mac本地部署蘑菇个人博客详解

文章目录 一、安装Docker、Docker Compose1、系统要求2、安装Docker3、Docker-Compose 二、docker一键部署博客1、创建网络2、修改前端配置1&#xff09;自动修改前端配置2&#xff09;手动修改前端配置 3、开始部署 三、系统测试1、Nacos测试2、swagger测试3、前端页面4、后端…

Python datetime

datetime的作用 Python datetime的模块&#xff0c;用于处理日期和时间 datetime 官网 datetime模块的类如下 datetime 使用的时候需要引入datetime import datetime 下面说下其中的2个datetime 和 date date 类 import datetime # 获取当前日期 t1 datetime.date.today…