javaweb登录界面_Java Web容器安全

这里的Java Web容器特指Tomcat,Tomcat依然是最流行的Java Web容器,你大爷还是你大爷。

ef80684287f34d1fdba804c86c59efcd.png

本文并不涉及业务层面上的安全控制,只针对Tomcat自身所支持的相关安全控制功能与特性。

首先看一下Web容器的四个基本安全特性

  • 验证 Authentication
  • 资源访问控制 Access control for resources
  • 数据完整性 Data Integrity
  • 数据机密性或私密性 Confidentiality or Data Privacy

每一项的细节这里不展开,并不难理解。

Java EE使用基于角色的访问控制——有用户、组、角色三个基本概念。

存储用户名和密码的地方叫Realm,有可能是文件,比如Tomcat的tomcat-users.xml,也可能是数据库,或者基于证书的机制。

Tomcat支持声明式验证和编程式验证,一个是基于XML配置,一个是通过代码实现。

声明式基本身份验证

在web.xml中定义

<login-config>
    <auth-method>BASIC</auth-method>
</login-config>

同时可以定义角色

<security-role>
    <description>Admin User</description>
    <role-name>admin</role-name>
</security-role>
<security-role>
    <description>Manager</description>
    <role-name>manager</role-name>
</security-role>

针对路径做控制

<security-constraint>
    <web-resource-collection>
        <web-resource-name>Admin</web-resource-name>
        <url-pattern>/admin/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>admin</role-name>
    </auth-constraint>
</security-constraint>

连HTTP方法也能配置

