前记本节课是Java安全的入门第一讲核心围绕JavaWeb场景下的4类高频注入漏洞展开JDBC/MyBatis SQL注入、XXE注入、SSTI模板注入、SPEL表达式注入。课程以“原理理解靶场实战”为主配套实操环境和资源重点掌握漏洞成因、POC编写、利用方法及修复思路为后续Java安全深入学习打下基础。一、环境搭建必做支撑后续实战本节课需搭建两个核心靶场环境均要求JDK1.8、MySQL5.7MySQL8会出现语法错误支持Docker或手动安装以下为手动安装详细步骤一Hello-Java-Sec 环境搭建下载地址GitHub直接搜索下载获取源码包数据库配置CREATE DATABASE IF NOT EXISTS java_sec DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;USE java_sec;-- 用户表5.7 兼容版CREATE TABLE users( id int(11) unsigned NOT NULL AUTO_INCREMENT, uuid CHAR(36) NOT NULL, user varchar(50) NOT NULL, pass varchar(128) NOT NULL, PRIMARY KEY (id), UNIQUE KEY uuid_unique (uuid));-- 触发器插入时自动生成 UUIDDELIMITER $$CREATE TRIGGER users_before_insertBEFORE INSERT ON usersFOR EACH ROWBEGIN IF NEW.uuid IS NULL OR NEW.uuid THEN SET NEW.uuid UUID(); END IF;END$$DELIMITER ;-- 预置数据手动给 uuidINSERT INTO users (id, uuid, user, pass) VALUES (1, UUID(), zhangwei, 123456), (2, UUID(), Admin, password), (3, UUID(), wangwei, 123123);-- 登录日志表CREATE TABLE auth( id int(6) unsigned NOT NULL AUTO_INCREMENT, user varchar(50) NOT NULL, ip varchar(50) NOT NULL, date varchar(60) NOT NULL, PRIMARY KEY (id));-- 存储型 XSS 表CREATE TABLE xss( id int(6) unsigned NOT NULL AUTO_INCREMENT, user varchar(50) NOT NULL, content TEXT NOT NULL, date varchar(60) NOT NULL, PRIMARY KEY (id));​打开源码中 application-dev.properties​ 文件修改为本地MySQL数据库连接信息账号、密码、数据库名修改 db.sql​ 文件适配MySQL5.7内容如下创建数据库、表、预置数据导入数据库连接本地MySQL创建java_sec​ 数据库导入修改后的 db.sql​ 文件打包运行在源码根目录用Maven打包运行生成的jar包默认端口8888可自行修改访问测试浏览器打开 http://localhost:端口​默认账号密码 admin/admin​能正常登录即搭建成功。二JavaSec 环境搭建下载地址GitHub搜索 bewhale/JavaSec​获取源码数据库配置修改 src/main/resources/application.yml​ 文件配置本地MySQL账号、密码创建数据库 javasec​可自定义名称如 javaseclab​导入源码中的 javasec.sql​ 文件打包运行根目录Maven打包运行jar包默认端口8000可修改访问测试浏览器打开 http://localhost:端口​默认账号密码 admin/admin​登录成功即完成搭建。二、Java安全 - SQL注入JDBCMyBatisJava中SQL注入的核心成因与PHP类似——​用户可控参数直接拼接SQL语句​但因Java常用JDBC、MyBatis等数据库访问框架漏洞场景更具针对性主要分为JDBC注入和MyBatis注入两类。一JDBC注入基础企业开发中较少用JDBC是Java访问数据库的核心标准直接操作数据库使用不当易产生注入主要有4种漏洞场景1. 语句拼接最基础、最高危原理直接将用户可控参数拼接进SQL语句未做任何过滤或预编译。// 漏洞代码直接拼接id参数 String sql select * from users where id id ; // 注入POCid传入 or 11 -- - 拼接后SQL变为 // select * from users where id or 11 -- -防范避免直接拼接使用预编译或严格的黑名单过滤不推荐。2. 预编译的错误使用原理虽使用了预编译PreparedStatement但仍用拼接方式构造SQL未使用占位符 ?​等同于未做预编译。// 错误代码拼接id预编译失效 String sql select * from users where id id; PreparedStatement st conn.prepareStatement(sql); // 正确代码使用?占位符预编译生效 String sql select * from users where id ?; PreparedStatement st conn.prepareStatement(sql); st.setString(1, id); // 将参数传入占位符自动过滤特殊字符3. JdbcTemplate注入原理JdbcTemplate是Spring对JDBC的封装简化数据库操作但若使用拼接语句仍会产生注入。// 漏洞代码拼接id参数 JdbcTemplate jdbctemplate new JdbcTemplate(dataSource); String sql select * from users where id id; return jdbctemplate.queryForMap(sql); // 防范使用ESAPI框架对参数进行编码 String sql select * from users where id ESAPI.encoder().encodeForSQL(oracleCodec, id) ; ResultSet rs stmt.executeQuery(sql);4. 正则过滤绕过原理通过正则过滤特殊字符如只允许a-z、0-9但仍可能被绕过如编码、特殊拼接核心问题是未限制参数数据类型。防范优先限制参数数据类型如id限定为整型而非单纯依赖正则过滤。二MyBatis注入企业高频重点掌握MyBatis是Java主流持久层框架默认通过 #{} ​ 占位符实现预编译可防注入但开发者误用 ${}​字符串拼接会导致注入漏洞。核心区别​#{} ​预编译自动对参数转义安全​${}​字符串拼接不转义高危易产生注入。常见漏洞场景有3种1. Like注入模糊查询场景漏洞成因使用Like模糊查询时直接用 #{} ​ 会报错开发者误将 #​ 改为$​导致拼接注入。// 漏洞代码${username} 拼接产生注入 Select * from users where username like %${username}% // 注入POCusername传入 xxx% union select database(),user(),version,4,5 -- - // 拼接后SQLselect * from users where username like %xxx% union select database(),user(),version,4,5 -- -% // 正确写法使用concat函数拼接保留预编译 Select * from users where username like concat(%,#{username}, %)2. Order By注入排序场景漏洞成因Order By后需接字段名用 #{} ​ 会报错开发者改为 ${}​允许用户控制排序字段产生注入。// 漏洞代码${field} 拼接排序字段 select * from users order by ${field} // 注入POCfield传入 id and (updatexml(1,concat(0x7e,(select user())),0))-- - // 利用updatexml函数报错获取数据库用户信息 // 正确写法固定排序字段或通过条件判断限制字段 mapper namespacecom.best.hello.mapper.UserMapper select idorderBySafe resultTypecom.best.hello.entity.User select * from users choose when testfield idorder by id desc/when when testfield userorder by user desc/when otherwiseorder by id asc limit 1/otherwise /choose /select /mapper3. In注入多值查询场景漏洞成因In语句后需接多个参数用 #{} ​ 会报错开发者改为 ${}​导致拼接注入。// 漏洞代码${ids} 拼接多id参数 Select * from users where id in (${ids}) // 注入POCids传入 1,2,3) and (updatexml(1,concat(0x7e,(select user())),0))-- - // 正确写法使用foreach循环遍历参数保留预编译 script SELECT * FROM users WHERE id IN foreach itemitem indexindex collectionids open( separator, close) #{item} /foreach /script4. 白盒案例演示inxedu项目核心思路白盒审计时优先搜索MyBatis的敏感关键字%${​、order by ${​、in (${​定位漏洞点再结合前端功能触发注入。环境搭建IDEA打开inxedu源码修改 project.properties​ 数据库配置导入 demo_inxedu_v2_0_open.sql​MySQL5.5配置Tomcat9运行漏洞定位搜索 in (${​找到删除文章功能的漏洞代码deleteArticleByIds​调用路径为 /admin/article/delete​实战利用登录后台admin/111111找到文章删除功能Burp抓包获取 articelId​ 参数用Sqlmap跑注入获取数据库信息。三SQL注入总结核心无论JDBC还是MyBatis​字符串拼接是注入的根源​防范核心是“避免拼接使用预编译”MyBatis优先用 #{} ​特殊场景Like/Order By/In用安全写法替代 ${}​。三、Java安全 - XXE注入XML外部实体注入1. 核心原理XXEXML External Entity Injection即XML外部实体注入当Java程序中XML解析器配置允许外部实体引用时攻击者可通过构造恶意XML payload实现任意文件读取、内网端口探测、命令执行部分场景、拒绝服务等攻击。Java中易产生XXE的核心类/方法代码审计重点基础类XMLReader、SAXReader、SAXBuilder、Unmarshaller、DocumentBuilder扩展类XMLStreamReader、SAXParser、SAXSource、TransformerFactory等。2. 靶场演示要点白盒测试审计代码中是否存在上述XML解析类/方法判断是否允许外部实体引用未做过滤即存在漏洞黑盒测试与PHP的XXE测试方法一致寻找接收XML参数的接口如接口请求体为XML格式传入恶意XML payload测试核心漏洞本质是XML解析器配置不当与编程语言无关测试思路通用。四、Java安全 - SSTI模板注入ThymeleafURL1. 核心原理SSTIServer Side Template Injection服务器模板注入服务端接收用户可控参数将其作为模板内容的一部分编译渲染执行了用户插入的恶意代码导致RCE、信息泄露等危害。Java中常见SSTI场景模板引擎Thymeleaf本节课重点、Freemarker、Velocity、URL作为视图。2. 靶场案例Thymeleaf漏洞成因用户可控参数如语言切换的lang参数直接拼接进模板路径未做过滤导致恶意模板代码执行。// 漏洞代码lang参数可控直接拼接模板路径 public String lang(String lang) { return lang/ lang; // 恶意lang参数会被当作模板渲染 }利用方法传入恶意payload触发RCE如弹出计算器核心是构造符合Thymeleaf语法的恶意模板代码。3. 测试要点黑盒测试寻找模板切换场景语言、皮肤、主题切换测试可控参数是否能注入恶意代码注意无明显提示时黑盒测试难度较高需结合场景猜测模板引擎类型。五、Java安全 - SPEL表达式注入SpringBoot框架1. 核心原理SPELSpring Expression LanguageSpring表达式语言用于运行时查询和操作对象图若未对用户传入的表达式参数做过滤会导致恶意表达式被解析执行相当于Java版的“eval函数”可实现RCE。2. 漏洞代码与靶场案例// 漏洞代码ex参数可控直接解析SPEL表达式 public String vul(String ex) { ExpressionParser parser new SpelExpressionParser(); EvaluationContext evaluationContext new StandardEvaluationContext(); Expression exp parser.parseExpression(ex); String result exp.getValue(evaluationContext).toString(); return result; }3. 注入POC与绕过基础POC弹出计算器T(java.lang.Runtime).getRuntime().exec(calc.exe)​解析T(...)​ 是SPEL取类对象的操作符获取Runtime类调用exec方法执行系统命令黑名单绕过如过滤Runtime利用Java反射字符串拼接绕过POC如下T(String).getClass().forName(java.l ang.Ru ntime).getMethod(ex ec, T(String[])).invoke(T(String).getClass().forName(java.l ang.Ru ntime).getMethod(getRu ntime).invoke(T(String).getClass().forName(java.l ang.Ru ntime)),new String[]{calc})​核心用字符串拼接避免直接出现“Runtime”通过反射加载类、调用方法绕过过滤。4. 测试要点先判断是否存在SPEL注入传入简单运算表达式如100-1若返回99说明表达式会被解析可进一步注入恶意代码。六、核心总结与注意事项1. 本节课核心重点Java SQL注入重点掌握MyBatis的3种注入场景Like/Order By/In区分 #{} ​ 和 ${}​ 的用法XXE注入记住Java中易产生漏洞的XML解析类测试思路与PHP通用SSTI注入聚焦Thymeleaf模板寻找模板切换场景识别可控参数SPEL注入掌握基础POC和反射绕过方法记住 T(...)​ 操作符的用法。2. 实操注意事项环境要求必须使用JDK1.8、MySQL5.75.5/5.7兼容8会报错否则环境无法正常运行代码审计思路优先搜索敏感关键字如 ${​、XML解析类、SPEL解析方法快速定位漏洞点合规测试靶场演示需在本地搭建严禁未经授权测试真实网站遵守网络安全法律法规。3. 后续学习关联本节课是Java安全的基础后续会深入学习Java反序列化、Spring框架漏洞等内容需熟练掌握本节课的4类注入漏洞理解Java代码审计的基本思路为后续深入学习打下基础。