JAVA安全—SpringBoot框架&MyBatis注入&Thymeleaf模板注入

发布于:2024-12-18 ⋅ 阅读:(8) ⋅ 点赞:(0)

前言

之前我们讲了JAVA的一些组件安全,比如Log4j,fastjson。今天讲一下框架安全,就是这个也是比较常见的SpringBoot框架。

SpringBoot框架

Spring Boot是由Pivotal团队提供的一套开源框架,可以简化spring应用的创建及部署。它提供了丰富的Spring模块化支持,可以帮助开发者更轻松快捷地构建出企业级应用。Spring Boot通过自动配置功能,降低了复杂性,同时支持基于JVM的多种开源框架,可以缩短开发时间,使开发更加简单和高效。

先来了解一下这个框架里面常见的东西

路由映射

@RequestMapping, @GetMapping, 和 @PostMapping 注解用于定义HTTP请求的映射路径。

@RequestMapping 是通用注解,而 @GetMapping 和 @PostMapping 是其简化形式,分别用于处理GET和POST请求。

参数传递

@RequestParam 注解用于从HTTP请求中提取参数,使得控制器方法可以访问并使用这些参数。

数据响应

@RestController 注解用于标识一个类是RESTful风格的控制器,它包含了 @ResponseBody 和 @Controller 的功能。
@ResponseBody 表示方法的返回值将直接作为HTTP响应体返回给客户端。
@Controller 通常用于标识传统的MVC控制器,而 @RestController 更适用于RESTful风格的控制器。

项目构建

新建一个项目。

这个服务器URL是默认从官网获取架构,如果说你觉得网络卡的话,你可以改为https://start.aliyun.com,去从阿里云获取架构。

版本的话目前最新的就是3.4.0了。

如果你前面用的是阿里云的架构网址,那么就会只显示2.x的版本,就是说阿里云认为这几个版本比较稳定,所以只提供这几个。

我这里网速慢,就用阿里云的2.3.16版本,依赖选择Spring Web。

创建成功之后可以看到这个框架自带了很多外部库,什么Log4j啊啥的,就不需要我们自己去下载了,比较方便。

新建一个类叫controller.IndexController。

我们写入以下代码。

package com.sf.maven.springboot.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class IndexController {
    @RequestMapping("/wlw")
    public String index(){
        return "wlw";
    }

}

接着回到Application.java这里运行起来。

此时便可以在控制台这里看到启动了8080端口也就是Tomcat服务,这是它自带的我并没有去配置它。

如果端口被占用的话,你可以在resources目录下的application.properties配置文件进行修改。

访问8080端口,返回的确是我们写入的东西。

我们稍微修改一下,添加POST请求和GET请求。

package com.sf.maven.springboot.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class IndexController {
    @RequestMapping(value = "/wlwget",method = RequestMethod.GET)  //get请求
    public String getmethod(){
        return "wlwget";
    }

    @RequestMapping(value = "/wlwpost",method = RequestMethod.POST) //post请求
    public String postmethod(){
        return "wlwpost";
    }

}

我们运行起来再访问一下,可以看大此时我们再访问wlw的话会报错,这个就是典型的SpringBoot报错页面。

get提交wlwget,则是正常返回。

我们用postman这个工具去请求wlwpost,也是正常返回信息。

现在我们修改代码添加参数来试一下,稍微修改一下代码,传递参数name。

get请求。

post请求。

MyBatis注入

MyBatis是SpringBoot中用的较多的一个数据库驱动,它存在的一个安全问题就是,使用MyBatis的时候遇到了#{}和${}可能导致sql注入的问题。

先创建一个项目重新来吧,命名为MyBatis-demo。

依赖项就选择Spring web,MyBatis Framework,MySQL Driver。

数据库的话我这里是用phpstudy,简单方便,我是在user库里面新建一个user表来进行测试。

在pom文件这里可以看到,外部包都被导入了。

接着再来配置一下数据库连接,把src/main/resources/ 目录下的 application.properties文件改为application.yml

清空里面的内容。写入以下的内容。

spring:
    datasource:
        url: jdbc:mysql://localhost:3306/user
        username: root
        password: 123456
        driver-class-name: com.mysql.cj.jdbc.Driver

新建一个类叫entity.User。

接着我们先写入以下代码,要和数据库的字段对应。

然后右键选择生成,选择Setter和Getter,把显示的三个东西都选上确定即可。

自动生成了方法代码。

同理选择toStron()方法自动生成。

再新建一个类叫mapper.Usermapper。

写入以下的代码,创建sql查询的接口。

package com.sf.maven.mybatisdemo.mapper;


import com.sf.maven.mybatisdemo.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;


import java.util.List;

@Mapper
public interface Usermapper {
    // ${id} 是拼接写法,#{id} 是预编译写法
    @Select("select * from name")//通过ID查询
    public List<User> findAll();

