JSP - 安全性



JavaServer Pages 和 servlet 为 Web 开发人员提供了多种保护应用程序的机制。通过在应用程序部署描述符中标识资源并为其分配角色,可以声明式地保护资源。

有多种身份验证级别可供选择,从使用标识符和密码的基本身份验证到使用证书的复杂身份验证。

基于角色的身份验证

servlet 规范中的身份验证机制使用一种称为基于角色的安全的技术。其思想是,与其在用户级别限制资源,不如创建角色并按角色限制资源。

您可以在位于 Tomcat 主目录下的 conf 文件夹中的tomcat-users.xml文件中定义不同的角色。下面显示此文件的一个示例:

<?xml version = '1.0' encoding = 'utf-8'?>
<tomcat-users>
   <role rolename = "tomcat"/>
   <role rolename = "role1"/>
   <role rolename = "manager"/>
   <role rolename = "admin"/>
   <user username = "tomcat" password = "tomcat" roles = "tomcat"/>
   <user username = "role1" password = "tomcat" roles = "role1"/>
   <user username = "both" password = "tomcat" roles = "tomcat,role1"/>
   <user username = "admin" password = "secret" roles = "admin,manager"/>
</tomcat-users>

此文件定义了用户名、密码角色之间简单的映射。请注意,给定用户可能具有多个角色;例如,用户名 = "both" 同时具有 "tomcat" 角色和 "role1" 角色。

定义不同的角色后,可以使用web.xml文件(位于 WEB-INF 目录下)中的<security-constraint>元素对不同的 Web 应用程序资源设置基于角色的安全限制。

以下是 web.xml 中的一个示例条目:

<web-app>
   ...
   <security-constraint>
      <web-resource-collection>
         <web-resource-name>SecuredBookSite</web-resource-name>
         <url-pattern>/secured/*</url-pattern>
         <http-method>GET</http-method>
         <http-method>POST</http-method>
      </web-resource-collection>
      
      <auth-constraint>
         <description>
            Let only managers use this app
         </description>
         <role-name>manager</role-name>
      </auth-constraint>
   </security-constraint>
   
   <security-role>
      <role-name>manager</role-name>
   </security-role>
   
   <login-config>
      <auth-method>BASIC</auth-method>
   </login-config>
   ...
</web-app>

以上条目意味着:

  • 任何对与 /secured/* 匹配的 URL 的 HTTP GET 或 POST 请求都将受到安全限制。

  • 具有管理员角色的人员可以访问受保护的资源。

  • login-config元素用于描述BASIC形式的身份验证。

如果您尝试浏览任何包含/security目录的 URL,则会显示以下对话框,要求您输入用户名和密码。如果您提供用户名"admin"和密码"secret",则您可以访问与/secured/*匹配的 URL,因为我们已将具有管理员角色的用户 admin 定义为允许访问此资源。

基于表单的身份验证

当您使用 FORM 身份验证方法时,必须提供登录表单以提示用户输入用户名和密码。以下是login.jsp的简单代码。这有助于创建用于相同目的的表单:

<html>
   <body bgcolor = "#ffffff">
      
      <form method = "POST" action ="j_security_check">
         <table border = "0">
            <tr>
               <td>Login</td>
               <td><input type = "text" name="j_username"></td>
            </tr>
            <tr>
               <td>Password</td>
               <td><input type = "password" name="j_password"></td>
            </tr>
         </table>
         <input type = "submit" value = "Login!">
         
      </form>
      
   </body>
</html>

您必须确保登录表单必须包含名为j_usernamej_password的表单元素。<form>标签中的 action 必须为j_security_check。必须使用POST作为表单方法。同时,您需要修改<login-config>标签以将 auth-method 指定为 FORM:

<web-app>
   ...
   <security-constraint>
      <web-resource-collection>
         <web-resource-name>SecuredBookSite</web-resource-name>
         <url-pattern>/secured/*</url-pattern>
            <http-method>GET</http-method>
            <http-method>POST</http-method>
      </web-resource-collection>
      
      <auth-constraint>
         <description>Let only managers use this app</description>
         <role-name>manager</role-name>
      </auth-constraint>
   </security-constraint>
   
   <security-role>
      <role-name>manager</role-name>
   </security-role>
   
   <login-config>
      <auth-method>FORM</auth-method>
      <form-login-config>
         <form-login-page>/login.jsp</form-login-page>
         <form-error-page>/error.jsp</form-error-page>
      </form-login-config>
   </login-config>
   ...
</web-app>

现在,当您尝试访问任何具有URL /secured/*的资源时,它将显示上述表单,要求您输入用户 ID 和密码。当容器看到“j_security_check”操作时,它将使用某些内部机制来验证调用者。

如果登录成功并且调用者有权访问受保护的资源,则容器将使用 session-id 从那时起识别调用者的登录会话。容器使用包含 session-id 的 cookie 来维护登录会话。服务器将 cookie 发送回客户端,只要调用者在后续请求中提供此 cookie,容器就会知道调用者是谁。

如果登录失败,则服务器将返回由 form-error-page 设置标识的页面。

这里,j_security_check是使用基于表单登录的应用程序必须为登录表单指定的 action。在同一表单中,还应该有一个名为j_username的文本输入控件和一个名为j_password密码输入控件。当您看到这一点时,这意味着表单中包含的信息将提交到服务器,服务器将检查名称和密码。这如何完成是特定于服务器的。

查看标准 Realm 实现以了解j_security_check如何在 Tomcat 容器中工作。

Servlet/JSP 中的程序化安全性

HttpServletRequest对象提供以下方法,可用于在运行时挖掘安全信息:

序号 方法和描述
1

String getAuthType()

getAuthType()方法返回一个 String 对象,该对象表示用于保护 Servlet 的身份验证方案的名称。

2

boolean isUserInRole(java.lang.String role)

isUserInRole()方法返回一个布尔值:如果用户具有给定角色,则为 true;如果没有,则为 false。

3

String getProtocol()

getProtocol()方法返回一个 String 对象,该对象表示用于发送请求的协议。此值可以检查以确定是否使用了安全协议。

4

boolean isSecure()

isSecure()方法返回一个布尔值,表示请求是否使用 HTTPS 发出。值为 true 表示已使用 HTTPS,连接安全。值为 false 表示未使用 HTTPS。

5

Principle getUserPrinciple()

getUserPrinciple()方法返回一个 java.security.Principle 对象,其中包含当前已验证用户的名称。

例如,对于链接到经理页面的 JavaServer Page,您可能具有以下代码:

<% if (request.isUserInRole("manager")) { %>
   <a href = "managers/mgrreport.jsp">Manager Report</a>
   <a href = "managers/personnel.jsp">Personnel Records</a>
<% } %>

通过检查 JSP 或 servlet 中用户的角色,您可以自定义网页以仅向用户显示她可以访问的项目。如果您需要用户在身份验证表单中输入的用户名,可以在请求对象中调用getRemoteUser方法。

广告