【问题标题】:Can't deal with csrf token between CakePHP and android无法处理 CakePHP 和 android 之间的 csrf 令牌
【发布时间】:2016-04-05 07:11:42
【问题描述】:

我已经阅读了数十篇关于这个主题的帖子,其中大部分都依赖于已弃用的 Android API,我最终尝试使用 this 但没有成功:

所以我得到了这样的 csrftoken:

URL url = new URL(urlString);

HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setUseCaches(false);
urlConnection.setRequestMethod("GET");

if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
    String COOKIES_HEADER = "Set-Cookie";
    site.setCookieManager(new java.net.CookieManager());

    Map<String, List<String>> headerFields = urlConnection.getHeaderFields();
    List<String> cookiesHeader = headerFields.get(COOKIES_HEADER);

    if(cookiesHeader != null)
    {
        for (String cookie : cookiesHeader)
        {
            if (cookie.startsWith("csrfToken")) {
                site.getCookieManager().getCookieStore().add(null, HttpCookie.parse(cookie).get(0));
            }
        }
    }

    urlConnection.disconnect();
} else {
    urlConnection.disconnect();
    return null;
}

我也尝试从标题中获取所有信息,但它并没有改变事情。

然后,在发帖请求期间,我像这样插入令牌:

urlConnection = (HttpURLConnection) url.openConnection();

if(site.getCookieManager().getCookieStore().getCookies().size() > 0)
{
    urlConnection.setRequestProperty("Cookie",
            TextUtils.join(";", site.getCookieManager().getCookieStore().getCookies()));
}

if ((params != null) && !params.isEmpty()) {
    urlConnection.setDoOutput(true);
    urlConnection.setChunkedStreamingMode(0);
    urlConnection.setRequestProperty("Accept-Charset", "UTF-8");
    urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + "UTF-8");

    OutputStream output = urlConnection.getOutputStream();
    output.write(params.getBytes("UTF-8"));
    output.close();
}

is = urlConnection.getInputStream();

所以如果我查看 urlconnection 数据,我可以看到:

requestHeaders
    nameAndValues
        0 = "Cookie"
        1 = "csrkToken=5f62......973"
        2 = "Accept-Charset"
        3 = "UTF-8"
        4 = "Content-Type"
        5 = "application/x-www-form-urlencoded;charset=UTF-8"

但是当我执行urlConnection.getInputStream() 时,我得到以下异常:

java.io.FileNotFoundException: http://my.example.com/mywebservice
    at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:238)
    at com.ndguide.ndguide.JSONParser.getJSONFromUrl(JSONParser.java:93)
    at com.ndguide.ndguide.MainActivity.sendRegistrationIdToBackend(MainActivity.java:1562)
    at com.ndguide.ndguide.MainActivity.access$600(MainActivity.java:82)
    at com.ndguide.ndguide.MainActivity$2.doInBackground(MainActivity.java:1160)
    at com.ndguide.ndguide.MainActivity$2.doInBackground(MainActivity.java:1122)
    at android.os.AsyncTask$2.call(AsyncTask.java:295)
    at java.util.concurrent.FutureTask.run(FutureTask.java:237)
    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
    at java.lang.Thread.run(Thread.java:818)

能否准确地说,如果我不在服务器端加载 Csrf 组件,一切都会好起来的。

我还尝试在我的应用程序开头添加以下行,因为我在这里阅读,但它会导致相同的异常:

CookieManager cookieManager = new CookieManager();
CookieHandler.setDefault(cookieManager);

那么我的标题有什么问题?

【问题讨论】:

  • csrkToken?另外,请务必提及您正在使用的确切 CakePHP 版本,您说的是 CSRF 组件,因此表示 Cake 3.x,但没有人能真正确定(默认情况下,Cake 3.x 使用长期存在的令牌,而 Cake 2.x 使用长寿命令牌。 x 使用一次性令牌)。
  • @ndm 对不起,CakePHP 3.1 中的 csrfToken。事实上,我遇到了这个问题,因为 csrf 组件中的错误在测试版 AFAIR 中得到了解决。我想我的问题出在 Android 方面,因为我对其他 Web 服务没有任何问题。但是当我发现一些关于该主题的文章没有成功时,我经常尝试解决它。我可以检查 CakePHP csrf 组件中的内容以获取更多信息吗?
  • 那么,csrkToken=5f62......973 中的 k 在这个例子中只是一个错字吗?如果是这样,那么我建议您从调试 CakePHP 端接收的内容开始,即记录请求数据/cookie 转储。

