Comment puis-je récupérer le jeton CSRF à transmettre avec une requête JSON?
Je sais que pour des raisons de sécurité Rails vérifie le jeton CSRF sur tous les types de demandes (y compris JSON/XML).
Je pourrais mettre dans mon contrôleur skip_before_filter :verify_authenticity_token
, mais je perdrais la protection CRSF (déconseillé :-)).
Ce même (toujours pas accepté) réponse suggère de
Récupérez le jeton avec
<%= form_authenticity_token %>
La question est comment? Dois-je faire un premier appel sur l’une de mes pages pour récupérer le jeton, puis ma véritable authentification avec Devise? Ou est-ce une information ponctuelle que je peux obtenir de mon serveur et ensuite utiliser de manière cohérente (jusqu'à ce que je la modifie manuellement sur le serveur lui-même)?
ÉDITER :
Dans Rails 4, j'utilise maintenant ce que @genkilabs suggère dans le commentaire ci-dessous:
protect_from_forgery with: :null_session, if: Proc.new { |c| c.request.format == 'application/json' }
Au lieu de désactiver complètement la sécurité intégrée, toutes les sessions pouvant exister lorsque quelque chose frappe le serveur sans le jeton CSRF sont supprimées.
skip_before_filter :verify_authenticity_token, :if => Proc.new { |c| c.request.format == 'application/json' }
Cela désactive le contrôle CSRF pour les publications/options json correctement marquées comme telles.
Par exemple, dans iOS, définissez les paramètres suivants sur votre NSURLRequest, où "paramètres" sont vos paramètres:
[request setHTTPMethod:@"POST"];
[request setValue:@"application/json"
forHTTPHeaderField:@"content-type"];
[request setValue:@"application/json"
forHTTPHeaderField:@"accept"];
[request setHTTPBody:[NSData dataWithBytes:[parameters UTF8String]
length:[parameters length]]];
Vous pouvez envoyer le jeton CSRF après une connexion réussie à l'aide d'un en-tête personnalisé.
Par exemple, mettez ceci dans vos sessions # create:
response.headers['X-CSRF-Token'] = form_authenticity_token
Exemple d'en-tête de réponse de connexion fournissant le jeton CSRF:
HTTP/1.1 200 OK
Cache-Control: max-age=0, private, must-revalidate
Connection: Keep-Alive
Content-Length: 35
Content-Type: application/json; charset=utf-8
Date: Mon, 22 Oct 2012 11:39:04 GMT
Etag: "9d719d3b9aabd413c3603e04e8a3933d"
Server: WEBrick/1.3.1 (Ruby/1.9.3/2012-10-12)
Set-Cookie: [cut for readability]
X-Csrf-Token: PbtMPfrszxH6QfRcWJCCyRo7BlxJUPU7HqC2uz2tKGw=
X-Request-Id: 178746992d7aca928c876818fcdd4c96
X-Runtime: 0.169792
X-Ua-Compatible: IE=Edge
Ce jeton est valide jusqu'à ce que vous vous connectiez à nouveau ou (déconnectiez-vous si vous le supportez via votre API). Votre client peut extraire et stocker le jeton à partir des en-têtes de réponse de connexion. Ensuite, chaque demande POST/PUT/DELETE doit définir l'en-tête X-CSRF-Token avec la valeur reçue au moment de la connexion.
Exemple d'en-têtes POST) avec le jeton CSRF:
POST /api/report HTTP/1.1
Accept: application/json
Accept-Encoding: gzip, deflate, compress
Content-Type: application/json; charset=utf-8
Cookie: [cut for readability]
Host: localhost:3000
User-Agent: HTTPie/0.3.0
X-CSRF-Token: PbtMPfrszxH6QfRcWJCCyRo7BlxJUPU7HqC2uz2tKGw=
Documentation: form_authenticity_token
En effet, le moyen le plus simple. Ne vous embêtez pas pour changer les en-têtes.
Assurez-vous que vous avez:
<%= csrf_meta_tag %>
dans votre layouts/application.html.erb
Il suffit de faire un champ de saisie caché comme ceci:
<input name="authenticity_token"
type="hidden"
value="<%= form_authenticity_token %>"/>
Ou si vous voulez un post jquery ajax:
$.ajax({
type: 'POST',
url: "<%= someregistration_path %>",
data: { "firstname": "text_data_1", "last_name": "text_data2", "authenticity_token": "<%= form_authenticity_token %>" },
error: function( xhr ){
alert("ERROR ON SUBMIT");
},
success: function( data ){
//data response can contain what we want here...
console.log("SUCCESS, data="+data);
}
});
En gros, lorsque vous postez vos données json, ajoutez simplement un champ authenticity_token valide aux données post
et l'avertissement devrait disparaître ...
J'ai résolu cette erreur de cette façon:
class ApplicationController < ActionController::Base
protect_from_forgery
skip_before_action :verify_authenticity_token, if: :json_request?
protected
def json_request?
request.format.json?
end
end
Source: http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html
Ce qui est inquiétant, c’est que dans Rails 3.2.3 nous recevons maintenant l’avertissement CSRF dans production.log mais la publication n’échoue pas! Je veux qu’elle échoue car elle me protège des attaques. Et vous pouvez ajoutez le jeton csrf avec jquery avant le filtre btw:
Cette réponse c'est mieux.
Vous pouvez conserver la validation CSRF-TOKEN sans effort supplémentaire (le jeton est ajouté) avant tout envoi de XMLHttpRequest. Pas de JQuery, rien rien que copier/coller et rafraîchir.
Ajoutez simplement ce code.
(function() {
var send = XMLHttpRequest.prototype.send,
token = $('meta[name=csrf-token]').attr('content');
XMLHttpRequest.prototype.send = function(data) {
this.setRequestHeader('X-CSRF-Token', token);
return send.apply(this, arguments);
};
}());
J'ai utilisé le ci-dessous. Utiliser include? donc si le type de contenu est application/json; charset = utf-8, alors il fonctionne toujours.
protect_from_forgery with: :null_session, if: Proc.new { |c| c.request.format.include? 'application/json' }
J'ai eu le même problème avec la version suivante de Rails:
gem 'Rails',: git => 'git: //github.com/Rails/rails.git',: branch => '3-2-stable'
J'ai mis à jour à 3.2.2 et tout fonctionne bien pour moi maintenant. :)
gem 'Rails', '3.2.2'
Aussi pour le mode développement/test.
protect_from_forgery with: :exception unless %w(development test).include? Rails.env
Cet avertissement indique que vous utilisez :null_session
, in Rails 4.1 cela fonctionne par défaut si aucun with:
options spécifiées.
protect_from_forgery
J'ai rencontré le même problème ce soir. La raison en est que lorsque vous vous connectez, le dernier jeton csrf n'est plus valide. Ce que j'ai fait était: $("meta[name=csrf-token]").attr('content', '<%= form_authenticity_token %>');
dans votre application/vues/concevez/sessions/create.js.rb.
Maintenant, il a un jeton valide de csrf :) J'espère que cela aide