2013-07-08 19 views
5

Sto lavorando a una semplice applicazione per giochi di parole multiplayer in Django (1.5). Seguendo l'esempio here, sto utilizzando un server Node.js e Socket.io separati per gestire le connessioni client.Passaggio del token CSRF da Node.js a Django

La mia domanda si scompone in due parti:

  1. Il tutorial sopra usa @csrf_exempt per la vista API. Poiché il POST non proviene dal client, ma dal server Node.js su localhost, a cosa sono esattamente esposto non utilizzando la protezione CSRF per questa vista?

  2. Siccome non sono sicuro di quanto sopra, mi piacerebbe utilizzare la protezione CSRF. Ho provato ad estrarre il token CSRF dal cookie fornito da Django (come suggerito da the docs) e inviarlo insieme al POST, ma ottengo comunque una risposta 403.

game_server.js:

io.configure(function() { 
    io.set('authorization', function (data, accept) { 
     if (data.headers.cookie) { 
      data.cookie = cookie_reader.parse(data.headers.cookie); 
      return accept(null, true); 
     } 
     return accept('error', false); 
    }); 
    io.set('log level', 1); 
}); 

io.sockets.on('connection', function (socket) { 

    socket.on('check_word', function (data) { 
     values = querystring.stringify({ 
      word: data, 
      sessionid: socket.handshake.cookie['sessionid'] 
     }); 

     var options = { 
      host: 'localhost', 
      port: 8000, 
      path: '/node/check_word', 
      method: 'POST', 
      headers: { 
       'X-CSRFToken': socket.handshake.cookie['csrftoken'], 
       'Content-Type': 'application/x-www-form-urlencoded', 
       'Content-Length': values.length 
      } 
     }; 

     var req = http.request(options, function (res) { 
      res.setEncoding('utf8'); 

      res.on('data', function (message) { 
       if (message) { 
        console.log(message); 
       } 
      }); 
     }); 

     req.write(values); 
     req.end(); 
    }); 
}); 

game.html (quota di script solo):

(function ($) { 
    var socket = io.connect('localhost', { port: 4000 }); 

    socket.on('connect', function() { 
    console.log("connected"); 
    }); 

    word_el = $('#word-input'); 

    word_el.keypress(function (event) { 
    if (event.keyCode === 13) { 
     // Enter key pressed 
     var word = word_el.attr('value'); 
     if (word) { 
     socket.emit('check_word', word, function (data) { 
      console.log(data); 
     }); 
     } 

     word_el.attr('value', ''); 
    } 
    }); 
})(jQuery); 

views.py:

@ensure_csrf_cookie 
def check_word(request): 
    return HttpResponse("MATCH:" + request.POST.get('word')) 

Tutta la comprensione sarebbe molto apprezzato!

risposta

2

Dopo un bel po 'di ricerca e sperimentazione, ho risolto il problema.

I miei risultati:

  1. In questo particolare caso, CSRF non mi esporre a qualsiasi attacco significativo. In teoria apre una strada per imbrogliare nel gioco, ma questa è una grande difficoltà (richiede la fabbricazione di ID di sessione e il targeting di una partita attualmente in corso) per una ricompensa pari a zero. Tuttavia, in altre applicazioni come la chat, una vulnerabilità di CSRF consente a qualcuno di impersonare un altro utente, il che è un problema più importante. E così scaviamo più a fondo ...

  2. Il mio tentativo originale di risolvere il problema tramite le intestazioni AJAX è stato un errore. Per uno, la richiesta non è in realtà su AJAX. (request.is_ajax() restituisce False all'interno della vista.) In secondo luogo, la pagina di errore ricevuta da Django cita CSRF cookie not set come motivo dell'errore.

Tutto che si accumula alla soluzione:

var options = { 
    // snip... 
    headers: { 
     'Cookie': 'csrftoken=' + socket.handshake.cookie['csrftoken'], 
     'Content-Type': 'application/x-www-form-urlencoded', 
     'Content-Length': values.length 
    } 
}; 

Aggiungere la corretta 'Cookie' intestazione, e la richiesta riesce.