2

I need to post some data to a django server using popup's js.because of the csrf, I should post data with csrftoken in cookie, how can i get the the value in the cookie. I have tried the following ways which do not work:

document.cookie

chrome.cookies.get({url: "chrome-extension://igmgfjnbghncmhbobdpjblokohejackc", name: "csrftoken"}, function(cookie){})

request infomation:

Request Method:POST
Status Code:403 FORBIDDEN
Request Headersview source
Accept:*/*
Accept-Encoding:gzip, deflate
Accept-Language:zh-CN,zh;q=0.8
Connection:keep-alive
Content-Length:3
Content-Type:application/x-www-form-urlencoded; charset=UTF-8
Cookie:csrftoken=V6OTh2NdwnomqLbkfh24qRwT8C0kESIV
Host:127.0.0.1:8000
Origin:chrome-extension://igmgfjnbghncmhbobdpjblokohejackc
User-Agent:Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X)      AppleWebKit/600.1.3 (KHTML, like Gecko) Version/8.0 Mobile/12A4345d    Safari/600.1.4
X-CSRFToken:null
peterdotjs
  • 1,526
  • 1
  • 13
  • 19
hking
  • 21
  • 1
  • 2

2 Answers2

3

You cannot access the csrftoken cookie from any domain but the one that generated it. So, you have to read the csrftoken when it's generated and save it if you want to use it from your extension.

In my case, when the token was not present, it didn't cause any error, but as soon as I logged in the server, the csrftoken was set, and couldn't retrieve it from any other domain, getting the 403 error on any request that was not generated in the same domain.


To fix it, first, I had to read the cookie from the domain when I logged in and save it to chrome storage. First, I need proper permissions (Note that, where I use background/background.js you could switch to popup/popup.js if needed)

manifest.json

...,
"background": {
    "scripts": ["jquery-1.11.1.min.js","background.js"],
    "persistent": false
  },
"permissions": ["tabs", "<all_urls>", "storage", "webNavigation"],
"content_scripts":[
 {
  "matches":["yourDomain"],
  "js": ["jquery-1.11.1.min.js", "readCSRFToken.js"]
 }],...

Now, this small script will read the cookie we need if it's present and send it to our extension. You could check the host name before sending the cookie if you want to be sure that you take the correct CSRF token.

readCSRFToken.js

function getCookie(name) {
     var cookieValue = null;
     if (document.cookie && document.cookie != '') {
         var cookies = document.cookie.split(';');
         for (var i = 0; i < cookies.length; i++) {
             var cookie = jQuery.trim(cookies[i]);
         if (cookie.substring(0, name.length + 1) == (name + '=')) {
             cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
             break;
         }
     }
 }
 return cookieValue;
}
csrftoken = getCookie("csrftoken");
if ( csrftoken ){
    chrome.runtime.sendMessage({action:"setCsrfToken", csrftoken:csrftoken}, function(){});
}

In the extension code, we add a listener that will save the csrf token in chrome storage when it's sent by the injected code. There is also a webNavigation.onComplete that will read the token from storage every time we load a page.

background.js

csrftoken = null;
chrome.webNavigation.onCompleted.addListener(function(details) {
    if ( details.frameId == 0 ){
         chrome.storage.sync.get(["csrftoken"], function(storage){
            csrftoken = storage.csrftoken;
        });}
    }
);
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
    switch ( request.action ){
        case "setCsrfToken":{
            chrome.storage.sync.set({'csrftoken': request.csrftoken}, function() {});
        }
        break;
    }
});

Finally, we have a csrftoken variable stored that we should be able to use to set the "X-CSRFToken" header to allow our AJAX request to work properly when used from the extension.

   ...
   var headers = {}
   if ( csrftoken ) headers["X-CSRFToken"] = csrftoken;

    $.ajax({                                                                                                                                                                                                                             
     dataType: 'json',                                                                                                                                                                                                               
     headers: headers,
     ...
    });
sergio0983
  • 1,232
  • 8
  • 15
1

I assume you already followed these steps: https://docs.djangoproject.com/en/1.7/ref/contrib/csrf/#how-to-use-it

I'm not familiar with popup.js but since it's a jquery plugin, this should work for you. An ajax request which puts the csrftoken into the request header:

$.ajax({                                                                                                                                                                                                                             
 dataType: 'json',                                                                                                                                                                                                               
 headers: {"X-CSRFToken": $.cookie('csrftoken') },
 ...
}
djangonaut
  • 7,233
  • 5
  • 37
  • 52
  • Yes, I have follwed that doc, in a normal web page, it's ok. but in chrome extension, it does not work. The main problem is how to get csrftoken in cookie in chrome extension, $.cookie('csrftoken') dose not work.In the request infomation above, Cookie:csrftoken=V6OTh2NdwnomqLbkfh24qRwT8C0kESIV, csftoken has existed in cookie, but I can not found a solution to get it. – hking Mar 10 '15 at 04:34
  • Yes, I can get any websites' cookie, like http://example.com. My problem is I can not get my own chrome extension's cookie, like Origin:chrome-extension://igmgfjnbghncmhbobdpjblokohejackc. – hking Mar 10 '15 at 13:59
  • This simple method works when you declare the site and 'cookies' for permission in manifest. No need to follow the answer above. – Imju Dec 08 '15 at 23:02