Java点击劫持案例分析
什么是点击劫持
点击劫持(Clickjacking)是一种恶意攻击技术,攻击者通过透明层覆盖在合法页面上,诱导用户点击看似无害的界面元素,实际上触发了隐藏页面上的功能,在Java Web应用中,这种攻击尤其危险,可能使用户在不知情下执行敏感操作。

典型攻击案例
案例1:社交网络中的隐藏点赞
场景描述:某社交平台使用Java Servlet处理用户交互,攻击者在其恶意站点嵌入了一个透明的iframe。
攻击过程:
<!-- 攻击者页面 -->
<html>
<body>
<div style="opacity:0; position:absolute; z-index:2;">
<iframe src="https://social-network.com/like?postId=123"
width="100" height="100" frameborder="0"></iframe>
</div>
<div style="z-index:1; position:absolute;">
<button>点击领取免费奖品!</button>
</div>
</body>
</html>
Java端脆弱代码:
@WebServlet("/like")
public class LikeServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
// 未检查X-Frame-Options
String postId = req.getParameter("postId");
User user = getCurrentUser(req); // 从session获取已登录用户
likeService.addLike(user.getId(), postId);
}
}
攻击效果:当用户点击"领取奖品"按钮时,实际点击了透明的点赞按钮,导致在不知情下点赞。
案例2:银行转账劫持
场景描述:Java Spring MVC实现的网上银行,转账操作通过POST请求完成。
攻击构造:
<html>
<head>
<style>
iframe {
opacity: 0;
position: absolute;
top: 0;
left: 0;
width: 500px;
height: 400px;
}
.fake-button {
position: absolute;
top: 200px;
left: 100px;
z-index: 10;
}
</style>
</head>
<body>
<iframe src="https://bank.com/transfer"></iframe>
<button class="fake-button" onclick="startClick()">查看星座运势</button>
<script>
function startClick() {
// 实际触发iframe内的转账提交按钮
document.querySelector('iframe').contentWindow.document
.querySelector('#transferBtn').click();
}
</script>
</body>
</html>
Java脆弱代码:
@Controller
public class TransferController {
@PostMapping("/transfer")
public String transfer(@RequestParam String toAccount,
@RequestParam BigDecimal amount,
HttpSession session) {
// 没有CSRF token验证,且未设置X-Frame-Options
User user = (User) session.getAttribute("user");
transferService.transfer(user.getAccount(), toAccount, amount);
return "success";
}
}
防御措施
设置X-Frame-Options响应头
@WebFilter("/*")
public class ClickjackingFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("X-Frame-Options", "SAMEORIGIN");
// 或: response.setHeader("X-Frame-Options", "DENY");
chain.doFilter(req, res);
}
}
使用CSP(Content Security Policy)
response.setHeader("Content-Security-Policy",
"frame-ancestors 'self'");
// 或禁止所有框架: frame-ancestors 'none'
框架破框脚本(JavaScript防御)
// 在页面加载时检查是否被iframe嵌入
if (top !== self) {
top.location.href = self.location.href;
// 或显示警告
document.body.innerHTML = "<h1>请直接访问本页面</h1>";
}
Spring Security配置(Spring Boot示例)
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.frameOptions()
.sameOrigin() // 或 .deny()
.and()
.csrf()
.enable(); // 启用CSRF保护
}
}
验证关键操作的二次确认
@PostMapping("/transfer")
public String transfer(@RequestParam String toAccount,
@RequestParam BigDecimal amount,
@RequestParam String confirmToken,
HttpSession session) {
// 验证确认token,防止自动化点击
if (!confirmToken.equals(session.getAttribute("transferToken"))) {
return "error";
}
// 执行转账逻辑
}
攻击检测方法
日志分析检测
// 在Servlet过滤器中记录Referer头
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) {
HttpServletRequest request = (HttpServletRequest) req;
String referer = request.getHeader("Referer");
if (referer != null && !referer.startsWith("https://yourdomain.com")) {
log.warn("可疑的Referer: " + referer);
}
chain.doFilter(req, res);
}
用户行为分析
- 监控异常的点击频率
- 检测鼠标轨迹的异常模式
- 记录点击位置与页面元素的偏差
- 始终设置X-Frame-Options:DENY(完全禁止)或SAMEORIGIN(同源允许)
- 启用CSRF保护:防止攻击者利用用户的认证会话
- 使用CSP框架限制:精确控制哪些域名可以嵌入页面
- 重要操作增加二次确认:如输入验证码或确认对话框
- 前端破框脚本:作为额外防线,但不可单独依赖
- 定期安全审计:检查所有Java Web组件的响应头配置
点击劫持攻击虽然构造简单,但危害巨大,Java应用开发者应该将防御措施作为安全开发的基础组成部分,而不是事后补救。