Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android sending post requests to django server csrf failing

I would like my android app to be able to send some information to my django server. So I made the android app send a post request to the mysite/upload page and django's view for this page would do work based on the post data. The problem is the response the server gives for the post request complains about csrf verication failed. Looking in to the problem it seems I might have to get a csrf token from the server first then do the post with that token But I am unsure how I do this. Edit: I have found out that I can knock off the crsf verification for this view using a view decorator @csrf_exempt but I am not sure if this is the best solution. My android code:

// 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);

and my views code for handling the upload:

# 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
like image 372
Jayyyyy Avatar asked Feb 12 '12 20:02

Jayyyyy


2 Answers

First you need to read the csrf token from the cookies from a preview request:

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();
    }
}

If your view is not rendering a template containing the csrf_token template tag, Django might not set the CSRF token cookie. This is common in cases where forms are dynamically added to the page. To address this case, Django provides a view decorator which forces setting of the cookie: ensure_csrf_cookie(). -- https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax

Then you can pass it to the server on the post request headers and cookies when doing the post request:

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);
like image 161
user2517675 Avatar answered Oct 28 '22 01:10

user2517675


Write own decorator and add some "secret" header to your request. 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)
like image 32
baklarz2048 Avatar answered Oct 28 '22 02:10

baklarz2048