2012-06-26 6 views
20

Ich versuche den CSRF-Schutz in einer App zu implementieren, die mit node.js unter Verwendung des express.js-Frameworks erstellt wurde. Die App nutzt reichlich Ajax-Post-Aufrufe an den Server. Ich verstehe, dass das connect-Framework CSRF-Middleware bereitstellt, aber ich bin mir nicht sicher, wie ich es im Rahmen der clientseitigen Ajax-Postanforderungen implementieren soll.Wie implementiert man CSRF-Schutz in Ajax-Aufrufen mit express.js (Suche nach einem vollständigen Beispiel)?

Es gibt Bits und Stücke darüber in anderen Fragen hier in Stackoverflow gepostet, aber ich habe noch ein einigermaßen vollständiges Beispiel finden, wie es von Client- und Server-Seiten zu implementieren.

Hat jemand ein funktionierendes Beispiel, das sie teilen möchten, wie man das umsetzt? Die meisten der Beispiele, die ich gesehen habe, gehen davon aus, dass Sie das Formular serverseitig rendern und es dann (zusammen mit dem eingebetteten Formularfeld csrf_token) an die Clientseite senden. In meiner App werden alle Inhalte auf der Client-Seite (einschließlich Vorlagen) über Backbone.js gerendert. Der gesamte Server stellt Werte im JSON-Format bereit, die von verschiedenen Modellen in Backbone.js auf der Clientseite verwendet werden. Durch mein Verständnis würde ich das csrf_token zuerst über Ajax abrufen müssen, bevor es verwendet werden kann. Ich bin jedoch besorgt, dass dies vom Standpunkt der Sicherheit aus problematisch sein könnte. Ist das ein berechtigtes Anliegen?

Antwort

6

server.js

... 
// All Cookies/Sessions/BodyParser go first 
app.use(express.csrf()); 
... 
// Get the request 
app.post('/ajax', function(req, res){ 
    res.render('somelayout', {csrf_token: req.session._csrf}); 
}); 

In somelayout.jade

input(type='hidden', name='_csrf', value=csrf_token) 

Die einzige CSRF-Middleware die csrf Token einmal pro Sitzung erzeugt, so wird es für die Dauer wahrscheinlich nicht von einem Besuch des Benutzers ändern .

Es prüft auch nicht auf das Token auf GET und HEAD Anfragen. Solange das Token in der Anfrage ist (Header, Body oder Query), sind Sie gut. Das ist so ziemlich alles.

+3

Danke für die schnelle Antwort. In meiner App werden alle clientseitigen Inhalte über Ajax ausgeführt. Das tatsächliche Rendern von Inhalten (einschließlich Vorlagen) wird auf der Client-Seite durchgeführt. Der gesamte Server stellt variable Daten für die Clientseite im JSON-Format bereit. Dies würde bedeuten, dass ich das CSRF-Token über Ajax zurückholen muss, um es in die Seite zu rendern, so dass es dann in der Ajax-Post-Anfrage zurückgeschickt werden kann. Ich bin besorgt, dass dies vom Standpunkt der Sicherheit aus problematisch sein könnte. Ist das ein berechtigtes Anliegen? – Benjen

+0

Wenn Sie können, ist es ein guter Weg, CSRF zum Client zu bekommen, es in einem Meta-Tag (a la Rails) oder etwas Ähnlichem von Express zu rendern. –

3

Da Sie Backbone.js für Ihre Anwendung verwenden, gehe ich davon aus, dass es ein SPA ist und Sie zuerst eine index.html Datei laden, dann machen Sie alle anderen Anfragen über ajax Anrufe. Wenn ja, können Sie Ihrer Datei index.html ein kleines Snippet mit JS-Code hinzufügen, um das crsf-Token für alle zukünftigen ajax-Aufrufe zu speichern.

Zum Beispiel:

index.html (Lenker für Templating mit ...)

<!DOCTYPE html> 
<html> 
    <head> 
     ... 
     <script type="text/javascript"> 
      $(function() { 
       window.Backbone.csrf = "{{csrfToken}}"; 
      }); 
     </script> 
    </head> 
    <body> 
     ... 
    </body> 
