微服务从小白到专家:Spring Cloud和Kubernetes实战
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

3.6 应用安全管理

随着互联网浪潮的涌起,加上苹果、谷歌等大型互联网公司所引领的移动互联网风潮,全世界的互联网用户数逐年呈指数级增长。互联网用户数统计(CNNIC第47次《中国互联网络发展状况统计报告》)如图3-86所示。

图3-86 互联网用户数统计

随着全球范围内互联网用户数量的爆发式增长,各种应用安全问题也随之增加,安全事故统计(CNCERT《2020年上半年我国互联网网络安全监测数据分析报告》)如图3-87所示。

由于经济利益的驱动,各种各样的黑客攻击手段层出不穷,这大大促进了信息安全领域的发展。通常,我们会从系统安全的角度对系统进行安全分级,系统的安全分级如图3-88所示。

图3-87 安全事故统计

图3-88 系统的安全分级

本章主要关注应用层(Application)的安全管理。

3.6.1 Authentication用户身份鉴定

对任何应用程序来说,最基础的安全保护机制是只允许授权用户访问应用,这条安全底线对存有客户敏感信息的系统(如社交网络或者政府机关为全国各地提供的信息服务)来说尤为重要。这类系统一旦被非法用户侵入,将会导致严重的信息泄漏问题。

应当如何设计系统才能保证系统只被授权用户使用呢?简单通用的一种解决方案就是用户认证,用户认证体系的工作流程如图3-89所示。

图3-89 用户认证体系的工作流程

通常情况下,用户身份认证要求用户提交一种凭证来证明自己就是账户的所有人,最简单的凭证是用户名和密码、用户名和指纹、人脸识别等。系统根据用户所提交的信息与系统中保存的用户信息进行匹配。如果匹配成功,则表示用户认证成功,反之则表示用户认证失败。

在互联网时代,系统安全变得越来越重要,一些安全等级要求较高的应用开始逐渐推广2FA(Two Factor Authentication)验证模式,即系统对用户采用两种不同的方式进行验证(例如用户名、密码+手机验证码两种方式)。我们以网银登录为例,网银账号不仅设置了用户名和密码,同时还绑定了一个手机号。当用户登录电子银行时,先以用户名、密码验证一次,验证成功之后,系统再向用户预留的手机号发送一个随机的验证码,用户需要输入该验证码才能通过验证。用户名、密码验证和随机验证码验证二者缺一不可,这样就以两种形式认证了用户。对于应用了2FA机制的系统,如果黑客无法同时获得两种凭证,就无法攻破该系统的用户账号体系,2FA机制如图3-90所示。

图3-90 2FA机制

3.6.2 Authorization用户鉴权

在用户认证成功登录进系统以后,只表明他是“他”,系统将面临下一个问题,该用户能使用系统的哪些功能?在一个庞大的系统中,例如一家公司的ERP系统,公司有各种不同角色的人,比如总经理、董事长、经理、组长和普通员工,不同角色的人可以使用同样的系统功能吗?显然无论从公司规章制度还是社会常识等方面考虑,答案都是否定的。系统应该让不同角色的用户拥有不同的权限,即不同用户可以看到不同数据并使用不同功能,用户授权流程如图3-91所示。

图3-91 用户授权流程

在用户授权体系中,主要有以下几个领域对象:

• User(用户):代指实际用户在系统中的代号,在用户第一次使用系统时创建。

• Credentials(凭证):用户用于证明自己身份的凭证,一般都是以密码或者令牌的形式存在。

• Role(角色):角色是一种逻辑上的抽象存在,在现实中并不一定有严格的一一对应的实体,我们也可以将角色理解成“一组享有相同系统权限的用户”。

• Resource(资源):系统的某些功能或数据资源,它是安全体系所要保护的内容,它可以是一个URL,也可以是一条数据或者一个页面。

• Permissions(权限):权限就是指用户(或角色)拥有的对特定资源(Resource)的访问等级。

3.6.3 OAuth 2.0

OAuth是由IETF定义的一组关于授权(Authorization)的规范,第一版形成于2006年,2012年推出了OAuth 2.0。OAuth是一种委派授权访问的协议,即资源的拥有者(Resource Owner)通过授权服务器(Authorization Server)将其部分权限授予用户(Client),OAuth 2.0的工作流程如图3-92所示。

图3-92 OAuth 2.0的工作流程

OAuth 2.0协议主要定义了两个核心功能(获得令牌和使用令牌)和三种角色(Resource Owner、Client和Authorization Server)。OAuth 2.0协议的工作流程如下:

(1)Resource Owner告知Client希望Client可以暂代他们的一些职责。

(2)Client向Resource Owner请求授权,也可以间接地从Authorization Server那里获得授权。

(3)Resource Owner向Client授权,代表一种资源的访问许可。

(4)Client使用前述授权和某种私有凭证向Authorization Server发起获得访问令牌的请求,Authorization Server验证私有凭证和访问授权,如果通过则发放访问令牌。

(5)Client使用访问令牌向资源服务器请求受保护的资源,在资源服务器验证访问令牌的合法性后,client获得其所请求的资源,流程结束。

OAuth 2.0中除上述几种角色外,还有以下重要组件:

(1)Access Token:客户端从Authorization Server获得的访问凭证(Token),用于访问受保护的资源,通常情况下,客户端只使用Token,并不解析Token的内容和含义,由Resource Server对Token进行验证。

(2)Scope:Scope表示针对受保护资源(Resource)的一组权利主张,Scope可以是任意字符串。

(3)Refresh Token:使用Refresh Token可以直接从Authorization Server获得一个新的Access Token,无需Resource Owner的再次授权。

