BoJack Horseman
BoJack Horseman

Reputation: 4450

How to add a csrf token properly in phantomJS

I want to get the content of a website as pdf in phantomJS which is quite easy as described in the phantomJS docs

phantomjs rasterize.js 'http://en.wikipedia.org/w/index.php?title=Jakarta&printable=yes' jakarta.pdf

So far so good. What my problem at the moment is, is that the webpage that I want print as pdf requires a user which is logged in and posts a form which contains 2 input fields! The input fields are a start and an end date which generates the outcome of the desired website which shall be printed as pdf later on. The site is written in Django and by default requires a csrf token. I wrote this code which doesn't work and even if it would, wouldn't help me because I can't use it with the help of rasterize to convert the page content into a pdf.

"use strict"
var page = require('webpage').create(),
    server = 'http://10.0.3.201:8000/report/',
    data = 'start_date=23.03.2016&end_date=24.03.2016';

page.settings.userName = 'ubuntu';
page.settings.password = 'ubuntu';

page.includeJS(
    // Include the http version, you can change this to http if you like.
    'https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js',
    function() {
        (page.evaluate(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]);
                    // Does this cookie string begin with the name we want?
                    if (cookie.substring(0, name.length + 1) == (name + '=')) {
                        cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                        break;
                    }
                }
            }
            return cookieValue;
        }
        phantom.addCookie({
            'name'      : 'csrf',
            'value'     : getCookie('csrftoken'),
            'domain'    : 'localhost',
            'path'      : 'report',
            'httponly'  : true,
            'secure'    : false,
            'expires'   : (new Date()).getTime() + (1000 * 60 * 60)
        });
        )
    }
);

page.open(server, 'post', data, function(status) {
    if (status !== 'success') {
        console.log('Unable to post!');
    } else {
        console.log(page.content);
    }
    phantom.exit();
});

I am super clueless and don't even know if what I want to do is possible with phantomJS. Help is highly appreciated!

Upvotes: 3

Views: 894

Answers (1)

jlvaquero
jlvaquero

Reputation: 8785

Django set a cookie (and in the DOM inside the Forms if its configured in the POST templates) with the csrf token in every GET but this cookie is not used to validate the POST request in the server (this would lead to a security hole).

Django seems to read csrf token from standard POST body (Form data) or from a custom HTTP header named X-CSRFToken.

So, to forge a valid request you have to emulate standard user interaction:

  • Make a GET to the page that creates the csfr token for the POST you need (could be the same page in autopostback or another page with FormAction="postDestination"). This response will come with a csrf token inside Form DOM and in a cookie.
  • Get the csrf token from the cookie or DOM
  • Forge a valid POST request setting the token in Form data request and/or custom header.
  • You should recive a success response that could be rendered to pdf.

If rasterize.js doesn't allow any step above you will need to create your custom rasterize.js.

Anyway, your POST does not seem to modify anything in your system, it looks like a search so I think you can disable csrf just for this POST.

Upvotes: 3

Related Questions