Подтвердить что ты не робот

Использование MVC HtmlHelper из WebForm

Я собираюсь добавить некоторые функции пользовательского интерфейса к гибридному сайту WebForms/MVC. В этом случае я добавляю некоторые функции интерфейса AJAX на страницу WebForms (через jQuery), и данные поступают из MVC JsonResult. Все работает на 100%, за одним исключением:

Я хотел бы реализовать XSRF-защиту AntiForgeryToken. Я использовал его в сочетании с атрибутом ValidateAntiForgeryToken в моих чистых приложениях MVC, но хотел бы знать, как реализовать метод Html.AntiForgeryToken() в WebForms. Вот пример использования UrlHelper.

У меня возникли проблемы с правильной обработкой ViewContext/RequestContext. Как мне использовать HtmlHelpers на странице WebForms?

Edit: Я ищу, чтобы получить AntiForgeryToken со страницы WebForms, а не из MVC JsonResult.

4b9b3361

Ответ 1

Ключевым методом является исходный код MVC: GetAntiForgeryTokenAndSetCookie

Это создает экземпляр внутреннего закрытого класса с именем AntiForgeryData.

Экземпляр сериализуется в файл cookie "__RequestVerificationToken_" + базовая кодировка версии приложения.

Тот же экземпляр AntiForgeryData сериализуется в скрытый ввод.

Уникальная часть AntiForgeryData получена с помощью RNGCryptoServiceProvider.GetBytes()

Все это может быть подделано на странице WebForms, единственным беспорядочным битом является сериализация скрытого закрытого класса. К сожалению, ключевой метод (GetAntiForgeryTokenAndSetCookie) полагается на ViewContext.HttpContext.Request для получения файлов cookie, тогда как WebForm должен использовать HttpContext.Current.Request.


Обновление

Не много тестирования и много кода, но я думаю, что я немного взломал его. Где я использовал отражение, я оставил эквивалентную строку, прокомментированную выше:

using System;
using System.Reflection;
using System.Web;
using System.Web.Mvc;

/// <summary>Utility to provide MVC anti forgery tokens in WebForms pages</summary>
public class WebFormAntiForgery
{
    /// <summary>Create an anti forgery token in a WebForms page</summary>
    /// <returns>The HTML input and sets the cookie</returns>
    public static string AntiForgeryToken()
    {
        string formValue = GetAntiForgeryTokenAndSetCookie();

        // string fieldName = AntiForgeryData.GetAntiForgeryTokenName(null);
        var mvcAssembly = typeof(HtmlHelper).Assembly;
        var afdType = mvcAssembly.GetType("System.Web.Mvc.AntiForgeryData");
        string fieldName = Convert.ToString(afdType.InvokeMember(
            "GetAntiForgeryTokenName",
            BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod,
            null,
            null,
            new object[] { null }));

        TagBuilder builder = new TagBuilder("input");
        builder.Attributes["type"] = "hidden";
        builder.Attributes["name"] = fieldName;
        builder.Attributes["value"] = formValue;
        return builder.ToString(TagRenderMode.SelfClosing);
    }

    static string GetAntiForgeryTokenAndSetCookie()
    {
        var mvcAssembly = typeof(HtmlHelper).Assembly;
        var afdType = mvcAssembly.GetType("System.Web.Mvc.AntiForgeryData");

        // new AntiForgeryDataSerializer();
        var serializerType = mvcAssembly.GetType("System.Web.Mvc.AntiForgeryDataSerializer");
        var serializerCtor = serializerType.GetConstructor(new Type[0]);
        object serializer = serializerCtor.Invoke(new object[0]); 

        // string cookieName = AntiForgeryData.GetAntiForgeryTokenName(HttpContext.Current.Request.ApplicationPath);
        string cookieName = Convert.ToString(afdType.InvokeMember(
            "GetAntiForgeryTokenName",
            BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod,
            null,
            null,
            new object[] { HttpContext.Current.Request.ApplicationPath }));

        // AntiForgeryData cookieToken;
        object cookieToken;
        HttpCookie cookie = HttpContext.Current.Request.Cookies[cookieName];
        if (cookie != null)
        {
            // cookieToken = Serializer.Deserialize(cookie.Value);
            cookieToken = serializerType.InvokeMember("Deserialize", BindingFlags.InvokeMethod, null, serializer, new object[] { cookie.Value });
        }
        else
        {
            // cookieToken = AntiForgeryData.NewToken();
            cookieToken = afdType.InvokeMember(
                "NewToken",
                BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod,
                null,
                null,
                new object[0]);

            // string cookieValue = Serializer.Serialize(cookieToken);
            string cookieValue = Convert.ToString(serializerType.InvokeMember("Serialize", BindingFlags.InvokeMethod, null, serializer, new object[] { cookieToken }));

            var newCookie = new HttpCookie(cookieName, cookieValue) { HttpOnly = true };

            HttpContext.Current.Response.Cookies.Set(newCookie);
        }

        // AntiForgeryData formToken = new AntiForgeryData(cookieToken)
        // {
        //     CreationDate = DateTime.Now,
        //     Salt = salt
        // };
        var ctor = afdType.GetConstructor(new Type[] { afdType });
        object formToken = ctor.Invoke(new object[] { cookieToken });

        afdType.InvokeMember("CreationDate", BindingFlags.SetProperty, null, formToken, new object[] { DateTime.Now });
        afdType.InvokeMember("Salt", BindingFlags.SetProperty, null, formToken, new object[] { null });

        // string formValue = Serializer.Serialize(formToken);
        string formValue = Convert.ToString(serializerType.InvokeMember("Serialize", BindingFlags.InvokeMethod, null, serializer, new object[] { formToken }));
        return formValue;
    }
}

Использование тогда похоже на MVC:

WebFormAntiForgery.AntiForgeryToken()

Он создает тот же файл cookie и тот же HTML, что и методы MVC.

Я не беспокоился о солевых и доменных методах, но их было бы довольно легко добавить.

Ответ 2

Я знаю, что это старый вопрос, но сегодня я столкнулся с этой проблемой и подумал, что поделюсь ею. Я работаю в MVC4 и имею элемент управления webform (.ascx), который делится между MVC (через RenderPartial) и WebForms. В этом контроле мне нужен токен антифургоризации. К счастью, теперь у вас теперь есть помощник, который можно использовать в ваших веб-формах, так же просто:

<%= AntiForgery.GetHtml() %>

Это сделает ваш токен анти-подделки, как вы бы получили в MVC.

Здесь ссылка MS на него.

Ответ 3

По умолчанию ASP.NET WebForms уже включает в себя меры по проверке событий и viewstate. Фил Хаак рассказывает немного об этом в связанном сообщении. Стратегии смягчения XSRF обсуждаются здесь здесь (Scott Hanselman) и здесь ( Дино Эспозито)

Ответ 4

вы можете создать новый HtmlHelper в своем контроллере, а затем вытащите анти-xrsf:

var htmlHelper = new HtmlHelper(
    new ViewContext(
        ControllerContext, 
        new WebFormView("omg"), 
        new ViewDataDictionary(), 
        new TempDataDictionary()), 
        new ViewPage());

var xsrf = htmlHeler.AntiForgeryToken;

myObject.XsrfToken = xsrf;

return JsonResult(myObject);