<security-constraint>
    <web-resource-collection>
        <web-resource-name>Manager</web-resource-name>
        <url-pattern>/manager/*</url-pattern>
        <http-method>GET</http-method>
        <http-method>POST</http-method>
        <!-- 这是取反
        <http-method-omission>GET</http-method-omission>
        -->
    </web-resource-collection>
    <auth-constraint>
        <role-name>admin</role-name>
        <role-name>manager</role-name>
        <!--表示任一通过验证的用户
        <role-name>**</role-name>
        -->
    </auth-constraint>
</security-constraint>
<!-- 除了GET POST 其他HTTP方法即便是admin manager也无法访问 -->

<!-- 加上这个标签后,对于不在<security-constraint>里的HTTP方法请求,会返回403 -->
<deny-uncovered-http-methods />

部署后,根据各服务器来配置用户和角色,比如Tomcat的就在conf/tomcat-users.xml里。

Tomcat的验证过程如下

  1. 初次访问某个受保护的URI,Web容器会检查请求中是否包括Authorization头,如果没有,容器会返回401,以及WWW-Authenticate标头给浏览器,浏览器收到后会弹出对话框要求用户输入名称和密码。
  2. 如果用户输入用户名、密码正确后,浏览器会将用户名、密码以BASE64方式编码,然后放在Authorization标头中送出,容器进行验证,正确就将资源传回。
  3. 在关闭浏览器之前,对服务器的请求都包括Authorization头,服务器也每次都检查,所以登录有效期一直持续到关闭浏览器为止。

现在实验步骤如下

在Tomcat9目录下,修改conf/tomcat-users.xml文件,解注并新增admin的角色

<role rolename="admin"/>
<role rolename="tomcat"/>
<role rolename="role1"/>
<user username="tomcat" password="123456" roles="tomcat,admin"/>
<user username="both" password="123456" roles="tomcat,role1"/>
<user username="role1" password="123456" roles="role1"/>

在webapps目录下,新建test目录和/WEB-INF/web.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<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_4_0.xsd"
  version="4.0"
  metadata-complete="true">
​
    <description>
      Servlet and JSP Examples.
    </description>
    <display-name>Servlet and JSP Examples</display-name>
​
    <request-character-encoding>UTF-8</request-character-encoding>
​
    <security-constraint>
      <display-name>Example Security Constraint</display-name>
      <web-resource-collection>
         <web-resource-name>Protected Area - Allow methods</web-resource-name>
         <url-pattern>/admin/*</url-pattern>
         <http-method>DELETE</http-method>
         <http-method>GET</http-method>
         <http-method>POST</http-method>
         <http-method>PUT</http-method>
      </web-resource-collection>
      <auth-constraint>
         <role-name>admin</role-name>
         <role-name>manager</role-name>
      </auth-constraint>
    </security-constraint>
    <login-config>
      <auth-method>BASIC</auth-method>
    </login-config>
​
    <!-- 定义角色名称 -->
    <security-role>
      <role-name>admin</role-name>
    </security-role>
    <security-role>
      <role-name>manager</role-name>
    </security-role>
</web-app>

新建/admin目录和/test.html文件,

访问http://localhost:8080/test/admin/test.html,第一次会打开对话框

101d8df4e61b9c129b6b52b0adde41fc.png

输入正确后,查看请求可以看到Authorization

a16fc05a49adbc59bc6c94c3f83a1300.png

注意这种方式几乎跟裸奔没区别,只要能拦截到你的HTTP请求,就相当于查看到你的密码。上面Basic后的字符串用base64解密就是tomcat:123456。

如果需要自定义登录窗口,可以配置

<login-config>
      <auth-method>FORM</auth-method>
      <form-login-config>
          <form-login-page>/login.html</form-login-page>
          <form-error-page>/error.html</form-error-page>
      </form-login-config>
</login-config>

登录表单的action和name属性是有要求的

<form method="POST" action='j_security_check' >
    <input type="text" name="j_username">
    <input type="password" name="j_password">
    <input type="submit" value="Log In">
</form>

除了FORM和BASIC,<auth-method>还可以设置为DIGESTCLIENT_CERTDIGEST提交时传递的是MD5加密后的摘要,CLIENT_CERT使用的是Public Key Certificate(PKC)加密,客户端要安装证书。

如果要启用HTTPS,则在<security-constraint>下设置

<user-data-constraint>
    <transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>

默认值是NONE,还可以设置为INTEGRAL,不过习惯设为CONFIDENTIAL,效果一样。

设置完后,认证的时候会自动跳转为HTTPS

43e600bf84ab67f5b14cb626631328dc.png

编程式安全管理

支持编程能带来更灵活的控制。HttpServletRequest里跟安全有关的方法有

  • authenticate( ): 是否登录,如果没有,返回false,并会转到登录界面
  • login( ): 登入
  • logout( ): 登出
  • getUserPrincipal( ): 取得代表用户的Principal对象
  • getRemoteUser( ): 获得登录用户的名称
  • isUserInRole(String role): 传入角色名称,检查登录用户是否属于该角色
@WebServlet("/secret")
public class User extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
        throws ServletException, IOException {
          if (request.authenticated(response)) { // 检查登录
              // 执行登录后的用户能够做的事情
          }
}

@WebServlet("/login")
public class Login extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
        throws ServletException, IOException {
          String username = request.getParameter("user");
          String password = request.getParameter("passwd");
          try {
                request.login(username, password);
                response.sendRedirect("user");
          } catch( ServletException ex) {
                response.sendRedirect("login.html");
          }
}

<security-constraint>对标的注解是@ServletSecurity,比如

@WebServlet("/admin")
@ServletSecurity(@HttpConstraint(rolesAllowed = {"admin"}))

就表示/admin只允许admin角色访问。

再看一个复杂一点的

@WebServlet("/admin")
@ServletSecurity(
    value=@HttpConstraint(rolesAllowed = { "admin", "manager" }),
    httpMethodConstraints = {
        @HttpMethodConstraint(value = "GET", rolesAllowed = {"admin", "manager"}, 
               transportGuarantee = TransportGuarantee.CONFIDENTIAL),
        @HttpMethodConstraint(value = "POST", rolesAllowed = {"admin", "manager"}),
)

其它Realm

前面的例子都是把用户名密码放在配置文件里,这样带来一定的隐患,在Tomcat里也支持其它的Realm,比如

  • JDBCRealm
  • DataSourceRealm
  • JNDIRealm
  • UserDatabaseRealm
  • MemoryRealm
  • JAASRealm
  • CombinedRealm
  • LockOutRealm

具体的用法可以查看官方文档Realm Configuration How-To

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值