CodeVerification Cookie 在 Edge 和 Chrome 中消失

Posted

技术标签:

【中文标题】CodeVerification Cookie 在 Edge 和 Chrome 中消失【英文标题】:CodeVerification Cookie disappears in Edge and Chrome 【发布时间】:2021-09-27 23:28:10 【问题描述】:

.NET framework 4.6.1 网站使用 OIDC 身份验证 (Microsoft.Owin.Security.OpenIdConnect 4.1.0) 作为身份验证的一部分,我包括“code_challenge”。下面的代码就是基于这个example。

RedirectToIdentityProvider = n =>
                
                    //ProcessCertificateValidation();
                    if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.Authentication)
                    
                        if (AppSettingsKey.AuthCodeChallangeEnabled.Enabled)
                        
                            // generate code verifier and code challenge
                            var codeVerifier = CryptoRandom.CreateUniqueId(32);

                            string codeChallenge;
                            using (var sha256 = SHA256.Create())
                            
                                var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier));
                                codeChallenge = Base64UrlEncoder.Encode(challengeBytes);
                            

                            // set code_challenge parameter on authorization request
                            n.ProtocolMessage.Parameters.Add("code_challenge", codeChallenge);
                            n.ProtocolMessage.Parameters.Add("code_challenge_method", "S256");

                            // remember code verifier in cookie (adapted from OWIN nonce cookie)
                            RememberCodeVerifier(n, codeVerifier);
                        
                        if (AppSettingsKey.MultiFactorAuthEnabled.Enabled)
                            n.ProtocolMessage.AcrValues = authCfg.AcrValues ?? n.ProtocolMessage.AcrValues;
                    
                    
                    logger.Debug("OIDC-Notification: RedirectToIdentityProvider Called");

                    //if signing out, add the id_token_hint
                    if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.Logout)
                    
                        logger.Debug("  RequestType=" + OpenIdConnectRequestType.Logout);
                        var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token");

                        if (idTokenHint != null)
                        
                            logger.Debug("  IdTokenHint got from n.OwinContext.Authentication.User");
                            n.ProtocolMessage.IdTokenHint = idTokenHint.Value;
                        
                        logger.Debug("  IdTokenHint=" + n?.ProtocolMessage?.IdTokenHint);
                        
                    
                    return Task.CompletedTask;
                ,

我确认“codeVerifierCookie”已发送。

AuthorizationCodeReceived = async n =>
                
                    logger.Debug("OIDC-Notification: AuthorizationCodeReceived Called");
                    logger.Debug("  Code=" + n.Code);
                    logger.Debug("  AuthenticationType=" + n.Options.AuthenticationType);

                    if (authCfg.DiscoverEndpoints)
                    
                        var disco = await n.Options.ConfigurationManager.GetConfigurationAsync(n.OwinContext.Request.CallCancelled);
                        authCfg.TokenEndpoint = disco.TokenEndpoint;
                        authCfg.UserinfoEndpoint = disco.UserInfoEndpoint;
                        authCfg.EndsessionEndpoint = disco.EndSessionEndpoint;
                        //authCfg.RevocationEndpoint = disco.RevocationEndpoint;
                        authCfg.WebKeySetEndpoint = disco.JwksUri;
                    
                    if (AppSettingsKey.AuthCodeChallangeEnabled.Enabled) 
                        var codeVerifier = RetrieveCodeVerifier(n);
                        // attach code_verifier
                        n.TokenEndpointRequest.SetParameter("code_verifier", codeVerifier);
                    
                    var requestMessage = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Post, authCfg.TokenEndpoint);
                    requestMessage.Content = new System.Net.Http.FormUrlEncodedContent(n.TokenEndpointRequest.Parameters);
                    var responseMessage = await n.Options.Backchannel.SendAsync(requestMessage);
                    responseMessage.EnsureSuccessStatusCode();
                    var responseContent = await responseMessage.Content.ReadAsStringAsync();
                    Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage message = new Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage(responseContent);

                    logger.Debug("  IdToken=" + message.IdToken);
                    logger.Debug("  AccessToken=" + message.AccessToken);

                    n.HandleCodeRedemption(message);

                ,

