Anti sahtecilik belirteci "" kullanıcısı içindir, ancak mevcut kullanıcı "kullanıcı adı" dır


130

Tek sayfalı bir uygulama oluşturuyorum ve sahtecilik karşıtı belirteçlerle ilgili bir sorun yaşıyorum.

Sorunun neden olduğunu biliyorum, nasıl düzelteceğimi bilmiyorum.

Aşağıdakiler olduğunda hatayı alıyorum:

  1. Oturum açmamış kullanıcı bir iletişim kutusu yükler (oluşturulan bir sahtecilik önleme belirteci ile)
  2. Kullanıcı iletişim kutusunu kapatır
  3. Kullanıcı oturum açar
  4. Kullanıcı aynı iletişim kutusunu açar
  5. Kullanıcı formu iletişim kutusunda gönderir

Sahteciliğe karşı koruma belirteci "" kullanıcı içindir, ancak mevcut kullanıcı "kullanıcı adı" dır

Başvurum% 100 tek sayfadır ve bir kullanıcı başarıyla bir ajax posta yoluyla açtığında çünkü Böyle nedeni /Account/JsonLogin, ben sadece sunucusundan döndürülen "doğrulanmış görünümler" ile mevcut görüşleri dışarı geçiş ancak yeniden yok sayfa.

Bunun sebebinin bu olduğunu biliyorum, çünkü sayfayı 3. ve 4. adımlar arasında basitçe yeniden yüklersem hata olmaz.

Öyleyse @Html.AntiForgeryToken(), yüklenen formda, sayfa yeniden yüklenene kadar eski kullanıcı için hala bir jeton döndürdüğü görülüyor .

@Html.AntiForgeryToken()Yeni, kimliği doğrulanmış kullanıcı için bir jeton döndürmek üzere nasıl değişiklik yapabilirim ?

Yeni enjekte GenericalPrincipalözel bir ile IIdentityher üzerinde Application_AuthenticateRequestzaman öylesine @Html.AntiForgeryToken()çağrılan HttpContext.Current.User.Identityile benim özel kimlik aslında, IsAuthenticatedhenüz özelliği true seti ve @Html.AntiForgeryTokenhala bir sayfa yeniden yapmanız sürece eski kullanıcı için belirteç hale görünüyor.


@ Html.AntiForgeryToken kodunun yeniden yüklenmeden çağrıldığını gerçekten doğrulayabilir misiniz?
Kyle C

Kesinlikle, HttpContext.Current.User nesnesini incelemek için başarılı bir şekilde ara verebilirim, bahsettiğim gibi
parlamento


@parlamento aşağıdaki cevapta hangi seçeneği tercih ettiğinizi söyler misiniz?
Siddharth Pandey

Doğru hatırlıyorsam tam doldurma ile gitmek için bir istisna yaptığıma inanıyorum. Ama bu sorunla çok yakında yeni bir projede karşılaşmayı umuyorum. Daha iyi bir çalışma seçeneği tercih edersem geri gönderirim.
parlamento

Yanıtlar:


170

Bu, sahteciliği önleme belirtecinin daha iyi doğrulama için şifrelenmiş belirtecin bir parçası olarak kullanıcının kullanıcı adını yerleştirmesi nedeniyle gerçekleşir. @Html.AntiForgeryToken()Kullanıcıyı ilk aradığınızda, kullanıcı oturum açmamış olduğundan, kullanıcı oturum açtıktan sonra jetonun kullanıcı adı için boş bir dizesi olacaktır, sahteciliğe karşı jetonu değiştirmezseniz, ilk jeton için olduğu için doğrulamayı geçmeyecektir. anonim kullanıcı ve artık bilinen bir kullanıcı adına sahip kimliği doğrulanmış bir kullanıcımız var.

