news 2026/4/17 17:37:53

从一次 Spring Boot + MySQL 报错,看 Web 攻击面与防御模型,用安全视角复盘攻击面、风险点与防御机制的记录。

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从一次 Spring Boot + MySQL 报错,看 Web 攻击面与防御模型,用安全视角复盘攻击面、风险点与防御机制的记录。

零、项目代码和攻击面介绍

众嗦粥汁,一个spring boot项目里DemoAplication是启动器,各个Controller是主要的攻击面,config是副攻击面,现在我通过AI写了一个spring boot项目并分析它的攻击点,以下是Usercontroller的代码和整个项目的结构

package com.liangning.demo.controller; import com.liangning.demo.common.Result; import com.liangning.demo.entity.User; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.web.bind.annotation.*; import java.util.Map; @RestController @RequestMapping("/user") public class UserController { private final JdbcTemplate jdbcTemplate; public UserController(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } // ✅ 查询用户:/user/get?id=1 @GetMapping("/get") public Result<User> getUser(@RequestParam Long id) { String sql = "SELECT id, name FROM users WHERE id = ?"; Map<String, Object> row = jdbcTemplate.queryForMap(sql, id); User u = new User(); u.setId(((Number) row.get("id")).longValue()); u.setName((String) row.get("name")); return Result.ok(u); } // ✅ 新增用户:/user/add?name=tom @GetMapping("/add") public Result<Long> addUser(@RequestParam String name) { String sql = "INSERT INTO users(name) VALUES (?)"; jdbcTemplate.update(sql, name); // 取最后插入的自增 id(对 MySQL 有效) Long id = jdbcTemplate.queryForObject("SELECT LAST_INSERT_ID()", Long.class); return Result.ok(id); } }

一、项目背景(最小可复现场景)

这是一个最简单的 Spring Boot Web 项目:

  • Web 框架:Spring Boot

  • Web 端口:8080

  • 数据库:MySQL(3306

  • 表:users

目前对外只暴露两个接口

  • GET /user/get?id=

  • GET /user/add?name=

这类结构在学习项目、小工具、内部系统中非常常见,但也正因为“简单”,攻击面反而更清晰

二、攻击面地图(Attack Surface Map)

先不谈漏洞,先谈攻击面在哪里

HTTP 请求

Controller(/user/get, /user/add) ← 攻击入口

JdbcTemplate / SQL ← 高风险区

MySQL users 表 ← 核心资产

攻击面拆解(√ / ×)

  • Controller
    所有 HTTP 参数都是不可信输入

  • SQL 执行层
    一旦输入进入 SQL 语法层,就可能产生注入、越权等问题

  • 数据库
    数据完整性、可用性是最终目标

  • ×浏览器报错/500 页面
    只是症状,不是根因

三、接口级风险分析

1️⃣/user/add?name=xxx

功能:
users表插入一条记录,并返回自增 id。

攻击面与风险
  • 参数入口name

  • 潜在风险

    • SQL 注入(如果使用字符串拼接)

    • 脏数据(超长、异常字符)

    • 错误信息泄露(SQL 异常直接返回)

当前实现的安全点(√)
String sql = "INSERT INTO users(name) VALUES (?)"; jdbcTemplate.update(sql, name);
  • 使用参数化查询

  • 用户输入只作为“数据”,不会进入 SQL 语法层

  • 能天然防御 SQL 注入

✅ 这是正确、安全、推荐的写法(说人话就是把用户输入当字符串,不去执行

2️⃣/user/get?id=1

功能:
根据 id 查询用户。

攻击面与风险(重点)
  • ID 枚举风险

    • id=1,2,3...天然可猜

  • 潜在 IDOR(越权)

    • 如果未来加入登录系统,而这里不校验“是否有权限看这个 id”

  • 信息泄露

    • SQL 报错会暴露表名、字段名

这类问题在真实 Web 攻击中非常常见,而且往往不是“技术高深”,而是“设计疏忽”。

四、一次真实遇到的问题:500 错误从何而来?

在访问/user/get?id=1时,接口返回500 Internal Server Error

日志核心信息是:

java.sql.SQLSyntaxErrorException: Table 'demo_db.users' doesn't exist

错误链路复盘

HTTP 请求 → Controller 正常接收 → SQL 正常执行 → MySQL 抛异常(表不存在) → Spring 包装成 500

⚠️关键点
这不是 Web 层的问题,也不是 Controller 写错,而是:

数据库结构 ≠ 应用假设的结构

五、根因定位:数据库结构问题,而非代码问题

进一步检查数据库:

USE demo_db; SHOW TABLES;

发现:

  • users表不存在,或结构不完整

  • 即使存在,也可能缺少AUTO_INCREMENT

后续又遇到的错误(典型)

Field 'id' doesn't have a default value

这说明:

  • 表中id字段既不是自增

  • 又被设为NOT NULL

  • 应用层没有传 id → 数据库拒绝

翻译成人话就是就只建了库,里面啥也没有,然后建了库以后又忘了把name设置成必须要有,id设置成自增(可以没有输入进去,没有的话就在上一个的id基础上加1)

六、修复方案(也是防御加固)

1️⃣ 正确设置自增主键

ALTER TABLE users MODIFY id INT NOT NULL AUTO_INCREMENT;

含义是:

  • 当 INSERT 不提供 id

  • 数据库自动生成唯一 id

  • 应用不需要“猜”或“管理”主键

2️⃣ 安全收益(不仅是功能修复)

  • ✅ 防止因主键问题导致的 500

  • ✅ 降低逻辑复杂度

  • ✅ 避免开发者在应用层“手写 id”

  • ✅ 更符合数据库安全与一致性原则

七、从安全角度总结这次实践

核心模型(非常重要)

Controller 是攻击入口,SQL 是高风险区,数据库是资产。

这次实践中学到的 3 个安全结论

  1. 500 错误 ≠ 程序崩溃
    很多时候是数据结构或假设错误

  2. 参数化查询是必须的,不是“最佳实践可选项”

  3. 攻击者和开发者看到的是同一套错误信息

    • 你能靠异常定位问题

    • 攻击者也能靠异常推断表结构


八、后续加固方向

  • name做长度与字符校验

  • id做范围校验

  • 错误信息对外统一为业务错误

  • 日志中保留详细异常,前端不暴露

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/3 6:13:30

SAM 3文化传播:艺术品分割技术

SAM 3文化传播&#xff1a;艺术品分割技术 1. 技术背景与应用价值 在数字艺术与文化遗产保护领域&#xff0c;高精度的图像和视频内容理解正变得愈发关键。传统图像分割方法往往依赖大量标注数据&#xff0c;且难以泛化到新类别或复杂场景。随着基础模型的发展&#xff0c;可…

作者头像 李华
网站建设 2026/4/10 22:14:51

ACE-Step实战教程:生成中国风古风歌曲的关键要素

ACE-Step实战教程&#xff1a;生成中国风古风歌曲的关键要素 1. 学习目标与背景介绍 随着AI音乐生成技术的快速发展&#xff0c;创作一首结构完整、风格鲜明的音乐作品已不再局限于专业作曲人。ACE-Step作为一款由ACE Studio与阶跃星辰&#xff08;StepFun&#xff09;联合推…

作者头像 李华
网站建设 2026/4/2 22:12:58

Glyph模型微调教程:定制化视觉任务部署指南

Glyph模型微调教程&#xff1a;定制化视觉任务部署指南 1. 引言 1.1 Glyph-视觉推理 在当前大模型时代&#xff0c;长文本上下文处理已成为自然语言处理领域的重要挑战。传统的基于token的上下文扩展方法面临计算复杂度高、显存占用大等问题。为应对这一瓶颈&#xff0c;智谱…

作者头像 李华
网站建设 2026/4/5 22:58:07

SAM3文本引导万物分割实战|一键精准提取图像掩码

SAM3文本引导万物分割实战&#xff5c;一键精准提取图像掩码 在计算机视觉领域&#xff0c;图像分割技术正经历一场由大模型驱动的变革。传统的分割方法依赖大量标注数据和特定任务训练&#xff0c;而基于提示&#xff08;Prompt&#xff09;的通用分割模型正在打破这一局限。…

作者头像 李华
网站建设 2026/4/9 13:38:29

kotlin数据类用法

数据类只保存数据&#xff0c;没有什么复杂业务。简单测试下&#xff1a;data class JingDianTaiCi(val name: String, val taici: String) // 经典台词fun main() {val taiCi JingDianTaiCi("少林武僧", "我的战斗力有6000&#xff0c;他起码有10000以上"…

作者头像 李华
网站建设 2026/4/17 7:04:57

Proteus电路仿真快速理解:示波器和逻辑分析仪联动

Proteus仿真实战&#xff1a;用示波器和逻辑分析仪“双剑合璧”定位混合信号问题你有没有遇到过这种情况&#xff1f;电路明明写好了代码&#xff0c;烧录进去却迟迟不工作。串口打印一切正常&#xff0c;但外设就是没反应——是模拟信号出问题了&#xff1f;还是数字时序对不上…

作者头像 李华