将CSRF令牌从Node.js传递到Django

时间:2013-07-08 16:49:50

标签: javascript django socket.io csrf

我正在Django(1.5)开发一个简单的多人游戏应用程序。在示例here之后,我使用单独的Node.js服务器和Socket.io来管理客户端连接。

我的问题分为两部分:

  1. 上面的教程使用@csrf_exempt作为API视图。由于POST不是来自客户端,而是来自Node.js服务器而不是本地主机,因此对于此视图不使用CSRF保护我到底接触到了什么?

  2. 由于我不确定上述内容,我想使用CSRF保护。我试图从Django提供的cookie中提取CSRF令牌(由the docs建议)并将其与POST一起发送,但我仍然得到403响应。

  3. 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(仅限脚本部分):

    (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'))
    

    非常感谢任何见解!

1 个答案:

答案 0 :(得分:2)

经过一番研究和实验,我已经解决了这个问题。

我的发现:

  1. 在此特定案例中,CSRF不会让我受到任何有意义的攻击。从理论上讲,它为游戏中的作弊打开了一条路线,但这是一个很大的困难(需要制作会话ID并针对当前正在进行的游戏)以获得零奖励。但是,在其他应用程序(如聊天)中,此处的CSRF漏洞允许某人冒充其他用户,这是一个更重要的问题。所以我们深入挖掘......

  2. 我最初尝试通过AJAX标头解决问题是一个错误。首先,请求实际上并未通过AJAX。 (request.is_ajax()在视图中返回False。)其次,从Django收到的错误页面引用CSRF cookie not set作为失败的原因。

  3. 所有这些都构建了解决方案:

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

    添加正确的'Cookie'标头,请求成功。