[Java EE 7] Servlet 安全机制
程序员文章站
2022-03-02 11:01:54
...
一般说来,servlet 会部署到 internet 上,因此需要一些安全性的考虑。你可以制定 servlet 的安全模式,例如角色、访问控制、鉴权等。这些都可以用 annotation 或 web.xml 进行配置。
@ServletSecurity 定义了安全约束,它可以添加在 servlet 实现类上,这样对 servlet 中的所有方法都生效,也可以单独添加在某个 doXXX 方法上,这样只针对这个方法有效。容器会强制调整 doXXX 方法被指定角色的用户调用:
在上面的代码段中,@HttpMethodConstraint 定义了 doGet 方法只能被角色为 R2 的用户调用,doPost 方法只能被角色为 R3 或 R4 的用户调用。@HttpConstraint 定义了其它的所有方法都能被角色为 R1 的用户调用。角色与用户映射容器的角色和用户。
安全约束也可以使用 web.xml 中的 <security-constraint> 元素来定义。在这个元素中,使用 <web-resource-collection> 元素来指定 HTTP 操作和 web 资源, 元素 <auth-constraint> 用来指定可以访问资源的角色,<user-data-constraint> 元素中使用 <transport-guarantee> 元素来指定客户端和服务器端的数据应该怎样被保护:
上面这段部署描述符表示:在 /account/* URL 上使用 GET 请求将会受到保护,访问的用户必须是 manager 角色,并且需要数据完整性。所有 GET 之外的其它 HTTP 请求都不会受到保护。 如果在 <security-constraint> 中没有明确指定 HTTP 方法的约束,那么默认所有的 HTTP 方法都会受到保护:
上面这段配置表示所有访问 /account/* URL 的 HTTP 方法都将受到保护。
从 Servlet 3.1 开始,规定了没有列入 <security-constraint> 中的 HTTP 方法称为“未被覆盖的方法”(uncovered,意思是在 security-constraint 中没有覆盖到此方法),并且在 <security-constraint> 中至少需要指定一个 <http-method> 元素:
上面的配置中,只有 GET 方法会受到保护,所有其它的 HTTP 方法,比如 PUT、POST 都是“未被覆盖的方法”。
在 <http-method-omission> 元素中可以指定哪些 HTTP 方法不受保护:
在上面的例子中,只有 HTTP GET 方法将不受保护,其它的 HTTP 方法将会受到保护。
<deny-uncovered-http-methods> 元素是 Servlet 3.1 中新增加的元素,用于阻止使用“未被覆盖的方法”进行访问。如果使用这个被阻止的 HTTP 方法进行访问,那么将会收到 403(SC_FORBIDDEN)错误状态码:
在上面的例子中,除了 HTTP GET 方法可以安全访问之外,其它所有的 HTTP 方法访问将会返回 403 错误码。
@RolesAllowed、@DenyAll、@PermitAll、和 @TransportProtected是用来进行安全配置的 Annotation:
如果同样的 annotation 被添加到类和方法上,那么方法级别的配置将覆盖类级别的配置。
Servlet 3.1 包含了两个预定义的角色:
* - 表示任意已定义的角色
** - 表示某个角色下的任意认证用户
这将允许你在更高的级别设置安全约束,而不仅仅只是针对某个角色。
同一个声明上,最多只能使用一个 @RolesAllowed、@DenyAll 或 @PermitAll 注释。@TransportProtected 可以和 @RolesAllowed 或 @PermitAll 进行组合。
可以将 Servlet 进行配置与基本 HTTP,HTTP Digest,HTTPS 客户端、或 form 表单进行权限认证。
上面的例子演示了如何使用 form-based 的方法进行验证。登陆表单必须包含用户名和密码,并且用户名和密码字段的名称必须分别是“j_username”和“j_password”,form 表单提交的 action 必须是 “j_security_check”。
Servlet 3.1 需要在密码字段上添加 autocomplete="off",用于进一步加强 form 表单的安全性。
HttpServletRequest 也提供了 login、logout 和 authenticate 方法,方便使用编码的方式来进行权限验证。
login() 方法将验证用户名和密码是否匹配在 ServletContext 中的配置(依赖 web 容器进行配置)的用户名密码。这将保证 getUserPrincipal、getRemoteUser、和 getAuthType 返回正确的值,使用 HttpServletRequest 提供的 login 方法可以取代上面使用的 form-based 验证。
authenticate() 方法将使用 ServletContext 的容器登陆机制来验证用户发起的这次请求。
文章来源:http://www.aptusource.org/2014/04/java-ee-7-servlet-security/
@ServletSecurity 定义了安全约束,它可以添加在 servlet 实现类上,这样对 servlet 中的所有方法都生效,也可以单独添加在某个 doXXX 方法上,这样只针对这个方法有效。容器会强制调整 doXXX 方法被指定角色的用户调用:
@WebServlet("/account") @ServletSecurity( value=@HttpConstraint(rolesAllowed = {"R1"}), httpMethodConstraints={ @HttpMethodConstraint(value="GET", rolesAllowed="R2"), @HttpMethodConstraint(value="POST", rolesAllowed={"R3", "R4"}) } ) public class AccountServlet extends javax.servlet.http.HttpServlet { //. . . }
在上面的代码段中,@HttpMethodConstraint 定义了 doGet 方法只能被角色为 R2 的用户调用,doPost 方法只能被角色为 R3 或 R4 的用户调用。@HttpConstraint 定义了其它的所有方法都能被角色为 R1 的用户调用。角色与用户映射容器的角色和用户。
安全约束也可以使用 web.xml 中的 <security-constraint> 元素来定义。在这个元素中,使用 <web-resource-collection> 元素来指定 HTTP 操作和 web 资源, 元素 <auth-constraint> 用来指定可以访问资源的角色,<user-data-constraint> 元素中使用 <transport-guarantee> 元素来指定客户端和服务器端的数据应该怎样被保护:
<security-constraint> <web-resource-collection> <url-pattern>/account/*</url-pattern> <http-method>GET</http-method> </web-resource-collection> <auth-constraint> <role-name>manager</role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>INTEGRITY</transport-guarantee> </user-data-constraint> </security-constraint>
上面这段部署描述符表示:在 /account/* URL 上使用 GET 请求将会受到保护,访问的用户必须是 manager 角色,并且需要数据完整性。所有 GET 之外的其它 HTTP 请求都不会受到保护。 如果在 <security-constraint> 中没有明确指定 HTTP 方法的约束,那么默认所有的 HTTP 方法都会受到保护:
<security-constraint> <web-resource-collection> <url-pattern>/account/*</url-pattern> </web-resource-collection> . . . </security-constraint>
上面这段配置表示所有访问 /account/* URL 的 HTTP 方法都将受到保护。
从 Servlet 3.1 开始,规定了没有列入 <security-constraint> 中的 HTTP 方法称为“未被覆盖的方法”(uncovered,意思是在 security-constraint 中没有覆盖到此方法),并且在 <security-constraint> 中至少需要指定一个 <http-method> 元素:
<security-constraint> <web-resource-collection> <url-pattern>/account/*</url-pattern> <http-method>GET</http-method> </web-resource-collection> . . . </security-constraint>
上面的配置中,只有 GET 方法会受到保护,所有其它的 HTTP 方法,比如 PUT、POST 都是“未被覆盖的方法”。
在 <http-method-omission> 元素中可以指定哪些 HTTP 方法不受保护:
<security-constraint> <web-resource-collection> <url-pattern>/account/*</url-pattern> <http-method-omission>GET</http-method-omission> </web-resource-collection> . . . </security-constraint>
在上面的例子中,只有 HTTP GET 方法将不受保护,其它的 HTTP 方法将会受到保护。
<deny-uncovered-http-methods> 元素是 Servlet 3.1 中新增加的元素,用于阻止使用“未被覆盖的方法”进行访问。如果使用这个被阻止的 HTTP 方法进行访问,那么将会收到 403(SC_FORBIDDEN)错误状态码:
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <deny-uncovered-http-methods/> <web-resource-collection> <url-pattern>/account/*</url-pattern> <http-method>GET</http-method> </web-resource-collection> . . . </web-app>
在上面的例子中,除了 HTTP GET 方法可以安全访问之外,其它所有的 HTTP 方法访问将会返回 403 错误码。
@RolesAllowed、@DenyAll、@PermitAll、和 @TransportProtected是用来进行安全配置的 Annotation:
@RolesAllowed("R2") protected void doGet(HttpServletRequest request, HttpServletResponse response) { //. . . }
如果同样的 annotation 被添加到类和方法上,那么方法级别的配置将覆盖类级别的配置。
Servlet 3.1 包含了两个预定义的角色:
* - 表示任意已定义的角色
** - 表示某个角色下的任意认证用户
这将允许你在更高的级别设置安全约束,而不仅仅只是针对某个角色。
同一个声明上,最多只能使用一个 @RolesAllowed、@DenyAll 或 @PermitAll 注释。@TransportProtected 可以和 @RolesAllowed 或 @PermitAll 进行组合。
可以将 Servlet 进行配置与基本 HTTP,HTTP Digest,HTTPS 客户端、或 form 表单进行权限认证。
<form method="POST" action="j_security_check"> <input type="text" name="j_username"> <input type="password" name="j_password" autocomplete="off"> <input type="button" value="submit"> </form>
上面的例子演示了如何使用 form-based 的方法进行验证。登陆表单必须包含用户名和密码,并且用户名和密码字段的名称必须分别是“j_username”和“j_password”,form 表单提交的 action 必须是 “j_security_check”。
Servlet 3.1 需要在密码字段上添加 autocomplete="off",用于进一步加强 form 表单的安全性。
HttpServletRequest 也提供了 login、logout 和 authenticate 方法,方便使用编码的方式来进行权限验证。
login() 方法将验证用户名和密码是否匹配在 ServletContext 中的配置(依赖 web 容器进行配置)的用户名密码。这将保证 getUserPrincipal、getRemoteUser、和 getAuthType 返回正确的值,使用 HttpServletRequest 提供的 login 方法可以取代上面使用的 form-based 验证。
authenticate() 方法将使用 ServletContext 的容器登陆机制来验证用户发起的这次请求。
文章来源:http://www.aptusource.org/2014/04/java-ee-7-servlet-security/