214 votes

les appels Ajax jQuery et le Html.AntiForgeryToken()

J'ai mis en œuvre dans mon application les mesures d'atténuation des attaques CSRF suivant les informations que j'ai lu sur certains post de blog autour de l'internet. En particulier, ces postes ont été le pilote de ma mise en œuvre

Fondamentalement, ces recommandations et des articles de dit que, pour prévenir l'attaque CSRF tout le monde devrait mettre en œuvre le code suivant:

1) Ajouter l' [ValidateAntiForgeryToken] sur chaque action que d'accepter le POSTE verbe Http

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SomeAction( SomeModel model ) {
}

2) Ajouter l' <%= Html.AntiForgeryToken() %> helper à l'intérieur de formes qui envoie des données au serveur

<div style="text-align:right; padding: 8px;">
    <%= Html.AntiForgeryToken() %>
    <input type="submit" id="btnSave" value="Save" />
</div>

De toute façon, dans certaines parties de mon application que je suis en train de faire de l'Ajax Postes avec jQuery pour le serveur sans avoir n'importe quelle forme à tous. C'est le cas par exemple où je suis, permettant à l'utilisateur de cliquer sur une image pour en faire une action spécifique.

Supposons que j'ai une table avec une liste d'activités. J'ai une image dans une colonne de la table qui dit que "la Marque de l'activité comme terminée" et lorsque l'utilisateur clique sur une activité que je suis en train de faire de l'Ajax POST comme dans l'exemple suivant:

$("a.markAsDone").click(function (event) {
    event.preventDefault();
    $.ajax({
        type: "post",
        dataType: "html",
        url: $(this).attr("rel"),
        data: {},
        success: function (response) {
            // ....
        }
    });
});

Comment puis-je utiliser l' <%= Html.AntiForgeryToken() %> dans ces cas? Dois-je inclure l'aide d'appels à l'intérieur du paramètre de données de l'appel Ajax?

Désolé pour le long post et merci beaucoup de votre aide

EDIT:

Comme par jayrdub réponse que j'ai utilisé de la façon suivante

$("a.markAsDone").click(function (event) {
    event.preventDefault();
    $.ajax({
        type: "post",
        dataType: "html",
        url: $(this).attr("rel"),
        data: {
            AddAntiForgeryToken({}),
            id: parseInt($(this).attr("title"))
        },
        success: function (response) {
            // ....
        }
    });
});

261voto

JeremyWeir Points 9424

J’utilise une fonction js simple comme ceci

Étant donné que chaque formulaire sur une page aura la même valeur pour le jeton, juste mettre quelque chose comme ceci dans votre page maître plus haut

Puis dans votre appel ajax faire (édité pour correspondre à votre deuxième exemple)

32voto

Bronx Points 164

J'aime la solution fournie par 360Airwalk, mais il peut être amélioré un peu.

Le premier problème est que si vous faites $.post() avec les données vide, jQuery n'est pas ajouter un Content-Type - tête, et dans ce cas ASP.NET MVC ne parvient pas à recevoir et vérifier le jeton. Donc, vous avez à assurer l'en-tête est toujours là.

Une autre amélioration de la prise en charge de tous les verbes avec le contenu: POST, PUT, DELETE, etc. Si vous utilisez uniquement des Messages dans votre application, il est préférable d'avoir une solution générique et vérifier que toutes les données que vous recevez avec tout verbe a un effet anti-faux jeton.

$(document).ready(function () {
    var securityToken = $('[name=__RequestVerificationToken]').val();
    $(document).ajaxSend(function (event, request, opt) {
        if (opt.hasContent && securityToken) {   // handle all verbs with content
            var tokenParam = "__RequestVerificationToken=" + encodeURIComponent(securityToken);
            opt.data = opt.data ? [opt.data, tokenParam].join("&") : tokenParam;
            // ensure Content-Type header is present!
            if (opt.contentType !== false || options.contentType) {
                request.setRequestHeader( "Content-Type", opt.contentType);
            }
        }
    });
});

25voto

viggity Points 5342

