3.3 安全架构
本节描述 Jakarta EE 安全架构,本规范定义的安全要求均以此架构为基础。
3.3.1 设计目标
以下是 Jakarta EE 安全架构的目标:
可移植性:Jakarta EE 安全架构必须支持“一次编写,随处运行”(Write Once, Run Anywhere™)的应用特性。
透明性:应用组件开发者在编写应用时,无需了解任何安全相关知识。
隔离性:Jakarta EE 平台应能够根据部署人员通过部署属性设定、并由系统管理员管理的规则,执行身份认证与访问控制。
注意:将应用与安全责任相分离,可确保 Jakarta EE 应用具备更高的可移植性。
可扩展性:具备安全感知能力的应用在使用平台服务时,不得影响应用的可移植性。
本规范在组件编程模型中提供了用于与容器/服务器安全信息交互的 API。仅使用规范所提供 API 进行交互的应用,将保持可移植性。
灵活性:遵循本规范的应用所使用的安全机制与声明,不应强制限定某一种特定安全策略,而应支持针对特定 Jakarta EE 安装环境或应用实现专属安全策略。
抽象性:应用组件的安全需求将通过 Java 语言注解或部署描述符进行逻辑化定义。Java 注解或部署描述符将指定安全角色与访问需求如何映射到特定运行环境中的安全角色、用户及策略。部署人员可根据部署环境对安全属性进行合理修改。注解或部署描述符应明确说明哪些安全属性可修改、哪些不可修改。
独立性:必需的安全行为与部署契约应能够通过多种主流安全技术实现。
兼容性测试:Jakarta EE 安全需求架构的表述方式,应能够明确判定某一实现是否符合兼容要求。
安全互操作性:运行于某一厂商 Jakarta EE 产品中的应用组件,应能够调用另一厂商 Jakarta EE 产品提供的服务,无论二者采用相同还是不同的安全策略。这些服务可由 Web 组件或企业 Bean 提供。
3.3.2 非目标
以下内容不属于 Jakarta EE 安全架构的设计目标:
本规范不规定特定的安全策略。应用程序与企业信息系统所采用的安全策略,会因多种与本规范无关的因素而存在差异。产品提供商可在遵守本规范要求的前提下,提供实现和管理所需安全策略的相关技术。
本规范不强制要求使用某一特定安全技术,例如 Kerberos、公钥基础设施(PK)、NIS+ 或 NTLM。
本规范不要求 Jakarta EE 安全行为必须能够通过任意或全部安全技术通用实现。
本规范不对 Jakarta EE 产品的实际安全有效性提供任何担保或保证。
3.3.3 术语
本节介绍用于描述 Jakarta EE 平台安全需求的术语。
主体(Principal)
主体是指可由企业中部署的安全服务内的认证协议进行身份认证的实体。主体通过主体名进行标识,并使用认证数据完成认证。主体名与认证数据的内容和格式会随所使用的认证协议不同而有所差异。
安全策略域(Security Policy Domain)
安全策略域(也可简称为安全域)是指由安全服务的管理员定义并实施统一安全策略的作用范围。 安全策略域有时也被称作域(realm)。本规范统一使用安全策略域或安全域这一术语。
安全技术域(Security Technology Domain)
安全技术域是指采用同一安全机制(如 Kerberos)实施安全策略的作用范围。 例如,一个安全技术域可以包含多个安全策略域。
安全属性(Security Attributes)
每个主体都会关联一组安全属性。安全属性有多种用途(例如,访问受保护资源、对用户行为进行审计)。安全属性可由认证协议和/或 Jakarta EE 产品提供商关联至主体。 Jakarta EE 平台不规定与主体关联的具体安全属性内容。
凭证(Credential)
凭证包含或引用用于对 Jakarta EE 产品服务中的主体进行身份认证的信息(即安全属性)。主体在完成认证后会获取凭证,也可通过其他主体授权使用其凭证(即委托)。 本规范不规定凭证的内容或格式,凭证的内容与格式可能存在较大差异。
3.3.4 基于容器的安全
在 Jakarta EE 环境中,组件的安全由其所属容器提供,以此实现上述安全设计目标。容器提供两类安全机制(将在后续小节展开说明):
- 声明式安全
- 编程式安全
3.3.4.1 声明式安全
声明式安全指以非编程方式描述应用的安全结构,包括安全角色、访问控制和认证需求。在 Jakarta EE 平台中,Java 注解与部署描述符是实现声明式安全的主要方式。
Java 注解与部署描述符构成了应用组件开发者与部署者或应用组装者之间的契约。应用开发者可通过它们描述应用与安全相关的运行环境需求。部署描述符可与组件组关联使用。
部署者将应用安全策略的声明式描述,映射到特定环境对应的安全结构中,并使用部署工具处理注解与部署描述符。
运行时,容器依据从注解和部署描述符中提取、并由部署者配置的安全策略与安全结构,实施授权控制(参见授权模型)。
3.3.4.2 编程式安全
编程式安全是指由具备安全感知能力的应用自主做出安全相关决策。当仅依靠声明式安全不足以表达应用的安全模型时,编程式安全就显得尤为实用。用于实现编程式安全的 API 包含:Jakarta Security 中 SecurityContext 接口的方法、Jakarta Enterprise Beans 中 EJBContext 接口的方法,以及 Servlet 中 HttpServletRequest 接口的方法。其中,SecurityContext 接口的方法旨在替代 EJBContext 和 HttpServletRequest 接口中对应的方法。
通过这些方法,组件可基于调用方或远程用户的安全角色做出业务逻辑决策。例如,组件可获取调用方或远程用户的主体名称,并将其用作数据库主键。 (注:主体名称的格式与内容在不同产品和企业间差异较大,具备可移植性的组件不应依赖主体名称的实际内容。受主体名称映射机制影响,同一个逻辑主体在不同容器中可能对应不同名称;不过通常可对单一产品进行配置,以使用统一的主体名称。特别需要注意的是,若将主体名称用作数据库表的查询键,且该数据库表会被多个组件、容器或产品访问,同一个逻辑主体可能会映射到数据库中的不同记录。)
3.3.5 分布式安全
部分产品提供商可能会推出各类组件容器呈分布式部署的 Jakarta EE 产品。在分布式环境中,Jakarta EE 组件之间的通信可能面临安全攻击(例如数据篡改与重放攻击)。
此类威胁可通过建立安全关联保障通信安全来抵御。安全关联是共享的安全状态信息,为组件间的安全通信奠定基础。建立安全关联通常包含多个步骤,例如:
- 向客户端验证目标主体身份,和/或向目标主体验证客户端身份。
- 协商保护等级,如数据保密性或完整性。
- 为组件间的关联建立安全上下文。
在 Jakarta EE 中,安全由容器提供,因此组件的安全关联通常由容器负责建立。本文档规定了 Web 访问的安全关联规范,而企业 Bean 访问的安全关联则在 Jakarta Enterprise Beans 规范中进行说明。
产品提供商可允许在部署阶段对保护等级或安全关联的其他属性进行管控。应用程序可通过注解或部署描述符中的元素,声明其访问 Web 资源的安全需求。
本规范未定义应用组件开发者可用于传递企业 Bean 安全关联需求的通信机制。
3.3.6 授权模型
Jakarta EE 授权模型基于安全角色这一概念。安全角色是由应用组件开发者或应用组装者定义的用户逻辑分组。部署者会将角色映射到运行环境中的安全身份(例如主体、用户组)。安全角色同时适用于声明式安全和编程式安全。
声明式授权可用于控制对企业 Bean 方法的访问,通过注解或企业 Bean 部署描述符进行指定。@RolesAllowed、@PermitAll 和 @DenyAll 注解用于声明方法访问权限。企业 Bean 方法也可通过部署描述符中的 method-permission 元素进行关联。该元素包含可由指定安全角色访问的方法列表。如果调用方主体属于允许访问该方法的任一安全角色,则允许其执行该方法;反之,若调用方主体不属于任一授权角色,则不允许执行。对 Web 资源的访问也可采用类似方式进行保护。
安全角色还用于 SecurityContext 中的 isCallerInRole 方法、EJBContext 中的 isCallerInRole 方法以及 HttpServletRequest 中的 isUserInRole 方法。若调用方主体属于指定的安全角色,这些方法均会返回 true。
3.3.6.1 角色映射
无论是通过编程式还是声明式方式对 Web 资源或企业 Bean 实施安全约束,都需要判断与传入请求关联的主体是否属于指定的安全角色。容器会根据调用方主体的安全属性做出这一判断。例如:
部署者可以将安全角色映射到运行环境中的用户组,也可以采用 Jakarta Security 规范中定义的安全角色到用户组的默认映射。在这种情况下,容器从调用方主体的安全属性中获取其所属用户组。如果该用户组与安全角色所映射的用户组一致,则判定该主体属于此安全角色。
部署者也可以将安全角色映射到安全策略域中的某个主体名称。此时,容器从调用方主体的安全属性中获取其主体名称。若该主体名称与安全角色所映射的主体名称一致,则判定调用方主体属于此安全角色。
在不同的 Jakarta EE 平台实现中,安全属性的来源可能有所不同。安全属性可以通过调用方主体的凭证或安全上下文进行传递;在其他场景下,安全属性也可以从身份存储库,或目录服务、安全服务等可信第三方获取。
3.3.7 HTTP 登录网关
不同安全策略域中企业 Bean 之间的安全互操作性问题在《Jakarta 企业 Bean 规范》中已有阐述。此外,组件还可以选择通过 HTTP 登录到外部服务器。应用组件在使用 HTTP 访问远程资源时,可配置为采用 SSL 双向认证保障安全。以这种方式使用 HTTP 的应用,可选择 XML 或其他结构化格式,而非 HTML。
我们将使用 HTTP 配合 SSL 双向认证来访问远程服务的方式称为 HTTP 登录网关。该领域的相关要求在“Web 客户端身份认证”部分中进行了规定。
3.3.8 用户认证
用户认证是用户向系统证明其身份的过程。该通过认证的身份将用于对 Jakarta EE 应用组件的访问进行授权判定。最终用户可通过两种受支持的客户端类型之一完成认证:
- Web 客户端
- 应用客户端
3.3.8.1 Web 客户端身份认证
规范要求,Web 客户端必须能够使用以下任意一种机制,向 Web 服务器完成用户身份认证。具体采用哪种方式,由部署人员或系统管理员针对单个应用或一组应用进行确定。
HTTP 基本认证
HTTP 基本认证是 HTTP 协议原生支持的认证机制,基于用户名和密码实现。Web 服务器会要求 Web 客户端对用户进行认证;在请求过程中,Web 服务器会传递用户待认证的域。Web 客户端从用户处获取用户名和密码,并发送给 Web 服务器;随后服务器在指定域(本文档中称为 HTTP 域)内完成用户认证。
HTTP 基本认证并不安全:密码仅以简单的 Base64 编码传输,且目标服务器不会被认证。可以通过额外防护手段弥补这些缺陷,例如在传输层启用安全保护(如 HTTPS),或在网络层使用 IPsec、VPN 等技术。
尽管存在上述局限,本规范仍纳入 HTTP 基本认证,原因是它在基于表单的应用中被广泛使用。
HTTPS 客户端认证
基于 HTTPS(SSL 加密 HTTP)的终端用户认证属于强认证机制。该机制要求用户持有公钥证书(PKC)。目前公钥证书在互联网终端用户中尚不普及,但在电子商务应用、浏览器内单点登录等场景中非常实用。因此,HTTPS 客户端认证是 Jakarta EE 平台的必选功能。
基于表单的认证
使用浏览器内置的认证机制无法自定义登录界面的外观与交互风格。本规范支持将标准 HTML、Servlet、JSP 或 Jakarta Faces 表单用于登录,从而实现用户界面定制化。规范中定义的基于表单的认证机制,具体说明详见 Servlet 规范。
HTTP 摘要认证
HTTP 摘要认证在浏览器中支持度不高,因此不属于必选要求。
Web 客户端可以将 Web 服务器作为其认证代理。在此模式下,客户端的凭证在服务器上创建,服务器可将其用于多种用途:执行授权判定、以客户端身份调用企业 Bean,或与资源协商建立安全关联。当前主流 Web 浏览器普遍支持代理认证。
3.3.8.2 Web 单点登录
HTTP 是一种无状态协议。然而,许多 Web 应用需要支持会话,以便在客户端的多次请求之间维持状态。因此,理想的设计应满足以下要求:
- 将登录机制与策略作为 Web 应用部署环境的一项属性。
- 能够使用同一个登录会话,向所有被访问的应用标识同一用户身份。
- 仅在跨越安全策略域边界时,才要求用户重新进行身份认证。
通过 Web 登录过程获取的凭证与会话相关联。容器使用这些凭证为该会话建立安全上下文。容器通过安全上下文来判定对 Web 资源的访问权限,以及与其他组件(包括企业 Bean)建立安全关联。
3.3.8.3 登录会话
在 Jakarta EE 平台中,登录会话支持由 Web 容器提供。当用户在 Web 服务器上成功完成身份认证后,容器会为该用户建立登录会话上下文。登录会话中包含与该用户关联的凭证。
3.3.8.4 应用客户端身份认证
应用客户端(详见“应用客户端”章节)是可以直接与企业 Bean 交互的客户端程序(即无需借助浏览器,也不必经过 Web 服务器)。应用客户端也可以访问 Web 资源。
与其他 Jakarta EE 应用组件类型一样,应用客户端运行在由对应容器提供的托管环境中。应用客户端应能够访问图形显示设备与输入设备,并与人类用户进行交互。
当终端用户访问受保护的 Web 资源或企业 Bean 时,由应用客户端负责完成用户在 Jakarta EE 平台上的身份认证。
3.3.9 延迟认证
认证过程会产生相应开销。例如,认证流程可能需要在网络上交换多条消息。因此,延迟认证是更优选择,即仅在需要时才执行认证。 采用延迟认证时,直到出现访问受保护资源的请求,才要求用户进行身份认证。
延迟认证可用于前端应用客户端,当它们请求访问需要认证的受保护资源时触发。此时系统会提示用户提供相应的认证信息。若用户认证成功,则允许其访问该资源。
