JAVA代码审计之SQL注入,基于Spring boot和jdbc以及mybatis

SpringBoot安全漏洞SQL注入和XSS攻击简介说明 阅读详情

目录

一、新建一个spring boot的有sql环境的工程

二、JDBC的SQL注入

2.1 java.sql.Statement

2.2 示例代码

 2.3  预编译防御以及非正确使用

2.4 order by注入

三、Mybatis的SQL注入

3.1 示例代码

3.2 orderby 注入

 3.3 in注入

 3.4 like注入

 四、SQL注入漏洞修复

4.1 白名单

4.2 预编译(jdbc)

4.3 预编译(mabatis)

本节讲述JavaWeb代码审计中存在SQL注入漏洞的情况。

基于spring boot,mysql,两种连接方式:jdbc和mybatis。

代码比较多,适合自己创建项目,跟着走一遍,如果只想了解原理,可以忽略代码,只看大概即可。比如Controller类或者sql语句的编写。

SQL注入漏洞是对数据库进行的一种攻击方式。 其主要形成方式是在数据交互中,前端数据通过后台在对数据库进行操作时,由于没有做好安全防护,导致攻击者将恶意代码拼接到请求参数中,被当做SQL语句的一部分进行执行,最终导致数据库被攻 击。 可以说所有可以涉及到数据库增删改查的系统功能点都有可能存在SQL注入漏洞。 虽然现在针对SQL注入的防护层出不穷,但大多情况下由于开发人员的疏忽或特定的使用场景,还是会存在SQL注入漏洞的代码。

一、新建一个spring boot的有sql环境的工程

选择这四个依赖进入

 数据库创建好  加点数据,我用的phpstudy,mysql。

 项目结构如下

 打开 src/main/resources/application.properties 配置文件,将以下数据库连接信息添加至配置中


#访问端口号
server.port=7089
#数据库连接信息
spring.datasource.url=jdbc:mysql://localhost:3306/jdbcdemo?AllowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

二、JDBC的SQL注入

动态拼接

SQL语句动态拼接导致的SQL注入漏洞是先前最为常见的场景。 其主要原因是后端代码将前端获取的参数动态直接拼接到SQL语句中使用 java.sql.Statement 执行 SQL语句从而导致SQL注入漏洞的出现。 

在这里关键点有两个:①、动态拼接参数。②、使用 java.sql.Statement 执行SQL语句。

2.1 java.sql.Statement

Statement 对象用于执行一条静态的 SQL 语句并获取它的结果。 createStatement() :创建一个 Statement 对象,之后可使用 executeQuery() 方法执行SQL语句。 executeQuery(String sql) 方法:执行指定的 SQL 语句,返回单个 ResultSet 对象。

2.2 示例代码

在 src\main\java\com\example\demo\jdbcinjection 下新建一个名为 JdbcDynamicController 的 Java Class。

package com.example.sqlinjection.jdbcinjection;


import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.sql.*;

@RestController
@RequestMapping("/jdbcsql")
public class JdbcDynamicController {
    private static String driver = "com.mysql.cj.jdbc.Driver";
    @Value("${spring.datasource.url}")
    private String url;
    @Value("${spring.datasource.username}")
    private String user;
    @Value("${spring.datasource.password}")
    private String password;

    @RequestMapping("/dynamic")
    public String jdbcdynamic(@RequestParam("id") String id) throws ClassNotFoundException, SQLException {
        StringBuilder result = new StringBuilder();
        Class.forName(driver);
        Connection conn = DriverManager.getConnection(url, user, password);
        Statement statement = conn.createStatement();
        String sql = "select * from user where id = '" + id + "'";
        ResultSet rs = statement.executeQuery(sql);
        while (rs.next()) {
            String rsUsername = rs.getString("username");
            String rsPassword = rs.getString("password");
            String info = String.format("%s: %s\n", rsUsername, rsPassword);
            result.append(info);
        }
        rs.close();
        conn.close();
        return result.toString();



    }
}

解释一下,StringBuilder是一个类,可以追加字符串,用于字符串拼接。

单引号闭合的sql语句。

使用闭合1' or 1=1%23,直接爆出了所有数据,可以看到是有sql注入的 。

 执行sql语句也是没问题的

 2.3  预编译防御以及非正确使用

