跳到主要内容

02、Spring Security 速成 - 各种架构中所应用的安全性

一、前言

该章内容其实仍然属于前言,只是对后面Spring Security对各个架构所需要涉及到的相关概念进行讲解,比如在单体式Web-》前后端分离-》Oauth2的一个架构理念以及Spring Security随着架构的演变是如何去改变它的大体用法的,这些我们都会涉及到,但是更详细的内容后面章节将逐一展示。

架构直接影响着为应用程序配置Spring Security的选择;因为安全保障方法取决于我们实现的解决方案,所以Spring Security中的配置也会有所不同。下面我们将讨论一些基于不同架构方式的示例,这些示例中将考虑影响安全保障方法的各种需求。

二、单体式Web应用程序

首先我们要开发一个代表Web应用程序的系统组件。在这个应用程序的开发过程中后台和前端没有直接分离这类应用程序出现的方式通常是通过普通的servlet流:应用程序接收HTTP请求,然后将HTTP响应发送回客户端。有时候,可为每个客户端提供一个服务器端会话,以便存储更多HTTP请求的特定细节。在本书提供的示例中,我们使用了Spring MVC

 

那么以上就是Spring MVC流的最小化标识,我们在这里就不往深处说

那么只要有一个会话,就需要考虑前文提到的会话固定漏洞 以及CSRF的可能性。还必须考虑在HTTP会话本身中所存储的内容

服务器端会话是准持久化的。它们是有状态的数据片段,因此他们的生命周期较长。而他们在内存中驻留的时间越长,它们被访问的统计概率就越大。例如,能够访问堆转储的人可以读取应用程序内部内存中的信息。不要认为获取堆转储有太大的难度!特别是当你在使用Spring Boot开发应用程序时,你可能会发现Actuator也是应用程序的一部分。Spring Boot Actuator是一个很好的工具。根据其配置方式的不同,它可以只返回一个端点调用的堆转储,也就是说,并不一定需要root权限来访问VM才能获得转储文件。

在本例中,回到CSRF方面的漏洞,避免该漏洞的最简单的方法就是使用反CSRF令牌。幸运的是,有了Spring Security,这个功能就可以开箱即用了默认情况下,CSRF保护和原始CORS的验证都是启用了的。如果确定不想使用它们,则必须手动禁用。对于身份验证和授权,可以选择使用来自Spring Security的隐式登录表单配置。这样,我们就只需要重写登录和注销的外观,并且还可以获得与身份验证和授权配置的默认集成。我们还将免受会话固定的困扰

如果实现身份验证和授权,这还意味着我们应该拥有一些具有有效凭证的用户。我们可以选择让应用程序管理用户的凭据,或者也可以选择依赖另一个系统来完成这项工作(例如,我们可能希望用户使用其QQ,微信,Gitee凭据进行登录)。在任何一种情况下,Spring Security都可以帮助我们以一种相对简单的方式配置用户管理。可以选择将用户信息存储在数据库中、使用Web服务或者连接到另一个平台。Spring Security架构中使用的抽象使其解耦化了,这样就可以选择适合我们应用程序的任何实现。

三、为前后端分离设计安全性

如今,在Web应用程序的开发中,我们经常看到前端和后端分离的选择,在这些程序中,开发人员使用ReactJS或Vue.js这样的框架开发前端,通过REST端点与后端通信,我们后面也将在这个架构实现应用Spring Security的示例。

 

如上图,浏览器执行前端应用程序。此应用程序调用后端公开的REST端来执行用户请求的一些操作

在前后端分离架构下,我们通常会避免使用服务器端会话:客户端会话将会替换这些会话,这类系统设计类似与在移动应用中使用的系统设计。运行在Android或iOS操作系统上的应用程序会通过REST端点调用后端

就安全性而言,还有其他一些方面需要考虑。首先,CSRF和CORS配置通常会更复杂。我们可能要水平地扩展系统,但并不是必须将前端和后端放在同一个服务源点上。对于移动应用,我们甚至无法获悉其服务源点。

作为一种实际的解决方案,最简单但最不理想的方法就是使用HTTP BASIC进行端点身份验证,虽然这种方法很容易理解,并且通常会用于初始的理论身份验证示例,但是它确实存在我们希望避免的漏洞。例如,使用HTTP Basic意味着每次调用时发送凭据。如果该凭据没有加密,浏览器以BASE64编码的方式发送用户名和密码,这样,就可以在每个端点调用的头信息中获取流经网络的凭据。另外,假设凭据代表了已登录的用户,我们就不会希望用户为每个请求都输入他们的凭据。也不希望必须在客户端存储凭据。这种做法是不可取的。

考虑上述原因,我们将介绍一种身份验证和授权的替代方法,即OAuth2

四、理解Oauth2流程

本节将探讨OAuth2流程的高度概述。主要是关注应用OAuth2的原因,后面我们将详细讨论这个话题。我们当然希望找到一种解决方案,以避免将每个请求的凭据重新发送到后端,并将其存储在客户端,这些情况下,OAuth2流程提供了更好的实现身份验证和授权的方法。

OAuth2框架定义了两个独立的实体:授权服务器和资源服务器。授权服务器的目的是对用户进行授权,并为用户提供一个令牌,该令牌将指定用户可以使用的一组资源权限。实现此功能的后端被称为资源服务器。可以调用的端点则被视作受保护的资源。根据获得的令牌,完成授权后,对于资源的调用则被视作受保护的资源。根据获得的令牌,完成授权后,对于资源的调用可能会被允许也肯能会被拒绝。具体步骤如下图:

(1)用户访问应用程序中的用例(也称为客户端)。应用程序需要调用后端资源

(2)为了能够调用资源,应用程序首先必须获得访问令牌,因此它需要调用授权服务器来获得该令牌。在请求中,应用程序会在某些情况下发送用户凭据或一个刷新令牌

(3)如果凭据或刷新令牌正确,则授权服务器将向客户端返回一个(新的)访问令牌

(4)在调用所需的资源时,在对资源服务器的请求的头信息中要使用访问令牌

 

令牌其实就是我们老生常谈的token,类似门禁卡,经过身份验证之后,将向调用者提供一个令牌,基于该令牌,调用者可以访问其具有权限的资源。

令牌有固定的生命周期,通常是短期的。当一个令牌过期时,应用程序需要获得一个新的令牌。如果需要,服务器可以在令牌过期之前取消其资格。下面列出这种流程的一些优点:

  • 客户端不需要存储用户凭据。访问令牌,以至于刷新令牌是唯一需要保存的访问细节。
  • 应用程序不公开用户凭据,这些凭据常常存在于网络上。
  • 如果有人截获了一个令牌,我们可以取消该令牌的资格,而不需要使用用户凭据失效。
  • 令牌可以由第三方实体使用,从而以用户的名义访问资源,而不必模拟用户。当然,在这种情况下,攻击者可以窃取令牌。但是,由于令牌的生命周期通常较短,因此可以使用此漏洞获取的令牌也是有时间限制的

当然,即使使用OAuth2流程,也不是所有一切都完美了,还需要使其适应应用的程序设计,其中一个问题就是,哪一种是管理令牌的最佳方式?

  • 将令牌持节化到应用程序的内存中
  • 将令牌持久化到数据库中
  • 使用加密签名和JWT(JSON Web Tokens)