SQL注入防护必须落在数据访问层,Spring Security不负责此事:应使用MyBatis的#{}、JPA命名参数、PreparedStatement,并限制数据库权限;XSS需在输入端过滤,不能仅依赖Thymeleaf转义或前端渲染。

SQL注入防护必须落在数据访问层,Spring Security不负责这事
Spring Security 本身不处理 SQL 注入——它压根不碰 SQL 语句构造。你指望 HttpSecurity 或 WebSecurityConfigurerAdapter(已弃用)自动拦截 ' OR '1'='1 这类输入,是方向性错误。
真正起作用的只有三件事:
- MyBatis 的
#{}(预编译占位符),不是${};JPA 的@Query必须用命名参数:name,不能拼接字符串 - JDBC 原生调用必须用
PreparedStatement,禁用Statement+ 字符串拼接 - 数据库账号权限最小化:查用户接口只给
SELECT user.*,别给DROP或跨库权限
曾见一个项目在 @RestController 里用 String.format("SELECT * FROM user WHERE name = '%s'", name),再配一百个 SecurityFilterChain 都拦不住堆叠注入。
XSS过滤不能只靠前端模板自动转义
Thymeleaf 的 th:text="${userInput}" 确实会 HTML 转义,但这是“输出时防御”,前提是数据没在中间环节被二次污染。比如富文本内容存进数据库前没过滤,读出来直接塞进 th:utext,<script> 就原样执行了。
更危险的是 DOM 型 XSS:前端 JS 拿到 JSON 数据后用 innerHTML 渲染,Spring Security 完全看不见这个过程。
所以得在输入端加一层:
- 全局
Filter包装HttpServletRequest,重写getParameter/getHeader,对所有非富文本字段做基础标签清理(如.replaceAll(") - 富文本字段单独走
Jsoup.clean(html, Safelist.relaxed().addTags("p", "br", "strong")),白名单比黑名单靠谱 - 避免用
@SafeHtml注解——它只校验字段值是否含标签,不清理,且对Map<String, Object>类型参数无效
Spring Security 能做的真实协同点只有 HTTP 头与 CSP
它不防 SQL、不拦 XSS payload,但它能加固浏览器侧的执行环境,让 XSS 即便进了页面也难生效。
关键配置就两条:
- 启用
Content-Security-Policy:在SecurityFilterChain里加headers().contentSecurityPolicy("default-src 'self'; script-src 'self' 'unsafe-inline'"),把'unsafe-inline'换成 nonce 或 hash 更稳妥 - 强制
X-Content-Type-Options: nosniff和X-Frame-Options: DENY,防 MIME 嗅探和点击劫持,间接削弱 XSS 利用链 - 别信
http.headers().xssProtection()—— 这个 header 在现代浏览器里已被废弃,Chrome 从 78 版本起无视它
这些头必须由 Spring Security 统一注入,否则前端自己设容易漏掉异步请求或 iframe 场景。
最易被忽略的混合漏洞场景:JSON API + 前端渲染
当你的接口返回 application/json,且前端用 fetch().then(r => r.json()).then(data => el.innerHTML = data.content),Spring Security 的任何配置都救不了你——XSS payload 已经绕过所有服务端过滤,直抵 DOM。
此时唯一可靠方案是:
- 后端返回 JSON 时,对所有可能渲染为 HTML 的字段(如
content,bio,comment)提前用Jsoup清洗,而不是依赖前端 sanitize - 前端改用
textContent或createTextNode渲染纯文本;真要插 HTML,必须用DOMPurify.sanitize()在客户端再过一遍 - 禁止在 Controller 返回体里直接拼接 HTML 字符串(例如
return "{html: '<div>xxx</div>'}"),这种写法等于主动开后门
安全不是某一层的事。SQL 注入卡在 DAO,XSS 的战场横跨数据库、HTTP 响应、浏览器解析三个环节——漏掉任意一环,防护就归零。

