在动态拼接中是使用Statement执行SQL语句。如果使用 PreparedStatement 预编译参数化查询是能够 有效防止SQL注入的。 但如果没有正确的使用 PreparedStatement 预编译还是会存在SQL注入风险的。

PreparedStatement是继承Statement的子接口。 PreparedStatement 会对SQL语句进行预编译,不论输入什么,经过预编译后全都以字符串来执行SQL 语句。 PreparedStatement会先使用 ? 作为占位符将SQL语句进行预编译,确定语句结构,再传入参数进行执 行查询。如下述代码:

String sql = "select * from users where username = ?";
PreparedStatement preparestatement = conn.prepareStatement(sql);
preparestatement.setString(1, username);

但如果没有正确的使用 PreparedStatement 预编译还是会存在SQL注入风险的。 简单来说,可能由于开发人员疏忽或经验不足等原因,虽然使用了预编译 PreparedStatement ,但没 有根据标准流程对参数进行标记,依旧使用了动态拼接SQL语句的方式,进而造成SQL注入漏洞。 在 src\main\java\com\example\demo\jdbcinjection 下新建一个名为 JdbcPrepareStatement 的 Java Class,并键入以下代码。

package com.example.sqlinjection.jdbcinjection;


import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.sql.*;

@RestController
@RequestMapping("/jdbcsql")
public class JdbcPrepareStatement {
    private static String driver = "com.mysql.cj.jdbc.Driver";
    @Value("${spring.datasource.url}")
    private String url;
    @Value("${spring.datasource.username}")
    private String user;
    @Value("${spring.datasource.password}")
    private String password;

    @RequestMapping("/preSec")
    public String jdbcPreSec(@RequestParam("id") String id) throws ClassNotFoundException, SQLException {
        StringBuilder result = new StringBuilder();
        Class.forName(driver);
        Connection conn = DriverManager.getConnection(url, user, password);
        String sql = "select * from user where id=?";
        PreparedStatement preparedStatement = conn.prepareStatement(sql);
        preparedStatement.setString(1,id);

        ResultSet rs = preparedStatement.executeQuery();
        while (rs.next()) {
            String resUsername = rs.getString("username");
            String resPassword = rs.getString("password");
            String info = String.format("%s: %s\n", resUsername, resPassword);
            result.append(info);
        }
        rs.close();
        conn.close();
        return result.toString();
    }

    @RequestMapping("preNot")
    public String jdbcPreNot(@RequestParam("id") String id) throws SQLException, ClassNotFoundException {
        StringBuilder result = new StringBuilder();
        Class.forName(driver);
        Connection conn = DriverManager.getConnection(url, user, password);
        //还是直接进行了拼接 无效
        String sql = "select * from user where id = '" + id + "'";
        PreparedStatement preparestatement = conn.prepareStatement(sql);
        ResultSet rs = preparestatement.executeQuery();
        while (rs.next()) {
            String reUsername = rs.getString("username");
            String resPassword = rs.getString("password");
            String info = String.format("%s: %s\n", reUsername, resPassword);
            result.append(info);
        }
        rs.close();
        conn.close();
        return result.toString();

    }

}

正确的预编译代码效果:

 错误的预编译代码效果:

2.4 order by注入

在SQL语句中, order by 语句用于对结果集进行排序。 order by 语句后面需要是字段名或者字段位 置。 在使用 PreparedStatement 预编译时,会将传递任意参数使用单引号包裹进而变为了字符串。 如果使用预编译方式执行 order by 语句,设置的字段名会被人为是字符串,而不再是字段名。 因此,在使用 order by 时,就不能使用 PreparedStatement 预编译了

下新建一个名为 jdbcOrderby 的Java Class, 并键入以下代码

package com.example.sqlinjection.jdbcinjection;


import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.sql.*;

@RestController
@RequestMapping("/jdbcsql")
public class jdbcOrderby {
    private static String driver = "com.mysql.jdbc.Driver";
    @Value("${spring.datasource.url}")
    private String url;
    @Value("${spring.datasource.username}")
    private String user;
    @Value("${spring.datasource.password}")
    private String password;
    @RequestMapping("/PreOrderby")
    public String jdbcOrderby(@RequestParam("id") String id) throws
            ClassNotFoundException, SQLException {
        StringBuilder result = new StringBuilder();
        Class.forName(driver);
        Connection conn = DriverManager.getConnection(url, user, password);
        String sql = "select * from user" + " order by " + id;
        PreparedStatement preparestatement = conn.prepareStatement(sql);
        ResultSet rs = preparestatement.executeQuery();
        while (rs.next()) {
            String reUsername = rs.getString("username");
            String resPassword = rs.getString("password");
            String info = String.format("%s: %s\n", reUsername, resPassword);
            result.append(info);
        }
        rs.close();
        conn.close();
        return result.toString();
    }
}

