Spring Security 的一个常见配置就是检测相同的用户以不同的 session 登录安全系统。这被称为并发控制( concurrency control ) ,是 session 管理( session management ) 一系列相关配置功能的一部分。严格来说,这个功能并不是高级配置,但是它会让很多新手感到迷惑,并且最好在你对 Sping Security 整体功能有所了解的基础上再掌握它。 Spring Security 的 session 管理能够以两种不同的方式进行配置—— session 固化保护( session fixation protection )和并发控制。因为并发控制的功能基于 session 固化保护所提供的框架,我们先介绍 session 固化。 配置session fixation 防护 如果我们使用的是 security 命名空间的配置方式, session 固化防护已经被默认进行了配置。如果我们要指明将其配置为与默认设置一致的话,我们需要这样:
Session 固化防护这个功能你可能并不会在意,除非你想扮演一个恶意的用户。我们将向你展示如何模拟一个 session 窃取攻击,但是在此之前,有必要理解 session 固化是怎么回事以及怎样防止这样的攻击。 理解 session fixation 攻击Session 固化是恶意用户试图窃取系统中一个未认证用户的 session 。对攻击者来说,可以通过各种技术来获取用户 session 的唯一标识(例如, JSESSIONID )。如果攻击者创建了带有用户 JSESSIONID 的 cookie 或者 URL 参数,他就能够访问用户的 session 。 尽管这是一个明显的问题,但是一般情况下,如果用户没有经过认证,他们就还没有输入任何敏感信息(假设站点的安全已经正确规划了)。如果用户认证后依旧使用相同的 session 标识符,这个问题就会比较更加重要了。如果用户在认证后还使用相同的标识符,那攻击者现在就能访问认证过用户的 session ,而甚至不必要知道他们的用户名和密码。 【此时,你可能很不屑并认为在现实世界中这不会发生。实际上, session 窃取攻击经常发生。关于这个话题,我们建议(正如在第三章那样)你花些时间阅读由 OWASP 组织( http://www./ )发布的包含重要信息的文章以及学习案例。攻击者和恶意用户是真实存在的,如果你不了解他们常用的技术及如何避免,他们会对你的用户、应用或公司造成真正的损害。】 下图展现了 session 固化攻击是如何发生的:
使用 Spring Security 防止 session fixation 攻击如果我们能够阻止用户在认证前和认证后使用相同的 session ,我们就能够让攻击者掌握的 session ID 信息变得没有用处。 Spring Security 的 session 固化防护解决这个问题的方式就是在用户认证之后明确创建一个新的 session 并将旧的 session 失效。 让我们看下图:
模拟 session fixation 攻击此时,你可能会想要看一下在模拟 session 固化攻击时会涉及到什么。为了实现这一点,你需要在 dogstore-security.xml 中配置 session 固化防护失效。
接下来,你需要打开两个浏览器。我们将会在 IE 中初始化 session ,并从那里窃取,我们的攻击者将会使用窃取到的 session 在 Firefox 中登录。我们将会使用 Internet Explorer Developer Tools ( IE 8 中自带)以及 Firefox Web Developer Add-On (第三章中已经给过 URL )来查看和控制 cookie 。 在 IE 中打开 JBCP Pets 首页,然后打开开发者工具(看“工具”下拉菜单或点击 F12 ),并在“缓存”菜单下选择“查看 Cookie 信息”。在合适域下(如果使用 localhost 将为空)找到 JSESSIONID 的 cookie 。
将 session cookie 的值复制到粘贴板上,然后登录 JBCP Pets 站点。如果你重复“查看 Cookie 信息”,你将会发现 JSESSIONID 在登录后没有变化,这将会导致很容易受到 session 固化攻击。 在 Firefox 下,打开 JBCP Pets 站点。你将会被分配一个 session cookie ,这能通过 Cookie 菜单的“查看 Cookie 信息”菜单项查看到。
现在,重新使 session 固化防护生效然后重新尝试这个练习。你会发现,在这种情况下, JSESSIONID 在用户登录后会发生变化。因为你已经了解了 session 固化攻击是如何发生的,这意味着减少了可信任用户陷入这种攻击的风险。干的漂亮! 细心的开发人员应该会注意到有很多种窃取 session cookie 的方式,有一些如跨站脚本攻击( XSS )可能会使得 session 固化防护都很脆弱。请访问 OWASP 站点来了解更多防止这种类型攻击的信息。 比较 session-fixation-protection 选项session-fixation-protection 属性支持三种不同的选项允许你进行修改:
在大多数场景下,默认行为即 migrateSession 适用于在用户登录后希望保持重要信息(如点击爱好、购物车等)的站点的站点 通过session 的并发控制增强对用户的保护紧随 session 固化防护一个很自然的用户安全增强功能就是 session 并发控制。如前面所描述的那样, session 并发控制能够确保一个用户不能同时拥有超过一个固定数量的活跃 session (典型情况是一个)。要确保这个最大值的限制需要涉及到好几个组件的协作以精确跟踪用户 session 活动的变化。 让我们配置这个功能并了解其如何工作,然后对其进行测试。 配置 session 并发控制既然我们要了解 session 并发控制所要涉及的组件,那将其运行环境搭建起来可能会更有感官的了解。首先,我们需要使得 ConcurrentSessionFilter 生效并在 dogstore-security.xml 配置。
现在,我们需要在 web.xml 描述文件中配置中使得 o.s.s.web.session.HttpSessionEventPublisher 生效,这样 servelt 容器将会通知 Spring Security session 生命周期的事件(通过 HttpSessionEventPublisher )。
这两个配置完成, session 的并发控制功能也就激活了。让我们看一下它内部是如何工作的,然后我们将会通过几步操作来查看它对用户的 session 的保护功能。
理解 session 并发控制我们在前面提到 session 并发控制试图限制相同的用户以不同的 session 进行访问。基于我们对 session 窃取方式攻击的了解,我们可以发现 session 并发控制能够降低攻击者窃取已登录合法用户 session 的风险。你觉得为什么会这样呢? Session 并发控制使用 o.s.s.core.session.SessionRegistry 来维护一个活跃 HTTP session 的列表而认证过的用户与其进行关联。当 session 创建或过期时,注册表中会实时进行更新,基于 HttpSessionEventPublisher 发布的 session 生命周期事件来跟踪每一个认证用户的活动 session 的数量。
在修改后的 session 并发控制过滤器链中的第二个参与者是 o.s.s.web.session.ConcurrentSessionFilter 。这个过滤器能够辨认出过期的 session (典型情况下, session 会被 servlet 容器或者被 ConcurrentSessionControlStrategy 强制失效掉)并通知用户他的 session 已经失效了。 既然我们已经了解了 session 并发控制是如何工作的,那对我们来说很容易制造一个它使用的场景。 测试 session 并发控制如同验证 session 固化攻击那样,我们需要访问两个 web 浏览器。按一下的步骤: 1. 在 IE 中,以 guest 用户登录; 2. 接下来,在 Firefox 中,以相同的用户( guest )登录; 3. 最后,返回到 IE 中,做任何的动作都可以。你会发现有一个信息提示你的 session 已经过期了。 将会显示以下的信息:
【 session 并发控制对 Spring Security 的新用户来说是很难掌握的概念。很多用户在还没有完全理解其怎样运行和能带来什么好处时就尝试实现它。如果你想使用这个强大的功能,并且它不像你预想的那样工作,请确保你的配置全部正确并回顾一下本节讲的原理——希望它能帮助你理解什么出错了。】 在这样的事件发生时,我们应该将用户重定向到登录页,并提供一个信息来说明发生了什么错误。 配置 session 失效时的重定向地址幸运的是,有一种很容易的方法使用户在 session 并发控制后重定向到友好的页面(一般来说,是登录页),即设置 expired-url 属性为一个你应用中合法的页面。
这样在我们的应用中,就会将用户重定向到登录 form ,并且我们可以修改这个页面来展现用户友好的信息来表明发现了多个活跃的 session ,从而需要重新登录。当然,这个 URL 是完全随意的,并根据你应用的需求来进行相应的调整。 Session 并发控制的其它好处Session 并发控制的另一个好处是存在 SessionRegistry 跟踪活跃的 session (过期 session 是可选的)。这意味着我们能够得到系统中运行时的用户活动信息(至少是认证过的用户)。 即使你不想使用 session 并发控制,你可以可以这样做。只需将 max-sessions 的值设置为 -1 ,这样 session 跟踪会保持可用,但没有最大 session 个数的限制。 让我们看两个使用此功能的两种简单方式。 显示活动的用户你可能会在线论坛上见到显示系统中当前活跃用户的数量。借助于使用 session 注册跟踪(通过 session 并发控制),很容易实现在应用中的每个页面对此进行展现。 让我们在 BaseController 中添加一个简单的方法以及 bean 自动织入。 @Autowired
我们可以看到这暴露了一个能够在 Spring MVC JSP 页面中能够使用的属性,所以我们添加一个页脚 footer.jsp 到 JBCP Pets 站点中并使用这个属性。
如果你重新启动应用并登录,能够在每个页面的底部看到活动用户的数量。
我们能够借助于 SessionRegistry 进行更高级的收据收集,这对于管理员来说很有用——现在让我们看一下。 显示所有用户的信息SessionRegistry 跟踪所有活跃用户 session 的信息。如果你想增强站点的管理,我们可以可以很容易地在一个页面中列出所有的用户活跃用户以及他们在站点中使用的名字。 让我们为 AccountController 添加一个新的方法(尽管这样的功能一般会添加在在管理区域,但是此时我们可以假设 JBCP Pets 并不是一个真正的站点),这个方法将会查找 SessionRegistry 中的信息并收集当前 session 的信息。
这个方法使用了 SessionRegistry 的两个 API 。 l getAllPrincipals :返回拥有活跃 session 的 Principal 对象(典型情况下为 UserDetails 对象)所组成的 List ; l getAllSessions(principal, includeExpired) :得到指定 Principal 的 SessionInformation 组成的 List ,包含了每个 session 的信息。也能够包含过期的 session 。 了解了 SessionRegistry API 方法, listActiveUsers 方法的逻辑就很简单了——检索注册表中所有的活跃用户并寻找最近活动的 session 。 Principal 以及最近活跃的时间戳信息插入到一个 Map 中用来在 UI 中展现。 UI 页面通过使用 JSTL 结构变得很简单了。在 WEB-INF/views/account 目录下,创建 listActiveUsers.jsp ,内容如下(简便起见,我们省略了头部和尾部信息):
最后,当我们导航到 http://localhost:8080/JBCPPets/account/listActiveUsers.do ,页面基本如下:
|
|
来自: windli笔记 > 《Spring security》