2013-07-08 83 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'報頭,並且請求成功。