利用报错函数,页面并没有返回值,但是在后端可以看到 

可以结合if进行盲注

 

也可以直接尝试用sqlmap跑一下,这里就不再多说了。

三、Mybatis的SQL注入

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎 所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映 射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

在Mybatis中拼接SQL语句有两种方式:一种是占位符 #{} ,另一种是拼接符 ${} 。

 占位符 #{} :对传入的参数进行预编译转义处理。类似JDBC中的 PreparedStatement 。 

拼接符 ${} :对传入的参数不做处理,直接拼接,进而会造成SQL注入漏洞。

 #{} 可以有效防止SQL注入漏洞。 ${} 则无法防止SQL注入漏洞。 因此在我们对JavaWeb整合Mybatis系统进行代码审计时,应着重审计SQL语句拼接的地方。 除非开发人员的粗心对拼接语句使用了 ${} 方式造成的SQL注入漏洞。 

在Mybatis中有几种场景是不能使用预编译方式的,比如: order by 、 in , like 。

3.1 示例代码

代码较多。

 在 src.main.java.com.example.demo.mybatisinjection 包下新建一个Java Class,名为 User ,这是一个实体类,和数据表做下映射,键入以下代码

package com.example.sqlinjection.mybatisinjection;

public class User {
    private int id;
    private String username;
    private String password;

    public int getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
    @Override
    public String toString() {
        return "User [id=" + id + ", username=" + username + ", password=" +
                password + "]";
    }
}

在 src.main.java.com.example.demo.mybatisinjection 文件下新建一个名为 UserMapper 的 Java Interface,键入以下代码

package com.example.sqlinjection.mybatisinjection;


import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

@Mapper
public interface UserMapper {
    List<User> orderbyInjection(@RequestParam("sort") String sort);
    @Select("select * from user where id in (${params})")
    List<User> inInjection(@Param("params")String params);
    List<User> likeInjection(@Param("username") String username);
//Mybatis查询SQL语句的另一种使用注解方式,这也是存在SQL注入的。
//@Select("select * from users where username = '${username}'")
//List<User> likeInjection(@Param("username") String username);

}

在 src.main.resources 文件下先新建名为 mapper 的文件夹,再新建一个名为 UserMapper.xml 文件,与dao层的 UserMapper 做好映射绑定,键入以下代码

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.sqlinjection.mybatisinjection.UserMapper">
<resultMap type="com.example.sqlinjection.mybatisinjection.User" id="User">
<id column="id" property="id" javaType="java.lang.Integer" jdbcType="NUMERIC"/>
<id column="username" property="username" javaType="java.lang.String" jdbcType="VARCHAR"/>
<id column="password" property="password" javaType="java.lang.String" jdbcType="VARCHAR"/>
</resultMap>
<select id="orderbyInjection" parameterType="String" resultMap="User">
select * from user order by ${sort} asc
</select>
<select id="likeInjection" parameterType="String" resultMap="User">
select * from user where username like '%${username}%'
</select>
</mapper>

在 src.main.java.com.example.demo.mybatisinjection 文件下新建一个名为 MybatisController 的Java class,键入以下代码

package com.example.sqlinjection.mybatisinjection;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/mybatisSql")
public class MybatisController {
    @Autowired
    private UserMapper userMapper;
    //orderby查询 http://localhost:7089/sqli/mybatis/orderby?sort=username
    @GetMapping("/orderby")
    public List<User> orderbySql(@RequestParam("sort") String sort) {

        return userMapper.orderbyInjection(sort);
    }
    //in查询 http://localhost:7089/sqli/mybatis/in?params=1
    @GetMapping("/in")
    public List<User> inSql(@RequestParam("params") String params) {
        return userMapper.inInjection(params);
    }
    //Like查询 http://localhost:7089/sqli/mybatis/like?username=admin
    @GetMapping("/like")
    @ResponseBody
    public List<User> likeSql(@RequestParam("username") String username){
        return userMapper.likeInjection(username);
    }
}

