13

ユーザーがログインせずに投稿できるフォームがあります。ただし、ユーザーの電子メールが認識された場合は、パスワードが必要です。パスワードフォームはAjaxで検証され、成功するとメインフォームが送信されます。どちらの形式にも、有効なAntiForgeryTokenが必要です。

キャッチは、副産物としてのパスワードチェックもユーザーにサインインすることです(クライアントからの要件)。これによりトークンが無効になり、メインフォームを送信できなくなります。

プログラムで新しいトークンを生成しようとしましたが、機能させることができません。

これを解決する方法について何かアイデアはありますか?

最終的解決

この質問は、振り返りを入力するのに役立つことがわかりました。ただし、これが、通常の状況で内部型のハッキングを回避する主な理由です。これは、リリース間でアセンブリ間で型が頻繁にジャグリングされるためです。Bettyが示唆しているように、ILSpyを使用して物事を見つけます。

これが最終的なコードです。

if (signIn)
    FormsAuth.SignIn(user.Email, false);


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

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


string text = HttpContext.Request.Form[fieldName];
object antiForgeryData = serializerType.InvokeMember("Deserialize", BindingFlags.InvokeMethod, null, serializer, new object[] { text });

afdType.GetProperty("Username").SetValue(antiForgeryData, 
    signIn ? user.Email : string.Empty, 
    null);

string newToken = Convert.ToString(serializerType.InvokeMember(
    "Serialize",
    BindingFlags.InvokeMethod,
    null,
    serializer,
    new object[] { antiForgeryData }));

return Content(JsonConvert.SerializeObject(new
                                                {
                                                    success = true,
                                                    newAntiForgeryToken = newToken
                                                }), Constant.JsonContentType);

WebPages2.0のアップグレード

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

        string fieldName = "__RequestVerificationToken";

        var serializerType = mvcAssembly.GetType("System.Web.Helpers.AntiXsrf.AntiForgeryTokenSerializer");
        var serializerCtor = serializerType.GetConstructor(new Type[0]);
        object serializer = serializerCtor.Invoke(new object[0]);


        string text = HttpContext.Request.Form[fieldName];
        string newToken = String.Empty;

        if (!String.IsNullOrEmpty(text))
        {
            object antiForgeryToken = serializerType.InvokeMember("Deserialize", BindingFlags.InvokeMethod, null,
                                                                 serializer, new object[] { text });

            afdType.GetProperty("Username").SetValue(antiForgeryToken,
                                                     signIn ? user.Email : string.Empty,
                                                     null);

            newToken = Convert.ToString(serializerType.InvokeMember(
                "Serialize",
                BindingFlags.InvokeMethod,
                null,
                serializer,
                new[] { antiForgeryToken }));
        }
4

2 に答える 2

4

現在のユーザーは、フォームデータの偽造防止トークンに保存され、ポストバック時に現在のユーザーと比較されます。

Phil Haackがこの投稿で行うのと同じ方法で、postbackでフォームトークンを引き出すことができるはずです。

次に、AntiForgeryDataSerializerクラスを使用してトークンを逆シリアル化し、現在のユーザーを更新し、再度シリアル化して、チェックする前にフォームに戻します。または、独自の属性を使用して、validateメソッドを完全に置き換えます。

または、メインフォームのポストバックで更新する代わりに、更新されたトークンをパスワードajaxリクエストで返送して、フォームを更新してみてください。どちらの方法でも、基本的なアプローチは同じで、逆シリアル化、ユーザーの更新、シリアル化、トークンの置換を行います。

string antiForgeryTokenName = AntiForgeryData.GetAntiForgeryTokenName(null);
string text = context.Request.Form[antiForgeryTokenName];
AntiForgeryDataSerializer serializer = new AntiForgeryDataSerializer();

AntiForgeryData antiForgeryData = serializer.Deserialize(text); 
antiForgeryData.Username = AntiForgeryData.GetUsername(context.User);
string newToken = serializer.Serialize(antiForgeryData);    

AntiForgeryDataSerializerとAntiForgeryDataは内部クラスであるため、これらのメソッドを呼び出すには、いくつかの基本的なリフレクションを使用する必要があります。

于 2012-02-04T02:53:21.483 に答える
1

AntiForgeryTokenSerializerコンストラクターへの変更を説明するために最終回答を更新しました。

    const string serializerAssembly = "System.Web.Helpers.AntiXsrf.AntiForgeryTokenSerializer";
    const string cryptoAssembly = "System.Web.Helpers.AntiXsrf.MachineKey40CryptoSystem";
    const string token = "System.Web.Helpers.AntiXsrf.AntiForgeryToken";
    const string fieldName = "__RequestVerificationToken";

    Assembly mvcAssembly = typeof (AntiForgery).Assembly;
    Type afdType = mvcAssembly.GetType(token);

    Type serializerType = mvcAssembly.GetType(serializerAssembly);
    Type cryptoType = mvcAssembly.GetType(cryptoAssembly);
    var constructors = serializerType.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
    ConstructorInfo cryptoConstructor = cryptoType.GetConstructor(new Type[0]);
    var crypto = cryptoConstructor.Invoke(new object[0]);
    object serializer = constructors[0].Invoke(new object[] { crypto });

    string text = currentContext.Request.Form[fieldName];
    string newToken = String.Empty;

    if (!String.IsNullOrEmpty(text))
    {
        object antiForgeryToken = serializerType.InvokeMember("Deserialize", BindingFlags.InvokeMethod, null,
                                                              serializer, new object[] {text});

        afdType.GetProperty("Username").SetValue(antiForgeryToken,
                                                 signIn ? user.Email : string.Empty,
                                                 null);

        newToken = Convert.ToString(serializerType.InvokeMember(
            "Serialize",
            BindingFlags.InvokeMethod,
            null,
            serializer,
            new[] {antiForgeryToken}));
    }

    return newToken;
于 2013-01-09T21:48:57.330 に答える