    @Select("select * from name where ID=1")
    public List<User> findID();
}

同理再创建一个constroller类去调用我们的sql查询,新建一个类叫constroller.Getnamecontroller,

这个和上面的那个 web 应用访问一样,就是返回数据为从数据库获取信息。

package com.sf.maven.mybatisdemo.constroller;
import com.sf.maven.mybatisdemo.entity.User;
import com.sf.maven.mybatisdemo.mapper.Usermapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

@RestController
public class Getnamecontroller {
    @Autowired
    private Usermapper Usermapper;

    @GetMapping("/Getpasswd")//定义请求路径
    public List<User> getpasswd(@RequestParam Integer id) {
        List<User> all = Usermapper.findAll();//调用sql查询接口
        return all;
    }

    @GetMapping("/GetID")
    public List<User> getID() {
        List<User> all = Usermapper.findID();
        return all;
    }

}

把搞好的项目运行起来,访问路径可以查看到表的内容,说明是执行了我们设定好的sql语句。

接下来就讲一下产生的安全问题,改一下刚才的代码。

运行起来访问一下,这次要加上参数才可以进行查询。

我们设置的sql语句是 select * from name where id like '%${id}%',此时我们只要把 id=1 的查询改为 id=1%' or 1=1# 即可产生sql注入,这是因为当参数拼接上去之后sql语句就变成这样子了 

select * from name where id like '%1%' or 1=1#' 。

只是不知道为啥我这里会报错,sql语句没问题呀。

我索性去到数据库那里试一下,发现是可以执行没有报错,你妹的。

关于为啥会产生sql注入,可以看一下这篇文章,在Java中呢,sql注入是非常少的,但是不代表没有。

Mybatis 框架下 SQL 注入攻击的 3 种方式,真是防不胜防! - 知乎

【安全】mybatis中#{}和${}导致sql注入问题及解决办法_${}sql注入-CSDN博客

Thymeleaf模板注入

我们在浏览一些网站时,会发现有些网站的页面十分的精美,这是由于网站开发引用了一些模板。而在SpringBoot中,Thymeleaf是个不安全的模版,日常开发中语言切换页面,主题更换等传参导致的 SSTI 注入安全问题。

新建一个项目叫Thymeleaf demo。

依赖项选择Thymeleaf和Spring web。

新建一个类叫controller.thymeleafcontroller。

我们写入个比较简单的代码,什么意思呢,就是访问index,由于我没有使用模板渲染那么就会返回个Hello World。

运行起来访问index,确实返回了Hello World,我这里就比较简陋的测试一下,实际情况中一般都是十分精美的页面。

那么现在我们使用一下模板渲染,在配置文件中可以看到模板的路径为templates/。

我们在resources目录下新建一个templates目录。

写一个index.html文件当作模板。

修改一下调用文件,调用我们的index模板并输出hello wlw。

运行代码访问index,然而却并没有返回hello wlw,而是返回了index。

这是为啥呢,原来是@RestController包含了 @ResponseBody 和 @Controller 的功能。@ResponseBody index当做字符串显示操作,所以我们更换为@Controller 没有ResponseBody index那么就会当做资源文件去渲染。

改了之后再访问返回了hello wlw,说明成功调用了模板。

查看页面源码,发现和我们写的index.html文件差不多。

OK那么我们现在来看一下安全问题,上面我们说过安全问题就是由于模板的调用,我们可以看到当前的lang=ZH_CN就是调用了中文页面的模板。

当我们把lang的值换为en那么就会调用英文的模板,思考一下我们把lang的值换位Java代码是否能实现rce。

注入漏洞存在与3.0.0—3.0.11版本,2.x版本的应该也会存在漏洞,但是我们的这个包是从阿里云拉取的。阿里云的东西一般都比较稳定没啥漏洞,我们替换一下pom文件。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.springframework</groupId>
    <artifactId>java-spring-thymeleaf</artifactId>
    <version>1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <!--latest-->
        <version>2.2.0.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

    </dependencies>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

替换了之后我们可以看到版本变为了2.2.0release。

稍微修改一下调用文件,使其可以传递参数lang。

我们再新建一个index-en.html模板文件,啥也不用写。

运行代码访问啥也没有,因为我们模板啥也没写。

把index-en换成下面的Java代码,成功弹出计算机。

__$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%22calc%22).getInputStream()).next()%7d__::.x

至于poc怎么构造的后面有机会再说了,或者看一下以下文章。

thymeleaf模板注入学习与研究--查找与防御

Thymeleaf模板生成过程以及注入原因分析 - 先知社区

总结

本次从开发的方面讲了两个SpringBoot框架常见的安全问题,感觉有点强度了,哎。

最后,以上仅为个人的拙见,如何有不对的地方,欢迎各位师傅指正与补充,有兴趣的师傅可以一起交流学习。


网站公告

今日签到

点亮在社区的每一天
去签到