使用 identityserver4 和 aspnet identity 时如何安全地实现空闲超时?
How can I safely implement idle timeout when using identityserver4 and aspnet identity?
我正在使用 .NET Core 2.2 Razor Pages 中的 .NET Identity 在 identityserver4 登录站点(服务器 UI)上工作,我有一个 javascript 模态警报,警告用户有待处理空闲超时,然后在达到超时时通过设置 window.location
将用户重定向到注销屏幕
我遇到的问题是快速启动示例中的 OnGet 显示用户提示注销,因为此时 logoutId 为空。我想在不提示用户的情况下注销。
目前我通过将 "autoLogout" 参数传递到我的注销页面来绕过对 logoutId 的检查并设置 ShowLogoutPrompt = false 来解决这个问题。我知道这在某种程度上违背了检查 logoutId 以确保在没有提示的情况下安全注销的目的。
有没有更好的方法来完成我想做的事情?
编辑 2019 年 7 月 16 日:
似乎 "right" 处理空闲超时的方法是设置应用程序 cookie 的令牌过期时间(比如 20 分钟)并启用 SlidingExpiration,以便在用户刷新时更新令牌。有关这方面的详细信息,请参阅 MS 文档中的 this blog post, this github issue thread (including comments from Brock Allen), and this info。
我的麻烦是这个解决方案有两个巨大的缺点。
- SlidingExpiration 仅在用户超过令牌 TimeSpan 的 50% 时刷新 cookie(请参阅 MS 文档 here 中的 SlidingExpiration 信息)。因此,如果他们将 9 分钟 59 秒刷新为 20 分钟的令牌,它们将在 10 分钟而不是 20 分钟后超时。一种解决方法是将令牌生命周期设置为 40 分钟,这将为用户提供至少 20 分钟的空闲时间,但他们可以最多有 40 分钟的空闲时间,这是不可接受的。
- 我的一个要求是一个模式来警告用户即将超时并让他们选择 continue/log 退出。要使用这种 cookie 方法执行此操作,我需要从我的 Javascript(或至少在我的 C# 中的 Razor 页面)中的 cookie 中读取令牌到期时间,以使我能够确定何时显示警告。即使没有模式要求,我也需要知道令牌何时过期,以便我可以刷新页面以将用户发送到登录屏幕。我正在尝试使用以下代码读取到期时间,但在令牌刷新后直到第二次刷新页面后它无法读取正确的到期时间,我不知道为什么。
@(DateTime.Parse(((await Context.AuthenticateAsync()).Properties.Items)[".expires"]))
cookie 方法的另一个不太明显的缺点是,如果我设法实现模式弹出窗口并且用户选择继续,那么页面将需要刷新以获取新令牌,此时任何未保存的数据都会迷路了。我想如果他们超时那么未保存的数据无论如何都会丢失,所以与上面相比这是一个相对次要的问题。
我正在考虑回到我原来的解决方案,它具有所需的功能,但会被攻击者滥用,攻击者在空闲超时时注意到我的 autoLogout 参数 javascript,然后可以使用它来提供到注销页面的热链接。目前,冒这个险是我最好的选择。
我觉得我在这个问题上陷入了困境,仍然没有好的解决方案。令我惊讶的是,我想象中的一个常见用例(空闲超时并发出警告,允许用户 continue/log 退出)却无法通过这种身份验证技术得到满足。我错过了什么吗?我是不是搞错了?
我在这里发布我的最终解决方案。它有效,但我不太喜欢它。对于参考,为什么我认为它有点 hacky 的详细信息,以及我认为主要缺点是什么,请参阅 7 月 16 日对我上面的原始问题的编辑。
在添加身份服务器后的 ConfigureServices 中,我设置了 cookie 的 SlidingExpiration = true; ExpireTimeSpan = AppSettings.IdleTimeoutMins(请参阅 this blog 了解我如何设置 AppSettings):
// Rename the .AspNetCore.Identity.Application cookie and set up for idle timeout
services.ConfigureApplicationCookie(options =>
{
options.Cookie.Name = "xxxx.Application";
options.SlidingExpiration = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(_config.GetValue<int>("AppSettings:" + nameof(AppSettings.IdleTimeoutMins)));
});
我有一个 Partial Razor 页面,其中我有 javascript 代码来向用户显示带有倒数计时器的模态警报。我从 AppSettings.IdleTimeoutMins 获取 timeoutSeconds 并且还有一个设置来确定何时显示警告。有关此位(及其优缺点)的更多详细信息,请在此处查看我的其他问题和答案: 警告消息使用户可以选择 "Continue" 刷新页面(因此刷新身份验证票证) 或 "Log Out",将它们发送到注销确认页面。如果时钟耗尽,则会刷新页面,这会导致他们返回到登录屏幕。
部分顶部:
@inject RussellLogin.Services.IAppSettings AppSettings;
@using Microsoft.AspNetCore.Authentication;
获取票据上剩余的(假定的)秒数:
secondsRemaining = "@(DateTime.Parse(((await AuthenticationHttpContextExtensions
.AuthenticateAsync(Context))
.Properties
.Items)[".expires"])
.Subtract(DateTime.Now)
.TotalSeconds)";
// If secondsRemaining is less than half the expiry timespan then assume it will be re-issued
if (secondsRemaining < timeoutSeconds / 2) {
secondsRemaining = timeoutSeconds;
}
我正在使用 .NET Core 2.2 Razor Pages 中的 .NET Identity 在 identityserver4 登录站点(服务器 UI)上工作,我有一个 javascript 模态警报,警告用户有待处理空闲超时,然后在达到超时时通过设置 window.location
将用户重定向到注销屏幕我遇到的问题是快速启动示例中的 OnGet 显示用户提示注销,因为此时 logoutId 为空。我想在不提示用户的情况下注销。
目前我通过将 "autoLogout" 参数传递到我的注销页面来绕过对 logoutId 的检查并设置 ShowLogoutPrompt = false 来解决这个问题。我知道这在某种程度上违背了检查 logoutId 以确保在没有提示的情况下安全注销的目的。
有没有更好的方法来完成我想做的事情?
编辑 2019 年 7 月 16 日: 似乎 "right" 处理空闲超时的方法是设置应用程序 cookie 的令牌过期时间(比如 20 分钟)并启用 SlidingExpiration,以便在用户刷新时更新令牌。有关这方面的详细信息,请参阅 MS 文档中的 this blog post, this github issue thread (including comments from Brock Allen), and this info。
我的麻烦是这个解决方案有两个巨大的缺点。
- SlidingExpiration 仅在用户超过令牌 TimeSpan 的 50% 时刷新 cookie(请参阅 MS 文档 here 中的 SlidingExpiration 信息)。因此,如果他们将 9 分钟 59 秒刷新为 20 分钟的令牌,它们将在 10 分钟而不是 20 分钟后超时。一种解决方法是将令牌生命周期设置为 40 分钟,这将为用户提供至少 20 分钟的空闲时间,但他们可以最多有 40 分钟的空闲时间,这是不可接受的。
- 我的一个要求是一个模式来警告用户即将超时并让他们选择 continue/log 退出。要使用这种 cookie 方法执行此操作,我需要从我的 Javascript(或至少在我的 C# 中的 Razor 页面)中的 cookie 中读取令牌到期时间,以使我能够确定何时显示警告。即使没有模式要求,我也需要知道令牌何时过期,以便我可以刷新页面以将用户发送到登录屏幕。我正在尝试使用以下代码读取到期时间,但在令牌刷新后直到第二次刷新页面后它无法读取正确的到期时间,我不知道为什么。
@(DateTime.Parse(((await Context.AuthenticateAsync()).Properties.Items)[".expires"]))
cookie 方法的另一个不太明显的缺点是,如果我设法实现模式弹出窗口并且用户选择继续,那么页面将需要刷新以获取新令牌,此时任何未保存的数据都会迷路了。我想如果他们超时那么未保存的数据无论如何都会丢失,所以与上面相比这是一个相对次要的问题。
我正在考虑回到我原来的解决方案,它具有所需的功能,但会被攻击者滥用,攻击者在空闲超时时注意到我的 autoLogout 参数 javascript,然后可以使用它来提供到注销页面的热链接。目前,冒这个险是我最好的选择。
我觉得我在这个问题上陷入了困境,仍然没有好的解决方案。令我惊讶的是,我想象中的一个常见用例(空闲超时并发出警告,允许用户 continue/log 退出)却无法通过这种身份验证技术得到满足。我错过了什么吗?我是不是搞错了?
我在这里发布我的最终解决方案。它有效,但我不太喜欢它。对于参考,为什么我认为它有点 hacky 的详细信息,以及我认为主要缺点是什么,请参阅 7 月 16 日对我上面的原始问题的编辑。
在添加身份服务器后的 ConfigureServices 中,我设置了 cookie 的 SlidingExpiration = true; ExpireTimeSpan = AppSettings.IdleTimeoutMins(请参阅 this blog 了解我如何设置 AppSettings):
// Rename the .AspNetCore.Identity.Application cookie and set up for idle timeout
services.ConfigureApplicationCookie(options =>
{
options.Cookie.Name = "xxxx.Application";
options.SlidingExpiration = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(_config.GetValue<int>("AppSettings:" + nameof(AppSettings.IdleTimeoutMins)));
});
我有一个 Partial Razor 页面,其中我有 javascript 代码来向用户显示带有倒数计时器的模态警报。我从 AppSettings.IdleTimeoutMins 获取 timeoutSeconds 并且还有一个设置来确定何时显示警告。有关此位(及其优缺点)的更多详细信息,请在此处查看我的其他问题和答案:
部分顶部:
@inject RussellLogin.Services.IAppSettings AppSettings;
@using Microsoft.AspNetCore.Authentication;
获取票据上剩余的(假定的)秒数:
secondsRemaining = "@(DateTime.Parse(((await AuthenticationHttpContextExtensions
.AuthenticateAsync(Context))
.Properties
.Items)[".expires"])
.Subtract(DateTime.Now)
.TotalSeconds)";
// If secondsRemaining is less than half the expiry timespan then assume it will be re-issued
if (secondsRemaining < timeoutSeconds / 2) {
secondsRemaining = timeoutSeconds;
}