Bu sorunu çözmek için birkaç seçeneğiniz var:

  1. Tam bu sefer SPA'nızın tam bir POST yapmasına izin verin ve sayfa yeniden yüklendiğinde, gömülü güncellenmiş kullanıcı adıyla bir sahtecilik karşıtı jetona sahip olacak.

  2. @Html.AntiForgeryToken()Oturum açtıktan hemen sonra kısmi bir görünüm elde edin , başka bir AJAX isteği yapın ve mevcut sahtecilik karşıtı jetonunuzu isteğin yanıtıyla değiştirin.

  3. Sadece sahtecilik önleme doğrulamasının gerçekleştirdiği kimlik kontrolünü devre dışı bırakın. Sizin için aşağıdakileri ekleyin Application_Start yöntemiyle: AntiForgeryConfig.SuppressIdentityHeuristicChecks = true.


21
@par Parliament: Bu cevabı kabul ettiniz, hangi seçeneği tercih ettiğinizi bizimle paylaşır mısınız?
R. Schreurs

9
Güzel ve basit seçenek için +1 3. OAuth sağlayıcıları tarafından zamanlanmış oturum kapatma işlemleri de bu soruna neden olur.
Kodlamaya Gitti

18
3. Seçenek benim için işe yaramadı. Oturumu kapatırken, oturum açma sayfasına iki pencere açtım. Bir pencerede bir kullanıcı olarak oturum açtı, ardından diğerinde başka bir kullanıcı olarak oturum açtı ve aynı hatayı aldı.
McGaz

5
Ne yazık ki buna iyi bir çözüm bulamadım. Jetonu giriş sayfasından kaldırdım. Yine de giriş yaptıktan sonra yazılara ekliyorum.
McGaz

7
3. Seçenek de benim için işe yaramadı. Hala aynı hatayı alıyorum.
Joao Leme

25

Hatayı düzeltmek için OutputCacheVeri Ek Açıklamasını ActionResultGiriş Sayfasına şu şekilde yerleştirmeniz gerekir:

[OutputCache(NoStore=true, Duration = 0, VaryByParam= "None")] 
public ActionResult Login(string returnUrl)

3
Bu benim için sorunu çözdü, tamamen mantıklı. Teşekkürler!
Prime03

Benim kullanım durumum, kullanıcı bir oturum açmayı denedi ve bir hata gösterildi, örneğin ModelState.AddError () aracılığıyla "hesap devre dışı bırakıldı". Sonra tekrar girişe tıklarlarsa bu hatayı görürler. Ancak bu düzeltme, sahtecilik karşıtı belirteç hatası yerine onlara boş bir yeni oturum açma görünümü verdi. Yani, bir düzeltme değil.
yourpublicdisplayname

Durumum: 1. Kullanıcı Oturum Açma () ve ana sayfaya iner. 2. Kullanıcı geri düğmesine basıp Oturum Açma görünümüne geri döner. 3. Kullanıcı tekrar oturum açın ve "Sahteciliğe karşı belirteç kullanıcı içindir" "hatasını görün ancak mevcut kullanıcı" kullanıcı adı "" Hata sayfasında Kullanıcı menüden başka herhangi bir sekmeyi tıklarsa, uygulama beklendiği gibi çalışıyordu . Yukarıdaki kodu kullanan kullanıcı yine de geri düğmesine basabilir ancak ana sayfaya yönlendirilir. Dolayısıyla, kullanıcı geri düğmesine kaç kez basarsa bassın, onu ana sayfaya yönlendirecektir. Teşekkür ederim
Ravi

Bunun bir Xamarin web görünümünde neden çalışmadığına dair bir fikriniz var mı?
Noobie3001


15

Uygulamamla birçok kez oluyor, bu yüzden bunun için google'a karar verdim!

Bu hatayla ilgili basit bir açıklama buldum! Kullanıcı, oturum açmak için düğmeye çift tıklıyor! Aşağıdaki bağlantıda başka bir kullanıcının bunun hakkında konuştuğunu görebilirsiniz:

MVC 4, sahtecilik önleme belirtecinin "" kullanıcı için olduğunu sağladı, ancak mevcut kullanıcı "kullanıcı" dır

Umut ediyorum bu yardım eder! =)


Bu benim sorunumdu. Teşekkürler!
Nanou Ponette

8