问题是当尝试检索“codeVerifierCookie”时它不存在,当尝试登录 Edge 或 Chrome(在 Firefox 上)时。

以下是用于发送、检索和获取验证码的方法。 CookieManager 配置为Microsoft.Owin.Host.SystemWeb.SystemWebChunkingCookieManager()

private void RememberCodeVerifier(RedirectToIdentityProviderNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> n, string codeVerifier)
    
        var properties = new AuthenticationProperties();
        properties.Dictionary.Add("cv", codeVerifier);
        n.Options.CookieManager.AppendResponseCookie(
            n.OwinContext,
            GetCodeVerifierKey(n.ProtocolMessage.State),
            Convert.ToBase64String(Encoding.UTF8.GetBytes(n.Options.StateDataFormat.Protect(properties))),
            new CookieOptions
            
                SameSite = SameSiteMode.None,
                HttpOnly = true,
                Secure = n.Request.IsSecure,
                Expires = DateTime.UtcNow + n.Options.ProtocolValidator.NonceLifetime
            );
    

    private string RetrieveCodeVerifier(AuthorizationCodeReceivedNotification n)
    
        string key = GetCodeVerifierKey(n.ProtocolMessage.State);

        string codeVerifierCookie = n.Options.CookieManager.GetRequestCookie(n.OwinContext, key);
        if (codeVerifierCookie != null)
        
            var cookieOptions = new CookieOptions
            
                SameSite = SameSiteMode.None,
                HttpOnly = true,
                Secure = n.Request.IsSecure
            ;

            n.Options.CookieManager.DeleteCookie(n.OwinContext, key, cookieOptions);
        

        var cookieProperties = n.Options.StateDataFormat.Unprotect(Encoding.UTF8.GetString(Convert.FromBase64String(codeVerifierCookie)));
        cookieProperties.Dictionary.TryGetValue("cv", out var codeVerifier);

        return codeVerifier;
    

    private string GetCodeVerifierKey(string state)
    
        using (var hash = SHA256.Create())
        
            return OpenIdConnectAuthenticationDefaults.CookiePrefix + "cv." + Convert.ToBase64String(hash.ComputeHash(Encoding.UTF8.GetBytes(state)));
         
    

为什么当我尝试从 Edge 或 Chrome 登录时“codeVerifierCookie”丢失?可能是一些默认设置还是我的设置缺少某些东西?为什么它可以在 Firefox 上运行?

感谢您阅读我的帖子,我欢迎您就这个问题提出任何意见。

【问题讨论】:

【参考方案1】:

您在测试应用时是否使用过 HTTPS?声明 SameSite=None 的 Cookie 也必须标记为 Secure。我认为这个问题可能与同一站点 cookie 设置有关。

我发现a thread和你的问题一样,你可以参考一下。此外,还有a detailed article关于在 ASP.NET 中使用 SameSite cookie,您也可以查看它以获取更多信息。

【讨论】:

这正是问题所在。出于某种原因,Firefox 不需要 cookie 来保证安全。您认为将此代码验证程序 cookie 上的 Secure 属性设置为始终为真是正确的操作吗?谢谢你的回答。 我认为你需要在SameSite=None时设置Secure并使用HTTPS。

以上是关于CodeVerification Cookie 在 Edge 和 Chrome 中消失的主要内容,如果未能解决你的问题,请参考以下文章

java 怎么把token放进cookie

c++cef禁止cookie设置

cookie在不同端口号可以共享吗

问题:将每次输入的信息保存在cookie中,再从cokie中取出值并显示在下拉框中。急需如何保存在cookie中...

Cookie对象

cookie 怎样存储值?