</html> 

Wenn Sie die Datei index.html machen, geben sie die csrf Token dass die ausdrückliche Rahmen hier erzeugt Wenn Sie Backbone.js verwenden, wird eine globale Variable mit dem Namen Backbone festgelegt. Alles, was die vorherige Funktion tut, ist das Setzen einer Eigenschaft namens csrf auf das globale Objekt Backbone. Und wenn Sie einen ajax Anruf an POST Daten machen, fügen Sie einfach die Backbone.csrf Variable zu den Daten als _csrf, die über die ajax Aufruf gesendet wird.

31

Es kann durch das Hinzufügen meta Tag für CSRF-Token und dann passieren CSRF-Token mit jedem Ajax-Request

Server

hinzufügen CSRF Middle

app.use(express.csrf()); 
app.use(function (req, res, next) { 
    res.locals.token = req.session._csrf; 
    next(); 
}); 

Sie können einen CSRF-Token passieren erfolgen die Client-Seite über, sagen wir, ein Meta-Tag. Für die Ex, in Jade

meta(name="csrf-token", content="#{token}") 

Kunden

hat jQuery eine Funktion namens ajaxPrefilter, mit dem Sie einen Rückruf zur Verfügung stellen kann, um jeden Ajax-Request aufgerufen werden. Dann setze einen Header mit ajaxPrefilter.

var CSRF_HEADER = 'X-CSRF-Token'; 

var setCSRFToken = function (securityToken) { 
    jQuery.ajaxPrefilter(function (options, _, xhr) { 
    if (!xhr.crossDomain) { 
     xhr.setRequestHeader(CSRF_HEADER, securityToken); 
    } 
    }); 
}; 

setCSRFToken($('meta[name="csrf-token"]').attr('content')); 
+1

wahrscheinlich die beste Antwort hier – FRD

+1

sollte dies angenommen werden Antwort – user3658423

+3

stimme ich nicht zu. Es ist eine gute Antwort, aber es befasst sich nicht mit dem Mangel an Server-Side-Rendering. Es erwähnt die Verwendung von Jade, um ein Meta-Tag auf der Seite zu rendern. Der Wert dieses Tags muss jedoch serverseitig generiert werden, und da der ursprüngliche Asker angibt, dass keine seiner Ansichten serverseitig generiert wird, funktioniert dies nicht. – Bill

1

In Server:

app.use(function (req, res) { 
    res.locals._csrf = req.csrfToken(); 
    res.locals.csrf_form_html = '<input type="hidden" name="_csrf" value="' + req.csrfToken() + '" >'; 
    req.next(); 
}); 

In Auftraggeber: (swig template)

var csrf = {{ _csrf|json|safe }}; 

$.ajaxSetup({ 
    headers: { 
    'X-CSRF-Token': csrf 
    } 
}); 

$.post("/create", data, function(result) { 
    console.log(result); 
}).fail(function(){ 
    console.log(arguments); 
}); 
+0

Wie validieren Sie das Token auf der Serverseite? –

0

1. hinzufügen csrf Schutz Middleware:

app.use(csrf({cookie: true})); 

// csrf middleware 
app.use(function (req, res, next) { 
    res.cookie('X-CSRF-Token', req.csrfToken()); 
    // this line below is for using csrfToken value in normal forms (as a hidden input) 
    res.locals.csrfToken = req.csrfToken(); 
    next(); 
}); 

// routing setup goes here 

2. hinzufügen beforeSend Rückruf $.ajaxSetup mit: (hinzufügen, um dieses irgendwo vor allen Ajax-Aufrufe)

$.ajaxSetup({ 
beforeSend: function (xhr, settings) { 
    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; 
    } 

    if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) { 
     // Only send the token to relative URLs i.e. locally. 
     xhr.setRequestHeader("X-CSRF-Token", getCookie('X-CSRF-Token')); 
    } 
} 
}); 

3. Das ist es! Jetzt können Sie Ajax-Anfragen senden, und Sie müssen nichts in Kopfzeilen oder als Anforderungsparameter hinzufügen, um csrf zu passieren.