2013-07-08 43 views
5

我正在研究Django(1.5)中的一个简单的多人游戏文字游戏应用程序。遵循示例here,我使用单独的Node.js服务器和Socket.io来管理客户端连接。将Node.js中的CSRF令牌传递给Django

我的问题分解成两个部分:

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

  2. 由于我不确定上述情况,我想使用CSRF保护。我试图从Django提供的cookie(如the docs建议的)中提取CSRF标记并将其与POST一起发送,但仍得到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(脚本部分只):

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

任何了解会大大不胜感激!

回答

2

经过一段时间的研究和实验后,我已经解决了这个问题。

我的发现:

  1. 在这种特别情况下,CSRF不公开我的任何有意义的攻击。理论上它为游戏中的作弊开辟了一条途径,但这是一个很大的困难(需要制作会话ID并针对目前正在进行的游戏),以获得零奖励。但是,在其他应用程序(如聊天)中,此处的CSRF漏洞允许某人冒充另一个用户,这是一个更重要的问题。所以我们深入挖掘...

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

所有这些都建立起到该溶液中:

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

添加适当'Cookie'报头,并且请求成功。