根据获得授权的不同方式,OAuth 2.0定义了四种不同流程(flow)来取得授权:

(1)Authorization Code:用于server side的应用。

(2)Implicit:用于运行在客户终端的应用。

(3)Client Credentials:用于应用的API访问。

(4)Resource Owner Password Credentials:用于受信任的应用,只要客户端一次性提交Username、Password、Client ID和Client Secret即可。

OAuth 2.0的四种授信方式如图3-93所示,由于篇幅原因,其具体含义和使用方式就不在此详述。

图3-93 OAuth 2.0的四种授信方式

根据OAuth 2.0协议的规定,获取Access Token分为以下五个步骤:

(1)客户端向OAuth服务发起预注册,获得Client ID和Client Secret。

(2)OAuth服务对用户进行认证。

(3)OAuth服务确保客户端获得某种授权。

(4)OAuth服务发送Secret Code给客户端。

(5)客户端通过Secret Code和Client Secret从OAuth服务获得Access Token。

3.6.4 Spring Security

3.6.4.1 Spring Security介绍

Spring Security是一个专门为Java应用提供各种安全服务的框架,它提供了多种开箱即用的Authentication方式,如LDAP、OpenID、Form Authentication、Certificate X.509 Authentication和Database authentication等。它还提供了多种不同层次的安全服务,比如URL、某个页面、方法和数据,可以根据所需任意组合。

Spring Security为Spring应用提供了Authentication和Authorization的基础接口和框架,Spring Security架构如图3-94所示。

图3-94 Spring Security架构图

Spring Security是一个非常庞大且复杂的系统,我们从Spring Security的类图入手,了解Spring Security核心类的功能,Spring Security类图如图3-95所示。

图3-95 Spring Security类图

(1)Authenticated Principal

Principal在Spring Security中指的是通过了认证(Authentication)的人,即当前登录的用户。在Spring Security体系中使用接口AuthenticatedPrincipal来指代当前登录的用户对象,AuthenticatedPrincipal接口的代码如下:

一旦用户认证成功,Spring Security就会创建一个AuthenticatedPrincipal对象,并保存在系统中供后续使用,避免了用户一直反复登录。

(2)Granted Authority

在Spring Security中用户的访问权限被称为Granted Authority,即用户希望访问任何resource,都必须拥有该资源的某种授权。我们使用Granted Authority接口来指定这类对象,具体代码如下。

(3)Role

角色表示一组授权(Authority),一个用户可以有一个或多个角色。

(4)Filters

从Servlet规范的角度来看,Filter是一个过滤器,Filter的执行阶段可以是在用户请求被处理之前或之后。Spring Security通过Filter中定义的规则来检查每个请求应该被拒绝还是被放行。

(5)Authentication Manager

Authentication Manager主要用于管理Authentication的配置,以及用户的认证,我们使用接口AuthenticationManager来定义它的行为,具体代码如下。

在用户按照要求提供了登录凭证之后,Spring Security filter拦截请求并创建Authentication对象,再将此对象交由AuthenticationManager验证,如果验证成功则返回一个包含Principal等信息的Authentication对象,否则就抛出异常。

(6)Authentication Manager Builder

Authentication Manager Builder用于创建AuthenticationManager,在应用中使用AuthenticationManagerBuilder来设置要使用哪种认证方式,例如in-memory、JDBC或LDAP等。我们在应用中并不直接创建AuthenticationManagerBuilder,而是通过继承WebSecurityConfigurerAdapter类的方式来创建AuthenticationManagerBuilder,具体代码如下。

(7)Authentication Provider

Authentication Provider为Authentication Manager提供用户认证功能和用户数据,其接口定义如下:

Spring Security提供了多种AuthenticationProvider类的内置实现,例如DaOAuthenticationProvider和LdapAuthenticationProvider。

(8)SecurityContextHolder

SecurityContext接口主要用于存储用户信息(即Authentication对象)。其接口定义如下:

SecurityContextHolder是存储SecurityContext的类,它的特点是所有的方法都是静态方法,在用户认证成功登录以后,过滤器会将相关信息存入SecurityContext对象,再将SecurityContext存入SecurityContextHolder,这样应用在任何地方都可以得到用户的相关信息。

3.6.4.2 Spring Boot与Spring Security集成

本节,我们在coupon-template-service项目中集成OAuth和Spring Security的相关功能。

首先,我们在项目中引入OAuth和Spring Security的相关的依赖项,具体代码如下:

然后,我们创建UserServiceSecurityConfig类,并继承自WebSecurityConfigurerAdapter,以下代码演示如何通过Java bean的方式来配置Spring Security:

接下来,我们搭建一个简易的Authorization Server应用,这个示例仅用作本地测试,在真正的生产环境中我们需要将Authorization Server搭建为一个独立服务。Authorization Server的具体代码如下:

最后,我们启动项目进行测试。假设用户需要访问template服务,访问地址为http://localhost:8090/template/add,获取Access Token的步骤如下:

(1)登录用户:

在浏览器中输入http://localhost:8080/user/OAuth/authorize?response_type=code&client_id= broadviewuser_client&redirect_uri=http://localhost:8090/template/add&scope=read。用户输入用户名和密码之后登录(用户名和密码配置在UserServiceSecurityConfig类中),浏览器会自动跳转到http://localhost:8090/template/add?code=CODE,注意在跳转后的网址中会带有一个code参数。

(2)换取Access Token。

使用上一步中获取的CODE换取Access Token,具体命令如下:

(3)访问目标服务。

使用获得的Access Token访问目标服务即可。