Ben de aynı sorunu yaşadım ve bu kirli hack, en azından daha temiz bir şekilde düzeltene kadar düzeltildi.

    public ActionResult Login(string returnUrl)
    {
        if (AuthenticationManager.User.Identity.IsAuthenticated)
        {
            AuthenticationManager.SignOut();
            return RedirectToAction("Login");
        }

...


1
Benim de aynı sorunu yaşıyor gibiyim. IMO bu bir bilgisayar korsanlığı değil, daha çok oturum açarken kontrol etmemiz gereken yaygın bir şey. Kullanıcı zaten oturum açtıysa, oturumu kapatın ve oturum açma sayfasını görüntüleyin. Sorunumu çözdüm, teşekkürler.
Alexandre

7

Mesaj, kimliğiniz zaten doğrulanmışsa oturum açtığınızda görünür.

Bu Yardımcı, [ValidateAntiForgeryToken]öznitelikle tam olarak aynı şeyi yapar .

System.Web.Helpers.AntiForgery.Validate()

[ValidateAntiForgeryToken]Özniteliği denetleyiciden kaldırın ve bu yardımcıyı eylem yöntemine yerleştirin.

Dolayısıyla, kullanıcı zaten yetkilendirilmişse, ana sayfaya yönlendirin veya bu doğrulamadan sonra geçerli sahtecilik karşıtı jetonun doğrulanmasına devam etmeyin.

if (User.Identity.IsAuthenticated)
{
    return RedirectToAction("Index", "Home");
}

System.Web.Helpers.AntiForgery.Validate();

Hatayı yeniden oluşturmayı denemek için aşağıdakileri yapın: Giriş sayfanızdaysanız ve kimliğiniz doğrulanmadıysa. Sekmeyi kopyalarsanız ve ikinci sekme ile oturum açarsanız. Ve giriş sayfasındaki ilk sekmeye geri dönerseniz ve sayfayı yeniden yüklemeden giriş yapmaya çalışırsanız ... bu hatayı alıyorsunuz.


Mükemmel çözüm! Bu, işe yaramayan diğer birçok öneriyi denedikten sonra sorunumu çözdü. Birincisi, aynı sayfayla açılan 2 tarayıcı veya sekme ve birinden giriş yapan ve ardından yeniden yükleme yapmadan ikinci sayfadan giriş yapan sekme nedeniyle olabileceğini keşfedene kadar hatayı yeniden üreten bir acıydı.
Nicki

Bu çözüm için teşekkürler. Benim için de çalıştı. Kimliğin oturum açma kullanıcı adıyla aynı olup olmadığını görmek için bir kontrol ekledim ve öyleyse mutlu bir şekilde kullanıcı oturumunu açmaya ve değilse oturumu kapatmaya devam ediyorum. Örneğin, {System.Web.Helpers.AntiForgery.Validate ();} catch (HttpAntiForgeryException) {if (! User.Identity.IsAuthenticated || string.Compare (User.Identity.Name, model.Username)! = 0) deneyin {// Oturum kapatma mantığınız burada}}
Steve Owen,

2

Üretim sunucusunda çoğu zaman meydana gelen aynı istisnaya sahibim.

Neden olur?

Kullanıcı geçerli kimlik bilgileriyle oturum açtığında ve bir kez oturum açıp başka bir sayfaya yönlendirdiğinde ve geri düğmesine bastıktan sonra oturum açma sayfasını gösterecek ve bu istisnanın meydana geleceği geçerli kimlik bilgilerini tekrar girdiğinde gerçekleşir.

Nasıl çözülür?

Sadece bu satırı ekleyin ve mükemmel çalışın, hata almayın.

[OutputCache(NoStore = true, Duration = 0, VaryByParam = "None")]

1

Kayıt sürecinde oldukça spesifik ama benzer bir sorun yaşadım. Kullanıcı, kendisine gönderilen e-posta bağlantısını tıkladığında, oturum açacak ve daha fazla bilgi girmesi için doğrudan bir hesap ayrıntıları ekranına gönderilecek. Kodum şuydu:

    Dim result = Await UserManager.ConfirmEmailAsync(userId, code)
    If result.Succeeded Then
        Dim appUser = Await UserManager.FindByIdAsync(userId)
        If appUser IsNot Nothing Then
            Dim signInStatus = Await SignInManager.PasswordSignInAsync(appUser.Email, password, True, shouldLockout:=False)
            If signInStatus = SignInStatus.Success Then
                Dim identity = Await UserManager.CreateIdentityAsync(appUser, DefaultAuthenticationTypes.ApplicationCookie)
                AuthenticationManager.SignIn(New AuthenticationProperties With {.IsPersistent = True}, identity)
                Return View("AccountDetails")
            End If
        End If
    End If

İade Görünümünün ("AccountDetails") bana belirteç istisnası verdiğini buldum, tahmin ediyorum çünkü ConfirmEmail işlevi AllowAnonymous ile dekore edilmiş ancak AccountDetails işlevi ValidateAntiForgeryToken'e sahipti.

Return to Return RedirectToAction'ın ("AccountDetails") değiştirilmesi sorunu benim için çözdü.


1
[OutputCache(NoStore=true, Duration=0, VaryByParam="None")]

public ActionResult Login(string returnUrl)

Bunu, Oturum Açma (Al) işleminizin ilk satırına bir kırılma noktası koyarak test edebilirsiniz. OutputCache yönergesini eklemeden önce, kesme noktası ilk yüklemede vurulacaktı, ancak tarayıcı geri düğmesine tıkladıktan sonra bunu yapmayacaktı. Yönergeyi ekledikten sonra her seferinde vurulan kesme noktası ile sonuçlanmalısınız, böylece AntiForgeryToken boş değil doğru olan olacaktır.


0

Tek sayfalık bir ASP.NET MVC Core uygulamasıyla aynı sorunu yaşadım. HttpContext.UserMevcut kimlik taleplerini değiştiren tüm denetleyici eylemlerini ayarlayarak çözdüm (çünkü MVC bunu yalnızca burada tartışıldığı gibi sonraki istekler için yapar ). Antiforgery tanımlama bilgilerini yanıtlarıma eklemek için ara yazılım yerine sonuç filtresi kullandım, bu da bunların yalnızca MVC eylemi geri döndükten sonra oluşturulmasını sağladı.

Denetleyici (NB. Kullanıcıları ASP.NET Core Kimliği ile yönetiyorum):

[Authorize]
[ValidateAntiForgeryToken]
public class AccountController : Controller
{
    private SignInManager<IdentityUser> signInManager;
    private UserManager<IdentityUser> userManager;
    private IUserClaimsPrincipalFactory<IdentityUser> userClaimsPrincipalFactory;

    public AccountController(SignInManager<IdentityUser> signInManager, UserManager<IdentityUser> userManager, IUserClaimsPrincipalFactory<ApplicationUser> userClaimsPrincipalFactory)
    {
        this.signInManager = signInManager;
        this.userManager = userManager;
        this.userClaimsPrincipalFactory = userClaimsPrincipalFactory;
    }

    [HttpPost]
    [AllowAnonymous]
    public async Task<IActionResult> Login(string username, string password)
    {
        if (username == null || password == null)
        {
            return BadRequest(); // Alias of 400 response
        }

        var result = await signInManager.PasswordSignInAsync(username, password, false, lockoutOnFailure: false);
        if (result.Succeeded)
        {
            var user = await userManager.FindByNameAsync(username);

            // Must manually set the HttpContext user claims to those of the logged
            // in user. Otherwise MVC will still include a XSRF token for the "null"
            // user and token validation will fail. (MVC appends the correct token for
            // all subsequent reponses but this isn't good enough for a single page
            // app.)
            var principal = await userClaimsPrincipalFactory.CreateAsync(user);
            HttpContext.User = principal;

            return Json(new { username = user.UserName });
        }
        else
        {
            return Unauthorized();
        }
    }

    [HttpPost]
    public async Task<IActionResult> Logout()
    {
        await signInManager.SignOutAsync();

        // Removing identity claims manually from the HttpContext (same reason
        // as why we add them manually in the "login" action).
        HttpContext.User = null;

        return Json(new { result = "success" });
    }
}

Antiforgery çerezlerini eklemek için sonuç filtresi:

public class XSRFCookieFilter : IResultFilter
{
    IAntiforgery antiforgery;

    public XSRFCookieFilter(IAntiforgery antiforgery)
    {
        this.antiforgery = antiforgery;
    }

    public void OnResultExecuting(ResultExecutingContext context)
    {
        var HttpContext = context.HttpContext;
        AntiforgeryTokenSet tokenSet = antiforgery.GetAndStoreTokens(context.HttpContext);
        HttpContext.Response.Cookies.Append(
            "MyXSRFFieldTokenCookieName",
            tokenSet.RequestToken,
            new CookieOptions() {
                // Cookie needs to be accessible to Javascript so we
                // can append it to request headers in the browser
                HttpOnly = false
            } 
        );
    }

    public void OnResultExecuted(ResultExecutedContext context)
    {

    }
}

Startup.cs özü:

public partial class Startup
{
    public Startup(IHostingEnvironment env)
    {
        //...
    }

    public IConfigurationRoot Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {

        //...

        services.AddAntiforgery(options =>
        {
            options.HeaderName = "MyXSRFFieldTokenHeaderName";
        });


        services.AddMvc(options =>
        {
            options.Filters.Add(typeof(XSRFCookieFilter));
        });

        services.AddScoped<XSRFCookieFilter>();

        //...
    }

    public void Configure(
        IApplicationBuilder app,
        IHostingEnvironment env,
        ILoggerFactory loggerFactory)
    {
        //...
    }
}

-3

İnternet mağazasında sahteciliğe karşı belirteç doğrulama ile ilgili bir sorunu var: kullanıcılar birçok sekmeyi (ürünlerle) açar ve birinde oturum açtıktan sonra diğerinde oturum açmayı dener ve böyle bir AntiForgeryException alır. Bu yüzden, AntiForgeryConfig.SuppressIdentityHeuristicChecks = true bana yardımcı olmadı, bu yüzden çok çirkin bir hackfix kullandım, belki biri için yardımcı olabilir:

   public class ExceptionPublisherExceptionFilter : IExceptionFilter
{
    public void OnException(ExceptionContext exceptionContext)
    {
        var exception = exceptionContext.Exception;

        var request = HttpContext.Current.Request;
        if (request != null)
        {
            if (exception is HttpAntiForgeryException &&
                exception.Message.ToLower().StartsWith("the provided anti-forgery token was meant for user \"\", but the current user is"))
            {
                var isAjaxCall = string.Equals("XMLHttpRequest", request.Headers["x-requested-with"], StringComparison.OrdinalIgnoreCase);
                var returnUrl = !string.IsNullOrWhiteSpace(request["returnUrl"]) ? request["returnUrl"] : "/";
                var response = HttpContext.Current.Response;

                if (isAjaxCall)
                {
                    response.Clear();
                    response.StatusCode = 200;
                    response.ContentType = "application/json; charset=utf-8";
                    response.Write(JsonConvert.SerializeObject(new { success = 1, returnUrl = returnUrl }));
                    response.End();
                }
                else
                {
                    response.StatusCode = 200;
                    response.Redirect(returnUrl);
                }
            }
        }


        ExceptionHandler.HandleException(exception);
    }
}

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new ExceptionPublisherExceptionFilter());
        filters.Add(new HandleErrorAttribute());
    }
}

Kullanıcı adını veya buna benzer bir şeyi hariç tutmak için sahtecilik karşıtı belirteç oluşturma seçeneklerinin ayarlanmasının harika olacağını düşünün.


12
Bu, sorudaki sorunla başa çıkmanın korkunç bir örneğidir. Bunu kullanma.
xxbbcc

Xxbbcc ile tamamen katılıyorum.
Javier

Tamam, kullanım durumu: sahtecilik karşıtı jetonlu giriş formu. 2 tarayıcı sekmesinde açın. Önce oturum açın. Sen olamaz ikinci sekmeyi yenileyin. İkinci sekmeden giriş yapmaya çalışan kullanıcılar için doğru davranışa sahip olmak için hangi çözümü önerirsiniz?
user3364244

@ user3364244: doğru davranış şunları yapabilir: websockets veya signalR kullanarak harici bir oturum açma algılaması. Bu aynı oturum, yani çalışmasını sağlayabilirsiniz sanırım :-)
dampee
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.