Je sais qu'il y a beaucoup d'autres réponses, mais cet article est agréable et concise et vous oblige à vérifier l'ensemble de vos HttpPosts, et pas seulement certains d'entre eux:

http://richiban.wordpress.com/2013/02/06/validating-net-mvc-4-anti-forgery-tokens-in-ajax-requests/

Il utilise les en-têtes HTTP au lieu d'essayer de modifier le formulaire de collecte.

Serveur

//make sure to add this to your global action filters
[AttributeUsage(AttributeTargets.Class)]
public class ValidateAntiForgeryTokenOnAllPosts : AuthorizeAttribute
{
    public override void OnAuthorization( AuthorizationContext filterContext )
    {
        var request = filterContext.HttpContext.Request;

        //  Only validate POSTs
        if (request.HttpMethod == WebRequestMethods.Http.Post)
        {
            //  Ajax POSTs and normal form posts have to be treated differently when it comes
            //  to validating the AntiForgeryToken
            if (request.IsAjaxRequest())
            {
                var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];

                var cookieValue = antiForgeryCookie != null
                    ? antiForgeryCookie.Value 
                    : null;

                AntiForgery.Validate(cookieValue, request.Headers["__RequestVerificationToken"]);
            }
            else
            {
                new ValidateAntiForgeryTokenAttribute()
                    .OnAuthorization(filterContext);
            }
        }
    }
}

Client

var token = $('[name=__RequestVerificationToken]').val();
var headers = {};
headers["__RequestVerificationToken"] = token;

$.ajax({
    type: 'POST',
    url: '/Home/Ajax',
    cache: false,
    headers: headers,
    contentType: 'application/json; charset=utf-8',
    data: { title: "This is my title", contents: "These are my contents" },
    success: function () {
        ...
    },
    error: function () {
        ...
    }
});

20voto

Edward Brey Points 8771

Ne pas utiliser Html.AntiForgeryToken . À la place, utilisez AntiForgery.GetTokens et AntiForgery.Validate à partir de l' API Web, comme décrit dans Prévention des attaques CSRF (Cross-Site Request Forgery) .

16voto

360Airwalk Points 1319

je viens de la mise en œuvre de ce réel problème dans mon projet en cours. je l'ai fait pour tous ajax-Postes que nécessaire à un utilisateur authentifié.

Tout d'abord, j'ai décidé d'accrocher mes appels ajax jquery donc je n'ai pas à me répéter trop souvent. ce bout de code javascript s'assure que tous les ajax (post) appels d'ajouter ma validation de la demande de jeton à la demande. Remarque: le nom de __RequestVerificationToken est utilisé par l' .Net framework afin que je puisse utiliser la norme Anti-CSRF fonctions comme indiqué ci-dessous.

$(document).ready(function () {
    securityToken = $('[name=__RequestVerificationToken]').val();
    $('body').bind('ajaxSend', function (elm, xhr, s) {
        if (s.type == 'POST' && typeof securityToken != 'undefined') {
            if (s.data.length > 0) {
                s.data += "&__RequestVerificationToken=" + encodeURIComponent(securityToken);
            }
            else {
                s.data = "__RequestVerificationToken=" + encodeURIComponent(securityToken);
            }
        }
    });
});

Dans votre point de Vue où vous en avez besoin le jeton à la disposition du javascript ci-dessus suffit d'utiliser le commun HTML-Helper. Vous pouvez ajouter ce code où vous le voulez. Je l'ai placé à l'intérieur d'un if(Request.IsAuthenticated):

@Html.AntiForgeryToken() // you can provide a string as salt when needed which needs to match the one on the controller

Dans votre contrôleur de simplement utiliser la norme ASP.Net MVC Anti-CSRF mécanisme. J'ai fait comme ça (même si j'ai effectivement utilisé le Sel).

[HttpPost]
[Authorize]
[ValidateAntiForgeryToken]
public JsonResult SomeMethod(string param)
{
    // do something
    return Json(true);
}

Avec Firebug ou un outil similaire, vous pouvez facilement voir comment votre POST demandes ont maintenant un __RequestVerificationToken paramètre ajouté.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X