论坛首页 安全编程开发区 阅读主题

[原创]基于图书管理系统的漏洞复现与代码审计

473 浏览 1 回复
#1 楼主 2026-06-01 21:09:07
⚠️ 免责声明:本项目仅用于安全学习与教育目的,严禁用于非法用途。如因使用本项目造成的任何法律后果,使用者自行承担全部责任。一、项目背景本项目是基于 SpringBoot + Vue 的图书管理系统,实现了图书查询、借阅、借阅记录查看、用户登录注册等功能。在学习 Web 安全知识后,我对项目进行了主动的代码审计,发现两处高危漏洞:SQL 注入和水平越权。项目源码:GitHub - library-security-lab二、SQL 注入漏洞2.1 漏洞原理${} 和 #{} 的区别:@Select("SELECT * FROM books WHERE book_name LIKE '%${bookName}%' AND author LIKE '%${author}%'")这个是危险的写法,${} 是字符串替换,直接把参数拼接到 SQL 里。举例:用户输入:JavaSQL:SELECT * FROM books WHERE book_name LIKE '%Java%'用户输入:' OR '1'='1' -- -SQL:SELECT * FROM books WHERE book_name LIKE '%' OR '1'='1' -- -%''1'='1' 永远都是真的,逻辑就被篡改了。@Select("SELECT * FROM books WHERE book_name LIKE #{bookName} AND author LIKE #{author}")这个是安全的写法,#{} 是预编译参数,这些参数会被当做纯文本来处理。举例:用户输入:' OR '1'='1' -- -SQL:SELECT * FROM books WHERE book_name LIKE ?(? 是占位符)数据库收到以后就是普通的字符串,不是 SQL 代码。2.2 漏洞代码位置BookMapper.java@Select("SELECT * FROM books WHERE book_name LIKE '%${bookName}%' AND author LIKE '%${author}%'")BookService.javareturn bookMapper.searchBoooksVuln(
    nameEmpty ? "%" : bookName,
    authorEmpty ? "%" : author
);问题: 直接把前端的数据喂给后端,没有做任何的处理。2.3 复现步骤步骤 1:验证漏洞存在Payload:bookName=' OR '1'='1' -- -解释:':闭合前面的单引号'1'='1':添加了一个永远都是真的条件-- -:注释掉后面的 AND author LIKE '%...%'(-- 是 SQL 注释符,后面必须跟一个空格)在 Burp 里操作就是:bookName=%27%20OR%20%271%27%3D%271%27%20--%20-%27 → ',%20 → 空格可以看到图片里返回了 33 本书,这是正确的。步骤 2:判断列数(ORDER BY)理由: 后面的 UNION SELECT 要让左右列数一样,不然会报错。Payload:ORDER BY 5 -- -这里我是知道我自己的页数,在不知道的情况下需要一个个试。如果正常返回:列数 >= 5报错或者空:列数 < 55√ 6 × → 列数就是 5这一步我们就确定了列数是 5。步骤 3:找显示位UNION 可以把两个查询结果拼接到一起,构造一个"假查询",数据就会显示在页面上。Payload:bookName=' UNION SELECT 1,2,3,4,5 -- -右边的就是我们构造的假查询。我这个有分页,而且没有排序,所以他会显示在最后一页,可以看到这个图片里显示了数字,这些就是我们找到的显示位。步骤 4:爆数据库版本主要是确认一下环境,找到这个 MySQL 的版本号,这里的显示位我用的是第 2 列。Payload:bookName=' UNION SELECT 0,version(),3,4,5 -- -0:id=0version():数据库内置函数,返回数据库版本8.0.45 就是我们提取出来的版本号。步骤 5:爆表名(获得数据库结构)主要查看数据库里有哪些表格。Payload:bookName=' UNION SELECT 1,table_name,3,4,5 FROM information_schema.tables WHERE table_schema=database() -- -information_schema.tables 是 MySQL 的系统表,存储了所有表的信息。table_schema=database() 表示查询当前数据库的表。还是放在第 2 列显示。出现这个问题不要慌,查一下是不是格式有问题,根据上面的步骤统一一下编码,或者刷新一下重新抓包。这四个表格就是我的数据库里的。步骤 6:爆字段名(找账号和密码)查 user 表里有哪些列(id, username, password 等)。还是一样的查 information_schema,但这里是 columns。Payload:bookName=' UNION SELECT 0,column_name,3,4,5 FROM information_schema.columns WHERE table_name='user' -- -确认有 username 和 password 就可以。步骤 7:拖库(偷 username 和 password)用 CONCAT 函数把这两个字段连接起来。Payload:bookName=' UNION SELECT 0,CONCAT(username,':',password),4,5 FROM user -- -注: 一定要注意符号,容易漏打。我这里有两个用户,可以看到完整的显示了。这个就是全过程。2.4 修复方案修复代码:// 【修复代码】使用 #{} 预编译参数,防止 SQL 注入
List<Book> searchBooksSafe(@Param("bookName") String bookName,
return bookMapper.searchBooksSafe(
    nameEmpty ? "%" : "%" + bookName + "%", 
    authorEmpty ? "%" : "%" + author + "%"
);换成 #{} 后,不能再在 SQL 里写 % 了,因为 #{} 会把整个参数(包括 %)当作一个整体去匹配,所以要放到 Java 里去拼接。如果用户没输入书名(nameEmpty 是 true),就传 "%"(匹配所有)如果用户输入了 Java,就拼接成 "%Java%",然后传给 Mapper这样既能模糊搜索,又不会有 SQL 注入风险。注意: 若需严格避免用户输入 % 或 _ 被当作 LIKE 通配符,可对用户输入进行转义(如将 % 替换为 \%),或改用全文索引方案。本系统为演示场景,暂不处理。三、水平越权漏洞3.1

...(已截断)

---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-290904.htm
#2 2026-06-01 21:09:07
这篇文章把 SpringBoot + Vue 项目中常见的两类高危漏洞讲得很透彻!尤其是 SQL 注入部分,直接点出 ${} 和 #{} 的本质区别——很多人刚接触 MyBatis 时容易忽略这个坑。如果你对网络安全知识感兴趣,推荐访问:7e5K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2B7j5%4N6D9P5h3k6Q4x3X3g2U0L8$3@1`.

最后于 2026-4-21 20:16
被mb_treykprh编辑

,原因:

请登录后参与讨论

立即登录 注册账号