⚠️ 免责声明:本项目仅用于安全学习与教育目的,严禁用于非法用途。如因使用本项目造成的任何法律后果,使用者自行承担全部责任。
本项目是基于 SpringBoot + Vue 的图书管理系统,实现了图书查询、借阅、借阅记录查看、用户登录注册等功能。在学习 Web 安全知识后,我对项目进行了主动的代码审计,发现两处高危漏洞:SQL 注入和水平越权。
项目源码:GitHub - library-security-lab
这个是危险的写法,${} 是字符串替换,直接把参数拼接到 SQL 里。
举例:
用户输入:Java
SQL:SELECT * FROM books WHERE book_name LIKE '%Java%'
用户输入:' OR '1'='1' -- -
SQL:SELECT * FROM books WHERE book_name LIKE '%' OR '1'='1' -- -%'
'1'='1' 永远都是真的,逻辑就被篡改了。
这个是安全的写法,#{} 是预编译参数,这些参数会被当做纯文本来处理。
举例:
数据库收到以后就是普通的字符串,不是 SQL 代码。
BookMapper.java
BookService.java
问题: 直接把前端的数据喂给后端,没有做任何的处理。
Payload:
解释:
在 Burp 里操作就是:
%27 → ',%20 → 空格




可以看到图片里返回了 33 本书,这是正确的。
理由: 后面的 UNION SELECT 要让左右列数一样,不然会报错。
Payload:
这里我是知道我自己的页数,在不知道的情况下需要一个个试。
5√ 6 × → 列数就是 5




这一步我们就确定了列数是 5。
UNION 可以把两个查询结果拼接到一起,构造一个"假查询",数据就会显示在页面上。
Payload:
右边的就是我们构造的假查询。


我这个有分页,而且没有排序,所以他会显示在最后一页,可以看到这个图片里显示了数字,这些就是我们找到的显示位。
主要是确认一下环境,找到这个 MySQL 的版本号,这里的显示位我用的是第 2 列。
Payload:




8.0.45 就是我们提取出来的版本号。
主要查看数据库里有哪些表格。
Payload:
information_schema.tables 是 MySQL 的系统表,存储了所有表的信息。
table_schema=database() 表示查询当前数据库的表。
还是放在第 2 列显示。




出现这个问题不要慌,查一下是不是格式有问题,根据上面的步骤统一一下编码,或者刷新一下重新抓包。




这四个表格就是我的数据库里的。
查 user 表里有哪些列(id, username, password 等)。
还是一样的查 information_schema,但这里是 columns。
Payload:






确认有 username 和 password 就可以。
用 CONCAT 函数把这两个字段连接起来。
Payload:
注: 一定要注意符号,容易漏打。




我这里有两个用户,可以看到完整的显示了。
这个就是全过程。
换成 #{} 后,不能再在 SQL 里写 % 了,因为 #{} 会把整个参数(包括 %)当作一个整体去匹配,所以要放到 Java 里去拼接。
这样既能模糊搜索,又不会有 SQL 注入风险。
传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!
最后于 1天前
被Jmn314编辑
,原因: 修改标题