最后,在 src\main\resources\application.properties 配置文件中添加以下代码,最终如下 图所示


#?????
server.port=7089
#???????
spring.datasource.url=jdbc:mysql://localhost:3306/jdbcdemo?AllowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
## Mybatis ??
## mybatis.typeAliasesPackage ???com.example.demo.dao??????????
mybatis.typeAliasesPackage=com.example.sqlinjection.mybatisinjection
## mybatis.mapperLocations ??? classpath ??? mapper ???* ??????? xml???
mybatis.mapperLocations=classpath:mapper/*.xml


3.2 orderby 注入

可以看到有明显的sleep现象,sql语句被执行,可以尝试盲注.

 3.3 in注入

IN语句 :常用于where表达式中,其作用是查询某个范围内的数据。

比如: select * from where field in (value1,value2,value3,…); 如上所示,in在查询某个范围数据是会用到多个参数,在Mybtis中如果直接使用占位符 #{} 进行查询会 将这些参数看做一个整体,查询会报错。

因此很多开发人员可能会使用拼接符 ${} 对参数进行查询,从而造成了SQL注入漏洞。

比如: select * from users where id in (${params})

正确的做法是需要使用foreach配合占位符 #{} 实现IN查询。比如:

<!-- where in 查询场景 -->
<select id="select" parameterType="java.util.List" resultMap="BaseResultMap">
SELECT *
FROM user
WHERE name IN
<foreach collection="names" item="name" open="(" close=")" separator=",">
#{name}
</foreach>
</select>

 3.4 like注入

使用like语句进行查询时如果使用占位符 #{} 查询时程序会报错(大家可自行调试)。

比如: select * from users where username like '%#{username}%' 因此经验不足的开发人员可能会使用拼接符 ${} 对参数进行查询,从而造成了SQL注入漏洞。 比如: select * from users where username like '%${username}%' 下面代码是正确的做法,可以防止SQL注入漏洞,如下。

SELECT * FROM users WHERE name like CONCAT("%", #{name}, "%")

 四、SQL注入漏洞修复

php的sql注入漏洞修复也可以用在这里,经常用到正则匹配过滤危险输入。java的话这里主要是说关于预编译的修复。

通过上面我们其实知道,一般情况,预编译是可以解决所有输入的。因为一般情况,所有输入都会被当成字符串。但是在面对oeder by等查询时,预编译就没用了,原因是:order by后一般是接字段名,而字段名是不能带引号的,比如 order by username;如果带上引号成了order by 'username',那username就是一个字符串不是字段名了,这就产生了语法错误。预编译只有自动加引号的setString()方法,没有不加引号的方法;而另一方面order by后接的字段名不能有引号。

事实上,凡是字符串但又不能加引号的位置都不能参数化;包括sql关键字、库名表名字段名函数名等等。

不能参数化的位置,不管怎么拼接,最终都是和使用“+”号拼接字符串的功效一样:拼成了sql语句但没有防sql注入的效果。但好在的一点是,不管是sql关键字,还是库名表名字段名函数名对于后台开发者来说他的集合都是有限的,更准确点应该说也就那么几个。所以考虑可以使用黑白名单等加以限制。

4.1 白名单

正则过滤就不多说了,可以自己编写过滤特定关键字和函数名。

// 插入数据用户可控时,应使用白名单处理
// example for order by

String orderBy = "{user input}";
String orderByField;
switch (orderBy) {
    case "name":
        orderByField = "name";break;
    case "age":
        orderByField = "age"; break;
    default:
        orderByField = "id";
}

这里对列名进行白名单处理,所有的列名都在上面,但凡输入不是白名单的都会被赋值成id。

4.2 预编译(jdbc)

一般情况就预编译,正常写。特殊场景如下。

// like 模糊查询场景
String sql = "SELECT * FROM users WHERE name like ?";
PreparedStatement pre = conn.prepareStatement(sql);
pre.setString(1, "%"+name+"%");
ResultSet rs = pre.executeQuery();

// where in 查询场景
String sql = "select * from user where id in (";
Integer[] ids = new Integer[]{1,2,3};

StringBuilder placeholderSql = new StringBuilder(sql);
for(int i=0,size=ids.length;i<size;i++) {
    placeholderSql.append("?");
    if (i != size-1) {
        placeholderSql.append(",");
    }
}
placeholderSql.append(")");

PreparedStatement pre = conn.prepareStatement(placeholderSql.toString());
for(int i=0,size=ids.length;i<size;i++) {
    pre.setInt(i+1, ids[i]);
}
ResultSet rs = pre.executeQuery();

4.3 预编译(mabatis)

<!-- like 查询场景 -->
<select id="select" parameterType="java.lang.String" resultMap="BaseResultMap">
    SELECT *
    FROM user
    WHERE name like CONCAT("%", #{name}, "%")
</select>

<!-- where in 查询场景 -->
<select id="select" parameterType="java.util.List" resultMap="BaseResultMap">
    SELECT *
    FROM user
    WHERE name IN
    <foreach collection="names" item="name" open="(" close=")" separator=",">
      #{name}
    </foreach>
</select>
MyBatis核心原理与Spring Boot集成实战:从SQL映射到动态查询 在Java后端开发中,数据持久化是构建稳定应用的核心基础。从最基础的JDBC手动处理连接与结果集,到ORM框架对对象关系映射的抽象,开发者始终在追求效率与灵活性的平衡。MyBatis作为一种半自动化的持久层框架,其核心价值在于将SQL的控制权交还给开发者,同时通过参数映射、结果集映射等机制大幅简化了数据库操作。它通过XML或注解配置实现SQL与Java代码的解耦,支持动态SQL构建,并能与Spring生态无缝集成,极大地提升了工程实践中的开发效率和代码可维护性。这种设计使其特别适用于对SQL优化有较高要求、 阅读详情

相关推荐

MyBatis核心原理与Spring Boot集成实战:从SQL映射到动态SQL

在Java后端开发中,数据持久化是构建稳定应用的核心基础。从基础的JDBC到全自动ORM框架,技术演进始终围绕如何平衡开发效率与执行控制力。MyBatis作为一款半自动的持久层框架,其核心原理在于将SQL控制权交还开发者,同时通过智能的结果集映射消除JDBC的模板代码。这一设计带来了显著的技术价值:开发者可以编写和优化原生SQL,充分利用数据库特性,并借助动态SQL能力安全、灵活地构建复杂查询条件。在互联网、金融等对数据库性能有严苛要求的应用场景中,这种“SQL-Mapping”模式成为事实标准。本文通过S

weixin_30781433的博客 479

Spring Boot 中的 SQL 注入攻击是什么,原理,如何预防

SQL 注入攻击是一种常见的网络安全问题,可以通过注入恶意的 SQL 代码来获取或篡改数据库中的数据。在 Spring Boot 中,由于使用了 ORM 框架,开发人员往往会忽略 SQL 注入攻击的风险。为了防止 SQL 注入攻击,开发人员可以采取参数化查询、输入验证和过滤、使用安全的 ORM 框架、使用安全的数据库配置以及记录日志并监控异常等措施。

it_xushixiong的博客 3139

吃透MyBatis底层原理:从JDBC封装到Spring Boot整合实战

MyBatis本质是对JDBC使用模式的标准化封装,其核心在于将SQL执行抽象为SqlSession工作单元、Mapper动态代理与配置驱动的执行链路。理解其原理需回归JDBC原始痛点——参数绑定脆弱、结果映射冗余、资源管理易错,进而掌握SqlSession生命周期、Executor执行器机制及XML与注解双轨制的工程权衡。技术价值体现在提升SQL可治理性、支持插件化横切(如分页/日志)、实现线程安全的数据库会话隔离;典型应用场景包括Spring Boot中多数据源路由、二级缓存集成Redis、动态SQL精

weixin_30437847的博客 399

springboot项目防止XSS攻击和sql注入

springboot项目防止XSS攻击和sql注入

yy1209357299的博客 3873

SpringBoot防止SQL注入最佳实践:从基础到高级全面指南

SpringBoot防护SQL注入全指南:从基础到高级实践 摘要:本文系统介绍了SpringBoot中防御SQL注入的完整方案。首先解析SQL注入原理及危害,包括数据泄露、篡改等风险。核心防护措施包括:使用预编译语句、正确应用JdbcTemplate和ORM框架(JPA/Hibernate/MyBatis)的参数化查询。高级防护技术涵盖输入验证、存储过程调用和最小权限原则。文章还提供了SQL防火墙集成和数据脱敏等进阶方案,通过详实的代码示例和对比表格,帮助开发者构建多层次的SQL注入防护体系。特别强调防御深

本博客聚焦 YOLOv11 全流程落地,涵盖架构优化、数据集处理、训练技巧与多场景部署,兼及国产数据库、Java 开发与 AI 模型应用,内容兼顾理论与工程实践,为开发者提供系统干货,助力高效提升技术能力。 1543

【Java代码审计】SQL注入篇

SQL 注入(SQL Injection)是因为程序未能正确对用户的输入进行检查,将用户的输入以拼接的方式带入 SQL 语句中,导致了 SQL 注入的产生。黑客通过 SQL 注入可直接窃取数据库信息,造成信息泄露输入用户可控直接或间接拼入 SQL语句执行因 SQL 注入漏洞特征性较强,在实际的审计过程中我们往往可以通过一些自动化审计工具快速地发现这些可能存在安全问题的代码片,如使用奇安信代码卫士、Fortify 等自动化工具。

大河之犬的博客 3166

WebGoat实战:Java代码审计中的SQL注入原理与修复指南

SQL注入是Web安全领域最常见的高危漏洞之一,也是Java后端面试和代码审计中的高频考点。其本质是程序在拼接SQL语句时,将用户输入误当作可执行的代码,从而改变了查询语义。在Java技术栈中,JDBC字符串拼接、MyBatis的${}占位符以及JPA原生SQL都是典型的风险点。理解预编译机制(如PreparedStatement和#{})的工作原理,是防御和修复的关键。对于安全测试人员和Java开发者而言,在真实的业务代码中识别并修复这类漏洞,比单纯记忆攻击Payload更有价值。OWASP出品的WebG

weixin_29327525的博客 147

android usb读写,安卓(Android)下如何开发USB NFC读写器app

对安卓工程师来说,在安卓下使用USB设备需要了解很多硬件的内容,这可能会导致工程周期的延长或者app的不稳定。为了将这种风险降到最低,友我科技发布了NFC读写器在安卓下的sdk,使用NFC读写器的类接口,安卓工程师就可以直接调用NFC读写器了,简单可靠。NFC读写器的安卓库文件为:yoworfidreader.jar在ADT工程中导入yoworfidreader.jar库文件,即可在工程中引用NF...

weixin_36433781的博客 823

java常见漏洞的代码审计

本文分析了Java应用中常见的几种安全漏洞及防御方法:1. SQL注入漏洞:重点分析了JDBC中Statement和PrepareStatement的区别,指出直接拼接SQL会导致注入风险,应使用参数化查询;MyBatis框架中动态SQL拼接也存在类似问题。2. XSS漏洞:直接展示用户可控数据会导致跨站脚本攻击,建议进行HTML转义或设置HTTPONLY。3. 命令注入漏洞:详细分析了ProcessBuilder和Runtime.exec()的执行机制,指出不当使用会导致系统命令执行风险。4. SSRF漏

miaositekali的博客 1049

抖音a_bogus参数逆向避坑指南:从环境检测到XHR请求的全流程解析

本文详细解析了抖音a_bogus参数在v1.0.1.19版本下的逆向工程全流程,重点介绍了如何通过PyV8Env框架进行有效的补环境操作,以绕过严格的环境检测。内容涵盖从环境初始化、关键事件触发到模拟XHR请求获取签名的完整步骤,并提供了可运行的Python代码示例和常见检测点的避坑指南,帮助开发者稳定生成有效的a_bogus参数。

tech5的博客 600

Python+Selenium实现抖音博主批量监控:300+账号实时更新通知(附完整代码)

本文详细介绍了如何使用Python和Selenium构建一个高可用的抖音博主批量监控系统。通过架构设计、Cookie管理、高效轮询与差异检测等核心模块,实现300+账号的实时更新追踪与通知。文章提供了完整的代码实现,并重点探讨了性能优化、异常处理及服务器部署等实战经验,帮助开发者打造稳定、可控的自动化监控解决方案。

weixin_29274969的博客 193

新人一看就懂:Spring Boot+Spring mvc+Mybatis的基础框架demo

Spring Boot的设计目的是来简化新Spring应用的初始搭建以及开发过程,大大减少了代码量,通过这篇文章你可以清楚的看到。这是一个基于Spring Boot的简单demo,希望读者可以通过这篇文章大概能看懂这一个简单的框架搭建。后续我会陆续更新,微服务架构(Spring Boot、Spring Cloud)、分布式架构(Dobbo+Zookeeper)、大数据架构以及源码解析等相关的文章,感兴趣的话可以关注一下。

程序员云帆哥的博客 2万+

别再乱改宏定义了!STM32F103程序移植保姆级教程(从C8T6到ZET6实战)

本文详细解析了STM32F103程序从C8T6移植到ZET6的实战步骤,重点介绍了硬件差异、开发环境配置、时钟陷阱及外设处理等关键点。通过修改宏定义(如STM32F10X_HD)、调整启动文件和时钟配置,确保移植顺利进行。适合嵌入式开发者参考,避免常见移植问题。

weixin_42567497的博客 215

Spring Boot整合MyBatis实现简单的CRUD

这篇文章主要针对java初学者,详细介绍如何创建一个基本的springboot项目来对数据库进行crud操作。

沐雨橙风ιε的博客 4487

肖特基二极管的反向恢复过程

本博客简述肖特基二极管反向恢复过程。

记得诚 1万+

激光除草技术原理与应用全解析

激光除草技术通过光热、光化学等效应精准破坏杂草组织,核心参数包括功率(20-6000W)、波长(400nm-10.6μm)和脉冲宽度。主要应用于大田作物(如玉米、棉花)、经济作物(烟草、果树)及城市绿化,具有环保(无化学污染)、高效(识别率≥95%)和非接触等优势,但存在设备成本高(20-50万元)、技术门槛高等局限。当前技术融合AI识别、多光谱协同等创新,国产设备如华工智耘已实现95.3%识别精度。虽短期投入较高,但长期可降低30%除草成本,并带来环境效益(每亩减排1.2吨CO₂)

start_up_go的博客 557

Java数据库开发入门之JDBC与MyBatis

1. 什么是JDBC?2. JDBC操作数据库的核心步骤(以查询为例) 新手可记住“五步曲”: 创建预编译语句(重点!): 使用而不是普通的,因为它能防止SQL注入(黑客攻击的一种),并且性能更好。 示例: 设置参数:给占位符赋值,注意参数顺序和类型。 执行查询并处理结果: 用执行查询,返回(结果集)。 用遍历结果,获取数据: 关闭资源:用完后一定要关闭连接,避免内存泄漏! 3. 新手必懂:什么是SQL注入?如何避免? 由于永远为真,黑客会绕过登录验证! 解决方案:必须使用预编译语句

weixin_63950083的博客 1479

YOLO26 数据标注工具:LabelImg、Label Studio实战指南:主流标注工具的安装配置与使用技巧,高效完成目标检测数据标注

本文介绍了目标检测中数据标注的核心地位与常用工具。数据标注质量直接影响模型性能,需要关注准确性、一致性等维度。文章详细讲解了边界框、类别标签等基本概念,并对比了LabelImg、Label Studio等主流标注工具的特点。重点介绍了LabelImg的轻量级、易用性等优势,以及Label Studio的协作功能,为不同规模项目提供标注工具选择建议。

本博客聚焦 YOLOv11 全流程落地,涵盖架构优化、数据集处理、训练技巧与多场景部署,兼及国产数据库、Java 开发与 AI 模型应用,内容兼顾理论与工程实践,为开发者提供系统干货,助力高效提升技术能力。 1176

Spring Boot 实战:MyBatis 操作数据库(上)

本文深度解析了 Spring Boot 环境下 MyBatis 的集成与应用。通过回顾传统 JDBC 的局限性,详细展示了 MyBatis 在日志配置、CRUD 操作、自增主键返回及多表查询中的实战用法。同时,文章深入探讨了 #{} 与 ${} 的底层预编译差异及安全风险,并分享了企业级开发中的数据库命名规范与 Druid 连接池配置,助力开发者构建稳健的持久层架构。

此人很懒,什么都留下了...快进来看看吧 2903

C#开发的OpenRA游戏之网络接收后找到游戏对象

而这个队列是在创建这个游戏对象时组件,因为一个游戏对象有很多特性,当发现创建游戏对象时有IResolveOrder继承接口的对象,就添加到这个数组。在这里先检查一下命令是否有效的,接着就调用命令的执行对象,即是游戏对象来执行这个命令了。order.Subject就是上面解释游戏对象ID,并从游戏世界里找到的游戏对象,再从各个字段里找到对应的信息,再把这个动作交给游戏世界里的对象执行。从前面分析可知,要找到游戏世界里的对象,就需要游戏对象的ID,因此, 我们来分析游戏对象的ResolveOrder函数。

大坡3D软件开发 1034

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Spring Boot 整合原生 MyBatis 实战:基于 mybatis-spring-boot-starter 的 ORM 示例解析

本篇技术指南以 spring-boot-demo 仓库中的 [demo-orm-mybatis](https://link.gitcode.com/i/70f0426b5c316d5464b8f4d2ab1449e3) 模块为核心,完整讲解 Spring Boot 如何通过 MyBatis 官方脚手架 `mybatis-spring-boot-starter` 与原生 MyBatis 进行整合。你

gitblog_00664的博客 1073

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Spring Boot整合MyBatis:企业级Java持久层实践

ORM框架作为Java企业应用开发的核心组件,通过对象关系映射简化数据库操作。MyBatis作为半自动化ORM框架,以其灵活的SQL控制能力著称,特别适合需要精细优化查询性能的场景。Spring Boot的自动配置特性与MyBatis结合后,能显著提升开发效率,减少样板代码。这种技术组合在电商系统等高并发应用中表现优异,支持动态SQL构建、多数据源配置等高级特性。通过PageHelper插件实现分页查询、利用声明式事务管理保证数据一致性,开发者可以快速构建健壮的持久层。本文以电商后台系统为例,详解Sprin

weixin_33714884的博客 341

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

MyBatis核心原理与Spring Boot集成实战:从JDBC困境到高效ORM

在Java企业级应用开发中,数据库持久化是核心环节。JDBC作为Java连接数据库的标准API,虽然提供了基础能力,但在实际项目中会面临样板代码重复、资源管理繁琐、SQL硬编码以及对象关系映射缺失等工程难题。为了解决这些问题,ORM(对象关系映射)技术应运而生,它旨在桥接关系型数据库与面向对象编程,提升开发效率和代码可维护性。MyBatis作为一款优秀的半自动化ORM框架,其核心价值在于平衡了灵活性与便捷性:它通过XML或注解配置,将SQL语句与Java方法、数据库记录与POJO对象优雅绑定,自动化了SQL

weixin_30466039的博客 423

MyBatis核心原理与Spring Boot集成实战:从JDBC痛点解析到企业级应用

在Java企业级开发中,数据库访问是核心环节。从基础的JDBC到全自动ORM,开发者始终在控制力与开发效率间寻求平衡。JDBC提供了完全的SQL控制,但伴随着大量的样板代码和资源管理负担;而全自动ORM框架虽然提升了开发效率,却在复杂查询和性能优化上削弱了控制力。MyBatis作为一款半自动ORM框架,其技术价值在于精准地解决了这一矛盾:它允许开发者直接编写和优化SQL,保持对数据库操作的完全掌控,同时通过自动化参数映射和结果集映射,消除了JDBC中的重复劳动。这种设计使得MyBatis特别适用于需要执行复

weixin_30564785的博客 500

Spring Boot防SQL注入:从原理到实战的纵深防御体系

SQL注入是一种常见的Web安全漏洞,其根本原理在于应用程序将用户输入的数据未经充分处理便直接拼接至SQL语句中执行,导致攻击者可能篡改查询逻辑。防御的核心在于贯彻“数据与代码分离”原则,通过预编译机制确保用户输入始终被当作数据处理。在技术实现上,ORM框架如MyBatis的正确使用是关键,必须区分`#{}`预编译占位符与`${}`字符串替换的本质差异。结合输入验证、数据库最小权限配置及运行时监控,可构建多层防护体系。本文聚焦于**Spring Boot**项目中如何系统性地应用这些策略,特别是在**MyB

aome1470的博客 416
上一篇: CCF“司南杯”量子计算编程挑战赛练习题(一)解析
GXcodes
博客等级 码龄5年 15粉丝 6原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值