【问题标题】:Android HttpUrlConnection Cannot Post - Error 403Android HttpUrlConnection 无法发布 - 错误 403
【发布时间】:2015-11-12 15:00:42
【问题描述】:

我正在尝试使用 spring security csrf 针对我的 web 服务发出 HttpPost。

首先,我正在尝试通过 GET 请求恢复 XSRF TOKEN,就像这样

public static CookieManager xcsrfToken() throws IOException{
    String token;
    URL url = new URL(urlBase);
    HttpURLConnection con = (HttpURLConnection) url.openConnection();
    con.setRequestMethod("GET");
    CookieManager cookieManager = new CookieManager();
    con.connect();

    List<String> cookieHeader = con.getHeaderFields().get("Set-Cookie");

    if (cookieHeader != null) {
        for (String cookie : cookieHeader) {
            cookieManager.getCookieStore().add(null, HttpCookie.parse(cookie).get(0));
        }
    }
    System.out.println(con.getHeaderFields());
    con.disconnect();

    return cookieManager;
}

这是我从 con.getHeaderFields() 得到的

{null=[HTTP/1.1 200 OK], Cache-Control=[no-cache, no-store, max-age=0, must-revalidate], Content-Language=[pt-BR], Content-Length=[973], Content-Type=[text/html;charset=ISO-8859-1], Date=[Wed, 19 Aug 2015 10:40:18 GMT], Expires=[0], Pragma=[no-cache], Server=[Apache-Coyote/1.1], Set-Cookie=[JSESSIONID=6C9326FBEEA14752068720006F2B5EAA; Path=/webapi/; HttpOnly, XSRF-TOKEN=07cbed7f-834e-4146-8537-0a6b5669f223; Path=/], X-Android-Received-Millis=[1439980819720], X-Android-Response-Source=[NETWORK 200], X-Android-Sent-Millis=[1439980819693], X-Content-Type-Options=[nosniff], X-Frame-Options=[DENY], X-XSS-Protection=[1; mode=block]}

XSRF-TOKEN 在我的 cookie 中,好的! 如果我打印然后 System.out.println(cookieManager.getCookieStore().getCookies()); 我得到了这个

[JSESSIONID=5B1D3E2D3E7B3E1E6572A3839BFF3741, XSRF-TOKEN=4d4048bd-f21c-48c6-895e-5f67523ad963]

现在,我正在尝试向服务器发出 POST,就像这样

public static HttpURLConnection makeRequest(String metodo, String uri, String requestBody) throws IOException{
    URL url = new URL(urlBase + uri);
    HttpURLConnection con = (HttpURLConnection) url.openConnection();
    con.setRequestMethod("POST");

    con.setDoInput(true);
    con.setDoOutput(!metodo.equals("GET"));
    con.setRequestProperty("Content-Type", "application/json");
    con.setRequestProperty("Cookie", TextUtils.join("," , xcsrfToken().getCookieStore().getCookies()));

    con.connect();

    InputStream is = con.getErrorStream();
    System.out.println(IOUtils.toString(is, "UTF-8"));

    System.out.println(con.getHeaderFields());

    return con;
}

但是没有 cookie 的标头又回来了

 {null=[HTTP/1.1 403 Forbidden], Cache-Control=[no-cache, no-store, max-age=0, must-revalidate], Content-Language=[en], Content-Length=[1149], Content-Type=[text/html;charset=utf-8], Date=[Wed, 19 Aug 2015 10:42:18 GMT], Expires=[0], Pragma=[no-cache], Server=[Apache-Coyote/1.1], X-Android-Received-Millis=[1439980939827], X-Android-Response-Source=[NETWORK 403], X-Android-Sent-Millis=[1439980939811], X-Content-Type-Options=[nosniff], X-Frame-Options=[DENY], X-XSS-Protection=[1; mode=block]}

它说没有 CSRF 有效令牌

Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-XSRF-TOKEN'.

在我的网络服务中,由于 angularJs,令牌被配置为重命名为 XSRF-TOKEN。

解决方案

public static void getTokens() throws IOException{
    URL url = new URL(urlBase);
    HttpURLConnection con = (HttpURLConnection) url.openConnection();
    con.setRequestMethod("GET");
    con.connect();
    cookieManager = new CookieManager();

    List<String> cookieHeader = con.getHeaderFields().get("Set-Cookie");

    if (cookieHeader != null) {
        for (String cookie : cookieHeader) {
            String[] tokens = TextUtils.split(cookie, "=");
            if (tokens[0].equals("JSESSIONID"))
                cookieManager.getCookieStore().add(null, HttpCookie.parse(cookie).get(0));
            if (tokens[0].equals("XSRF-TOKEN")) {
                String[] tokenValue = TextUtils.split(tokens[1],";");
                xsrfTOKEN = tokenValue[0];
            }
        }
    }

    con.disconnect();
}

然后,将其附加到 HttpUrlConnection

con.setRequestProperty("X-XSRF-TOKEN", xsrfTOKEN);

【问题讨论】:

  • 发送xcsrfToken().getCookieStore().getCookies() 到 logcat 会打印什么?
  • 这个,[JSESSIONID=5B1D3E2D3E7B3E1E6572A3839BFF3741,XSRF-TOKEN=4d4048bd-f21c-48c6-895e-5f67523ad963]
  • cookie 应该在请求上由 ; 分隔。也许这就是错误所在?使用像 Charles 这样的反向代理来调试您的 HTTP 请求并即时修改它也是值得的。
  • 我尝试使用分号,但不断收到错误消息。我会寻找反向代理的示例并尝试一下。

标签: android spring spring-security csrf


【解决方案1】:

根据我的经验,我们需要将令牌作为请求标头提交。 Spring 期望它的名字默认为X-CSRF-TOKEN。但是使用 AngularJS 的人通常在 Spring Security 配置中将其更改为 X-XSRF-TOKEN

但是查看您的代码,我无法确定您是否发送了该标头。

如果有帮助,这是我的一个项目中的一个 sn-p(使用 RestAssured):

if (xsrfToken != null && !ctx.getRequestMethod().equals(Method.GET))
    requestSpec.header("X-XSRF-TOKEN", xsrfToken);

【讨论】:

  • 这部分代码是设置 X-XSRF-TOKEN,con.setRequestProperty("Cookie", TextUtils.join("," , xcsrfToken().getCookieStore().getCookies())); 我正在尝试像 Cookie 一样发送它,因为我不知道如何拆分 cookieManager 来发送分开的标题
  • 我对此表示怀疑。我认为它必须作为单独的标头发送。
  • 或者,我认为是请求参数,默认命名为_crsf
猜你喜欢
  • 2013-03-16
  • 1970-01-01
  • 1970-01-01
  • 2017-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多