【问题标题】:Android sending post requests to django server csrf failingAndroid向django服务器csrf发送post请求失败
【发布时间】:2012-02-12 20:25:22
【问题描述】:

我希望我的 android 应用能够向我的 django 服务器发送一些信息。所以我让 android 应用程序向 mysite/upload 页面发送一个发布请求,并且 django 对该页面的视图将根据发布数据工作。问题是服务器对发布请求的响应抱怨 csrf 验证失败。调查这个问题似乎我可能必须先从服务器获取一个 csrf 令牌,然后使用该令牌进行发布但我不确定我是如何做到这一点的。编辑:我发现我可以使用视图装饰器 @csrf_exempt 取消此视图的 crsf 验证,但我不确定这是否是最佳解决方案。我的安卓代码:

// Create a new HttpClient and Post Header
                    HttpClient httpclient = new DefaultHttpClient();
                    HttpPost httppost = new HttpPost(URL);

                    // Add your data
                    List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
                    nameValuePairs.add(new BasicNameValuePair("scoreone", scoreone));
                    nameValuePairs.add(new BasicNameValuePair("scoretwo", scoretwo));
                    httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
                    System.out.println("huzahhhhhhh");
                    // Execute HTTP Post Request
                    HttpResponse response = httpclient.execute(httppost);
                    BufferedReader in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
                    StringBuffer sb = new StringBuffer("");
                    String line = "";
                    String NL = System.getProperty("line.separator");
                    while ((line = in.readLine()) != null) {
                        sb.append(line + NL);
                    }
                    in.close();
                    String result = sb.toString();
                    System.out.println("Result: "+result);

以及我处理上传的观点代码:

# uploads a players match
def upload(request):
    if request.method == 'POST':
        scoreone = int(request.POST['scoreone'])
        scoretwo = int(request.POST['scoretwo'])
        m = Match.objects.create()
        MatchParticipant.objects.create(player = Player.objects.get(pk=1), match = m, score = scoreone)
        MatchParticipant.objects.create(player = Player.objects.get(pk=2), match = m, score = scoretwo)
    return HttpResponse("Match uploaded" )

enter code here

【问题讨论】:

  • 我收到 403 错误,我也在做同样的事情。如果你解决了错误,你能帮我吗?

标签: android django post request


【解决方案1】:

首先,您需要从预览请求的 cookie 中读取 csrf 令牌:

httpClient.execute(new HttpGet(uri));
CookieStore cookieStore = httpClient.getCookieStore();
List <Cookie> cookies =  cookieStore.getCookies();
for (Cookie cookie: cookies) {
    if (cookie.getDomain().equals(Constants.CSRF_COOKIE_DOMAIN) && cookie.getName().equals("csrftoken")) {
        CSRFTOKEN = cookie.getValue();
    }
}

如果您的视图未呈现包含 csrf_token 的模板 模板标签,Django 可能不会设置 CSRF 令牌 cookie。这是 在表单被动态添加到页面的情况下很常见。至 针对这种情况,Django 提供了一个视图装饰器,它强制 cookie 的设置:ensure_csrf_cookie()。 -- https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax

然后你可以在做post请求的时候把它传递给post请求头和cookies上的服务器:

httpPost.setHeader("Referer", Constants.SITE_URL);
httpPost.setHeader("X-CSRFToken", CSRFTOKEN);

DefaultHttpClient client = new DefaultHttpClient();
final BasicCookieStore cookieStore =  new BasicCookieStore();

BasicClientCookie csrf_cookie = new BasicClientCookie("csrftoken", CSRFTOKEN);
csrf_cookie.setDomain(Constants.CSRF_COOKIE_DOMAIN);
cookieStore.addCookie(csrf_cookie);

// Create local HTTP context - to store cookies
HttpContext localContext = new BasicHttpContext();
// Bind custom cookie store to the local context
localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);

HttpResponse response = client.execute(httpPost, localContext);

【讨论】:

  • 我正在做同样的事情,但我收到 403 错误。我已尝试发送 cookie、标头。但我仍然收到相同的错误。
【解决方案2】:

编写自己的装饰器并在您的请求中添加一些“秘密”标头。 https://code.djangoproject.com/browser/django/trunk/django/views/decorators/csrf.py

def csrf_exempt(view_func):
        """
        Marks a view function as being exempt from the CSRF view protection.
        """
        # We could just do view_func.csrf_exempt = True, but decorators
        # are nicer if they don't have side-effects, so we return a new
        # function.
        def wrapped_view(request,*args, **kwargs):
            return view_func(request, *args, **kwargs)
            if request.META.has_key('HTTP_X_SKIP_CSRF'):
                wrapped_view.csrf_exempt = True
        return wraps(view_func, assigned=available_attrs(view_func))(wrapped_view)

【讨论】:

  • 你在这里绕过了安全性。
  • @remus CSRF for Android 应用没有意义。跨站请求伪造是针对经典网页的。 API 的废话。
【解决方案3】:

关闭 CSRF 验证确实有效!但你确定要这样做吗?你原来的思路;从服务器获取令牌并将其与 POST 数据一起发送要好得多。

csrf 令牌通常以 cookie 的形式存在。例如,在 Django 框架中,您有一个名为 csrftoken 的 cookie,您需要获取该值并将其作为“X-CSRFToken”发布到服务器

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-21
    • 1970-01-01
    • 2012-12-12
    • 1970-01-01
    • 2012-09-15
    • 1970-01-01
    相关资源
    最近更新 更多