CSRF(跨站请求伪造)攻击的核心逻辑是攻击者诱导已登录目标网站的用户,在用户的浏览器中发起一个指向目标网站的伪造请求,这个请求会自动携带用户的登录凭证(比如Cookie),让服务器误以为是用户主动发起的合法操作。文件上传功能如果没有对应的防护机制,就很容易被CSRF攻击利用。

CSRF攻击对文件上传的影响
当网站的文件上传接口没有做CSRF防护时,攻击者可以构造一个恶意页面,页面中包含自动提交的文件上传表单。只要用户访问这个恶意页面,并且此时用户刚好登录了目标网站,浏览器就会自动携带用户的Cookie向目标网站的文件上传接口发送请求,上传攻击者指定的文件。
这种攻击可能带来的危害包括:
- 上传恶意脚本文件,比如PHP、JSP木马,获取服务器控制权
- 上传违规内容,导致网站被封禁
- 上传大体积文件,消耗服务器存储和带宽资源
- 上传伪装成正常文件的恶意程序,诱导其他用户下载
CSRF Token防护原理
CSRF Token的防护逻辑是服务器为每个用户会话生成一个随机、不可预测的字符串(即Token),并将这个Token嵌入到前端的表单或者请求头中。当用户提交文件上传请求时,需要携带这个Token,服务器收到请求后会验证Token的合法性:如果Token不存在或者不匹配,就拒绝请求,从而识别并拦截CSRF伪造的请求。
前后端添加Token防护的实现步骤
1. 后端生成并返回Token
首先后端需要在用户登录或者访问文件上传页面时,生成一个CSRF Token,保存到用户的会话中,同时返回给前端。以下是Java Spring Boot的实现示例:
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.UUID;
public class CsrfTokenUtil {
// 生成Token并存入session
public static String generateToken(HttpServletRequest request) {
String token = UUID.randomUUID().toString().replace("-", "");
HttpSession session = request.getSession();
session.setAttribute("csrf_token", token);
return token;
}
// 验证Token
public static boolean verifyToken(HttpServletRequest request, String clientToken) {
HttpSession session = request.getSession();
String serverToken = (String) session.getAttribute("csrf_token");
if (serverToken == null || clientToken == null) {
return false;
}
return serverToken.equals(clientToken);
}
}
2. 前端表单嵌入Token
前端在文件上传表单中,需要添加一个隐藏的输入框,用来存放后端返回的CSRF Token。以下是HTML表单的示例:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>文件上传</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data" id="uploadForm">
<!-- 隐藏的CSRF Token输入框 -->
<input type="hidden" name="csrf_token" value="${csrfToken}">
<input type="file" name="file">
<button type="submit">上传文件</button>
</form>
</body>
</html>
如果是前后端分离的项目,前端可以通过接口获取Token,然后添加到请求头中,以下是JavaScript的示例:
// 获取CSRF Token
fetch('/getCsrfToken')
.then(res => res.json())
.then(data => {
const csrfToken = data.token;
// 后续上传文件时携带Token
const formData = new FormData();
formData.append('file', document.querySelector('input[type=file]').files[0]);
fetch('/upload', {
method: 'POST',
headers: {
'X-CSRF-TOKEN': csrfToken
},
body: formData
})
});
3. 后端验证Token
后端在文件上传接口中,需要取出请求中的Token进行验证,验证通过才处理上传逻辑。以下是接口处理的示例:
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
@PostMapping("/upload")
public String uploadFile(@RequestParam("file") MultipartFile file, HttpServletRequest request) {
// 获取请求中的Token
String clientToken = request.getParameter("csrf_token");
// 如果是请求头传递的Token,用request.getHeader("X-CSRF-TOKEN")
// 验证Token
if (!CsrfTokenUtil.verifyToken(request, clientToken)) {
return "请求非法,CSRF Token验证失败";
}
// Token验证通过,处理文件上传逻辑
// 此处省略文件存储的具体代码
return "文件上传成功";
}
防护注意事项
为了保证CSRF Token的防护效果,需要注意以下几点:
- Token必须是随机生成、不可预测的,不要使用固定值或者容易被猜到的规则生成
- Token要和用户的会话绑定,每个用户的Token独立,不要全局共用同一个Token
- Token的有效期要合理,建议和用户会话有效期一致,或者单次使用后失效
- 文件上传接口的Token验证要放在所有业务逻辑之前,避免未验证就处理请求
- 对于支持跨域的文件上传接口,要配合CORS策略做限制,只允许可信的域名发起请求
常见问题解答
Token泄露会不会导致防护失效?
如果Token被攻击者通过XSS等方式获取,那么防护确实会失效,所以还需要配合XSS防护,对用户输入的内容做转义,避免Token被窃取。另外可以使用双重Cookie验证作为补充方案,进一步提升安全性。
文件上传用了验证码还需要CSRF Token吗?
验证码可以在一定程度上防范CSRF攻击,但是验证码会影响用户体验,而且如果验证码验证逻辑存在漏洞,还是可能被绕过。CSRF Token的防护更轻量,和验证码配合使用可以进一步提升安全性。
CSRF攻击文件上传CSRF_tokenWeb安全防护方案修改时间:2026-06-25 01:54:38