微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在 IdentityServer4

如何解决如何在 IdentityServer4

我们有使用 IdentitySrver4 的 SSO 网站。我们最近测试了我们网站的安全性,我们发现了一个漏洞,如下所示,

应用程序的会话令牌保持有效(并且可以使用 验证对应用程序的请求)即使在注销后 函数已在相关会话中被调用。这表明 会话终止机制并不完全有效并且 增加了未经授权访问应用程序的可能性。 需要注意的是,令牌确实有一个有效的超时时间 一段时间后。注销功能终止了关联的 会话客户端(通过从用户的 浏览器),但会话在服务器端仍然有效。请求哪些 是在使用注销功能后进行的,但提供了 原始会话cookie,继续成功。

以下是代码片段,

IdentityServer

启动配置服务:-

services.AddIdentityServer(.......
services.AddAuthentication(options =>
               {
                   options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                   options.DefaultChallengeScheme = "oidc";
               })
               .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme,opt=> {

                   opt.ExpireTimeSpan = TimeSpan.FromMinutes(Convert.ToInt32(Configuration["CookieTimeOut"]));               
                   //This has time limit of 30 minutes    
               })
               .AddOpenIdConnect("oidc",opts =>
              {.......

登录代码如下,

await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,cp);

IdentityServer 中的注销方法:-

[HttpGet]
        public async Task<IActionResult> logout(string clientId,string returnUrl,string culture)
        {
            var clientsList = new List<Client>();

            // delete authentication cookie
            await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);

            var cookiesTobedeleted = Request.Cookies.Keys;
            foreach (string cookie in cookiesTobedeleted)
            {
                Response.Cookies.Delete(cookie);
            }

            var logoutURL = _configuration["DefaultlogoutRedirectUrl"];

            if (Uri.IsWellFormedUriString(returnUrl,UriKind.Absolute))
            {
                //Todo: validate that the return url belongs to the client who has initiated the logout request
                //if the url validation fails then we should return to a pre-determined url that is mentioned in the config                
                logoutURL = returnUrl;
            }

            var vm = new LoggedOutviewmodel()
            {
                PostlogoutRedirectUri = logoutURL,SignOutUrls = _clients.Value
                              .Where(client => !string.IsNullOrWhiteSpace(client.FrontChannellogoutUri))
                              .Select(client => client.FrontChannellogoutUri),ClientName = clientId,AutomaticRedirectAfterSignOut = true
            };

            //If there is no return url then display a local logged out page
            return View("LoggedOut",vm);
        }

        [HttpGet]
        public IActionResult LoggedOut(string returnUrl)
        {
            var vm = new LoggedOutviewmodel()
            {
                PostlogoutRedirectUri = returnUrl,SignOutUrls = null,AutomaticRedirectAfterSignOut = true
            };
            return View(vm);
        }

我们使用了FrontChannel注销,这里所有客户端的“FrontChannellogoutUri”都呈现在身份服务器注销页面的“IFrame”中.

客户端代码(MVC 应用程序):-

启动配置服务:-

services.AddAuthentication(options =>
                {
                    options.DefaultScheme =
                        CookieAuthenticationDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = "oidc";
                })
                .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme,ck =>
                {
                    ck.Cookie.Name = "ClientCookie";    
                    ck.ExpireTimeSpan = TimeSpan.FromMinutes(Convert.ToInt32(Configuration["CookieTimeOut"]));
                    //This also has value of 30 minutes. 
                })
                .AddOpenIdConnect("oidc",opts =>
                {.......

客户端应用程序中的注销功能:-

public async Task<IActionResult> logout(string path)
        {                
            var logoutUrl = //This is IdentityServer logout Method URL
            
            await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
            var prop = new Microsoft.AspNetCore.Authentication.AuthenticationProperties()
            {
                RedirectUri = logoutUrl
            };
            await HttpContext.SignOutAsync("oidc",prop);
            return Redirect(logoutUrl);
        }

客户端应用的 FrontChannel 方法:-

[AllowAnonymous]
        public async Task<IActionResult> ForcedSignout()
        {            
            var cookiesTobedeleted = Request.Cookies.Keys;
            foreach (string cookie in cookiesTobedeleted)
            {
                Response.Cookies.Delete(cookie);
            }
            await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
            
            return View();
        }

注销流程如下:-

当从客户端 MVC 应用程序调用 logout 时,我们已经调用了两者 HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme) & HttpContext.SignOutAsync("oidc",prop)

然后用户重定向到 IdentityServer logout 方法,该方法再次调用 HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme)

当 Identity 的注销页面呈现时,我们会生成带有客户端“FrontChannellogoutUri”(在本例中为“ForcedSignout()”)的“IFrames”客户端应用程序)。

"ForcedSignout" 方法再次删除 cookie 并调用 HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme)

重现问题的步骤:-

我们在 postman 中捕获了客户端应用程序的编辑方法

具有更改数据的邮递员请求已运行且有效。

在该用户退出客户端应用程序并再次运行邮递员请求后,即使我们已退出,该请求也成功运行。

然后我们等了 30 分钟(不活动)并尝试了邮递员请求,但这次它没有工作,因为会话已超时。

我们需要知道,当用户退出应用程序时,我们如何从服务器中删除/使会话无效?谢谢。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。