标签: android cakephp cookies csrf httpurlconnection


【解决方案1】:

所以,多亏了 ndm 的建议,我探索了 Csrf 组件的期望,在这里我解释了应该做些什么来完全满足它,因为到目前为止我只找到了部分解释,至少对于像我这样的菜鸟来说是这样。

首先我们必须执行GET 请求以获取 csrf 令牌:

URL url = new URL(urlString);

HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setUseCaches(false); // Don't use a Cached Copy
urlConnection.setRequestMethod("GET");

if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
    String COOKIES_HEADER = "Set-Cookie";
    site.setCookieManager(new java.net.CookieManager());

    Map<String, List<String>> headerFields = urlConnection.getHeaderFields();
    List<String> cookiesHeader = headerFields.get(COOKIES_HEADER);

    if(cookiesHeader != null)
    {
        for (String cookie : cookiesHeader)
        {
            if (cookie.startsWith("csrfToken")) {
                site.getCookieManager().getCookieStore().add(null, HttpCookie.parse(cookie).get(0));
            }
        }
    }
}
urlConnection.disconnect();

然后在您的发布请求中,您必须以多种方式复制回您的 csrf 令牌。这是我错过的:

try {

    HttpURLConnection urlConnection = null;
    InputStream is = null;
    JSONObject jObj = null;

    URL url = new URL(urlString);

    urlConnection = (HttpURLConnection) url.openConnection();

    String csrfToken = null;

    if(site.getCookieManager().getCookieStore().getCookies().size() > 0)
    {
        //While joining the Cookies, use ',' or ';' as needed. Most of the server are using ';'
        urlConnection.setRequestProperty("Cookie",
                TextUtils.join(";", site.getCookieManager().getCookieStore().getCookies()));

        for (HttpCookie cookie : site.getCookieManager().getCookieStore().getCookies()) {
            if (cookie.getName().equals("csrfToken")) {
                csrfToken = cookie.getValue();
                urlConnection.setRequestProperty("X-CSRF-Token", csrfToken);
            }
        }
    }

    if ((params != null) && !params.isEmpty()) { // To put your posts params AND the csrf Cookie
        urlConnection.setDoOutput(true);
        urlConnection.setChunkedStreamingMode(0);
        urlConnection.setRequestProperty("Accept-Charset", "UTF-8");
        urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + "UTF-8");

        OutputStream output = urlConnection.getOutputStream();
        output.write(params.getBytes("UTF-8"));

        if (csrfToken != null) {
            String token = "&csrfToken=" + csrfToken;
            output.write(token.getBytes("UTF-8"));
        }

        output.close();
    } else {
        OutputStream output = urlConnection.getOutputStream();
        output.write(params.getBytes("UTF-8"));

        if (csrfToken != null) {
            String token = "csrfToken=" + csrfToken;
            output.write(token.getBytes("UTF-8"));
        }

        output.close();

    }

    is = urlConnection.getInputStream();

    int status = urlConnection.getResponseCode();

    if (status == HttpURLConnection.HTTP_OK) {

        /**
         * Do your job
         */

    }

} catch (IllegalArgumentException | NullPointerException | UnsupportedEncodingException | SocketTimeoutException | IOExceptione) {
    e.printStackTrace();
} finally {
    if(is != null) {
        is.close();
    }
    urlConnection.disconnect();
}

希望这会有所帮助。

【讨论】:

  • 这里是什么网站...你能解释一下吗
  • @amity,很酷,站点只是一个全局数据结构。在我的应用程序中。与所需的库无关,否则我不知道还有什么。
  • 您自己创建了站点类吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-02-19
  • 2020-11-14
  • 1970-01-01
  • 2017-04-16
  • 2015-05-21
  • 2013-05-05
  • 1970-01-01
相关资源
最近更新 更多