为什么Python POST请求正常,Java(OkHttp)POST请求却报CSRF错误?
问题根因
- 表单提交类型不匹配:Python代码用
data=payload默认发送的是application/x-www-form-urlencoded格式的普通表单,而Java代码用了MultipartBody.FORM也就是multipart/form-data格式的分片表单。多数服务端的CSRF校验逻辑只对普通表单格式的请求自动解析参数中的__RequestVerificationToken,分片表单格式下会直接认为参数缺失,触发CSRF错误。 - Cookie未自动维护:Python代码用的session对象会自动携带前序页面请求(比如访问登录页、获取token的请求)返回的Cookie,CSRF的token通常是和Cookie中存储的对应凭证配对校验的,Android端如果没有把前序请求拿到的相关Cookie(比如
.AspNetCore.Antiforgery.xxx类CSRF Cookie)一起携带,哪怕请求头和参数里传了token也会校验失败。 - 潜在的语法错误:OkHttp添加请求头的正确方法名是
addHeader(首字母H大写),你代码里写的小写addheader无法正常编译,属于笔误。
修复方案
- 首先配置OkHttp全局自动维护Cookie,和Python的session逻辑对齐:
// 初始化OkHttpClient时配置CookieJar,自动管理会话Cookie OkHttpClient client = new OkHttpClient.Builder() .cookieJar(new CookieJar() { private final HashMap<HttpUrl, List<Cookie>> cookieStore = new HashMap<>(); @Override public void saveFromResponse(@NonNull HttpUrl url, @NonNull List<Cookie> cookies) { cookieStore.put(url, cookies); } @Override public @NonNull List<Cookie> loadForRequest(@NonNull HttpUrl url) { List<Cookie> cookies = cookieStore.get(url); return cookies != null ? cookies : new ArrayList<>(); } }) .build();
- 替换分片表单为普通表单,修正请求头写法:
RequestBody requestBody = new FormBody.Builder() .add("__RequestVerificationToken", veritoken) .add("Q_b9849eb2-813d-4d0a-a1ce-643f1c8af986_0", "test") .add("Q_62ebd8c8-7d45-481d-a8b1-ad54a390a029_0", "test@test.ca") .add("Q_f4a3bb2e-ebab-4660-a9a1-75c0d79fe0b4_0", "") .add("Q_20cd46d1-3b95-46ad-81a3-b7b4d7fe7bf9_0", "b9558536-87d3-4395-aceb-ac3e012b4bad") .add("Q_012d8ddf-e75a-4266-ae78-f59502862aa9_0", "Bay 4") .add("Q_6b61b457-f325-41d7-9784-5cb4a959223f_0", "Superman") .add("FormId", "276caa59-80a5-4ced-9b9d-025e1d753b4a") .add("_ACTION", "Continue") .add("PageIndex", "1") .build(); Request request = new Request.Builder() .addHeader("X-Requested-With", "XMLHttpRequest") .addHeader("Host", host) .addHeader("Origin", origin) .addHeader("Referer", url) .addHeader("__RequestVerificationToken", veritoken) .url(url) .post(requestBody) .build(); // 用配置了CookieJar的client发起请求即可 client.newCall(request).enqueue(new Callback() { // 自行实现请求成功/失败回调逻辑 });
修改后代码逻辑和Python实现完全对齐,即可正常通过CSRF校验。
内容的提问来源于stack exchange,提问作者arian-nasr
相关产品推荐
相关产品推荐

