欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Tomcat常用的过滤器

程序员文章站 2022-07-05 15:37:31
前言 之前我很肤浅的以为为了实现某种请求过滤功能(比如图片转换、文件上传、安全认证等),都需要自己去实现javax.servlet.Filter。之后在web.xml中配置即可。 但事实上,Tomcat已经提供了部分相关的过滤器(本文只介绍常用的7个过滤器),只需要简单配置就可以使用。最近通过系统学 ......

前言

  之前我很肤浅的以为为了实现某种请求过滤功能(比如图片转换、文件上传、安全认证等),都需要自己去实现javax.servlet.filter。之后在web.xml中配置即可。

  但事实上,tomcat已经提供了部分相关的过滤器(本文只介绍常用的7个过滤器),只需要简单配置就可以使用。最近通过系统学习tomcat架构之后,结合部分源码记录总结最常用的几种过滤器。

  参考资料《tomcat架构解析》(有需要pfd电子书的朋友可以评论或者私信),tomcat官方filter配置(tomcat 8为例)

 

 


 

 

一、跨域过滤器corsfilter

  org.apcache.catalina.filters.corsfilter是跨域资源共享规范的一个实现,常常用于前后端分离,静态资源与后端分离等情况。它主要在httpservletresponse中增加access-control-*头,同时保护http响应避免拆分,如果请求无效或者禁止访问,则返回403响应码。

配置示例

<filter>
  <filter-name>corsfilter</filter-name>
  <filter-class>org.apache.catalina.filters.corsfilter</filter-class>
  <init-param>
    <param-name>cors.allowed.origins</param-name>
    <param-value>*</param-value>
  </init-param>
  <init-param>
    <param-name>cors.allowed.methods</param-name>
    <param-value>get,post,head,options,put</param-value>
  </init-param>
  <init-param>
    <param-name>cors.allowed.headers</param-name>
    <param-value>content-type,x-requested-with,accept,origin,access-control-request-method,access-control-request-headers</param-value>
  </init-param>
  <init-param>
    <param-name>cors.exposed.headers</param-name>
    <param-value>access-control-allow-origin,access-control-allow-credentials</param-value>
  </init-param>
  <init-param>
    <param-name>cors.support.credentials</param-name>
    <param-value>true</param-value>
  </init-param>
  <init-param>
    <param-name>cors.preflight.maxage</param-name>
    <param-value>10</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>corsfilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

 

参数说明

  1、cors.allowed.origins

    允许访问的跨域资源列表,"*"表示允许访问来自任何域的资源,多个域用逗号分隔,默认为"*"

  2、cors.allowed.methods

    可以用于访问资源的http方法列表,","分隔,用于跨域请求。这些方法将出现在prefligh(预检请求)响应头access-control-allow-methods的一部分,t默认为"get, post, head, options"

  3、cors.allowed.headers

    构造请求时可以使用的请求头,以","分隔,这些方法将出现在prefligh(预检请求)响应头access-control-allow-headers的一部分,默认为origin, accept, x-requested-with, content-type, access-control-request-method, access-control-request-headers

  4、cors.exposed.headers

    浏览器允许访问的头部信息列表,","分隔。这些方法将出现在prefligh(预检请求)响应头access-control-allow-headers的一部分,默认为空。

  5、cors.preflight.maxage

    浏览器允许缓存的preflght请求结果的时间,单位为秒。如果为负数,则表示corsfilter不会添加头到preflight响应,这些方法将出现在prefligh(预检请求)响应头access-control-max-age的一部分,默认为1800.

  6、cors.support.credentials

    表示资源是否支持用户证书,这些方法将出现在prefligh(预检请求)响应头access-control-allow-credentials的一部分,默认为true

  7、cors.request.decorate

    cors规范属性是否已经添加到httpservletrequest,默认为true。corsfiter会为httpservletrequest添加请求相关信息,cors.request.decorate配置为true,那么以下属性将会被添加

    1)cors.iscorsrequest: 用于请求是否为cors请求。

    2)cors.request.origin: 源url,请求源自的页面url。

    3)cors.request.type: cors的请求类型,如下:

      simple: 非preflight请求为先导的请求。

      actual: 以preflight请求为先导的请求。

      pre_flight: preflight请求

      not_cors: 正常同域请求

      invalid_cors: 无效的域请求

    4)cors.request.headers: 作为preflight请求access-control-request-header头发送的请求头信息。

 

 

二、csrf保护过滤器csrfpreventionfilter

  org.apcache.catalina.filters.csrfpreventionfilter为web应用提供了基本的csrf保护。返回的客户端的所有链接均通过httpservletresponse.encoderedirecturl(string)与httpservletresponse.encodeurl(string)进行编码,该过滤器生成一个随机数并存储到会话session中进行对比,url使用该随机数进行编码。当接收到下一个请求时,请求中随机数与会话中的进行对比,只有两者相同时,请求才会被允许。

配置示例

<filter>
        <filter-name>csrfpreventionfilter</filter-name>
        <filter-class>org.apache.catalina.filters.csrfpreventionfilter</filter-class>
        <init-param>
            <param-name>denystatus</param-name>
            <param-value>403</param-value>
        </init-param>
        <init-param>
            <param-name>entrypoints</param-name>
            <param-value>/html,/html/list</param-value>
        </init-param>
        <init-param>
            <param-name>noncecachesize</param-name>
            <param-value>5</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>csrfpreventionfilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

 

参数说明

  1、denystatus:http响应吗,用于驳回拒绝请求,默认为403

  2、entrypoints:以","为分隔的url列表,这些列表将不会进行随机数检测(主要用于通过导航离开受保护应用,之后再返回) 

 if ("get".equals(req.getmethod()) && this.entrypoints.contains(this.getrequestedpath(req))) {
                skipnoncecheck = true;
 }

  3、noncecachesize:随机数缓存大小。先前发布的随机数被缓存到一个lru缓存中以支持并发请求,有限的用于浏览器刷新等行为(可能导致随机数不是当前的),默认为5

private int noncecachesize = 5;
....
if (noncecache == null) {
    noncecache = new csrfpreventionfilter.lrucache(this.noncecachesize);
      if (session == null) {
           session = req.getsession(true);
       }

    session.setattribute("org.apache.catalina.filters.csrf_nonce", noncecache);
}

  4、randomclass:用于生成随机数的类,必须是java.util.random实例,如不设置默认为java.security.securerandom

三、防止参数丢失过滤器failedrequestfilter

  org.apcache.catalina.filters.failedrequestfilter用于触发请求的参数解析,当参数解析失败时,将会拒绝请求,该filter用于确保客户端提交的参数信息不发生丢失。该过滤器的原理是:先调用servletrequest.getparameter(首次调用会触发tomcat服务器的请求参数解析,如果参数解析失败,将结果放到请求属性org.apache.catalina.parameter_parse_failed中),之后判断属性org.apache.catalina.parameter_parse_failed的值,如果不为空则直接返回400。

  为了能正确解析参数,需要该filter之前设置字符集编码过滤器setcharacterencodingfilter。此外,该过滤器是不支持r初始化参数的

// 判断是否为有效的请求:org.apache.catalina.parameter_parse_failed为null
private boolean isgoodrequest(servletrequest request) {
        request.getparameter("none");
        return request.getattribute("org.apache.catalina.parameter_parse_failed") == null;
    }

四、获取客户端ip过滤器remoteaddrfilter

  org.apcache.catalina.filters.remoteaddrfiler允许比较提交的客户端ip地址(通过servletrequest.getremoteaddr获取)是否符合指定正则表达式。

配置示例

    <filter>
      <filter-name>remote address filter</filter-name>
      <filter-class>org.apache.catalina.filters.remoteaddrfilter</filter-class>
      <init-param>
        <param-name>allow</param-name>
        <param-value>127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1</param-value>
      </init-param>
    </filter>
    <filter-mapping>
      <filter-name>remote address filter</filter-name>
      <url-pattern>/*</url-pattern>
    </filter-mapping>

参数说明

  1、allow:指定允许访问的客户端ip地址

  2、deny:拒绝访问的客户端地址

  3、denystatus:拒绝请求时返回的http响应吗。

五、获取客户端host过滤器remotehostfilter

  org.apcache.catalina.filters.remotehostfiler允许比较提交请求的客户端主机名是否符合指定的正则表达式,以确定是否允许继续处理请求。参数同remoteaddrfilter

六、获取原始客户端ip过滤器remoteipfilter

    当客户端通过http代理或者负载均衡访问服务器时,对于服务器来说,请求直接源自前置的代理服务器,此时获取到的远程ip实际为代理服务器的ip地址。

      这时候如何获得原始的客户端的ip地址呢?

      http协议通过x-forwarded-for头信息记录了资客户端到应用服务器前置代理的ip地址,remoteipfilter通过解析该请求头,将请求中的ip地址与主机名替换为客户端真实的ip地址和主机信息,此外还可以通过x-forwardred-proto请求头替换当前的协议名称http/https、服务器端口及request.secure。

      x-forwarded-for的格式如下:

      x-forwarded-for:  client, proxy1, proxy2

      最左侧client为最原始的客户端ip,如上示例中客户端经过了proxy1、proxy2、proxy3三级代理(最后一层proxy3不显示,通过servletrquest.getremoteaddr获取)。在负载均衡的情况下,remoteaddrfilter和remotehostfilter需要与该过滤器配合使用,否则无法正确限制访问客户端。

  通常我们获取x-forwarded-for使用如下java代码:

 public static string getip(httpservletrequest request) {
        string requestaddr = request.getheader("x-forwarded-for");
        if (requestaddr == null || requestaddr.length() == 0 || "unknown".equalsignorecase(requestaddr)) {
            requestaddr = request.getheader("proxy-client-ip");
        }

        if (requestaddr == null || requestaddr.length() == 0 || "unknown".equalsignorecase(requestaddr)) {
            requestaddr = request.getheader("wl-proxy-client-ip");
        }

        if (requestaddr == null || requestaddr.length() == 0 || "unknown".equalsignorecase(requestaddr)) {
            requestaddr = request.getremoteaddr();
        }

        return requestaddr;
    }

 

 

 

配置示例

  1)基本处理x-forwarded-for头的配置

  <filter>
        <filter-name>remoteipfilter</filter-name>
        <filter-class>org.apache.catalina.filters.remoteipfilter</filter-class>
      </filter>

      <filter-mapping>
        <filter-name>remoteipfilter</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>request</dispatcher>
      </filter-mapping>

  2)处理x-forwarded-for与x-forwarded-proto头部的配置

  <filter>
        <filter-name>remoteipfilter</filter-name>
        <filter-class>org.apache.catalina.filters.remoteipfilter</filter-class>
        <init-param>
          <param-name>protocolheader</param-name>
          <param-value>x-forwarded-proto</param-value>
        </init-param>
      </filter>

      <filter-mapping>
        <filter-name>remoteipfilter</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>request</dispatcher>
      </filter-mapping>

  3)使用内部代理的高级配置

 <filter>
       <filter-name>remoteipfilter</filter-name>
       <filter-class>org.apache.catalina.filters.remoteipfilter</filter-class>
       <init-param>
         <param-name>allowedinternalproxies</param-name>
         <param-value>192\.168\.0\.10|192\.168\.0\.11</param-value>
       </init-param>
       <init-param>
         <param-name>remoteipheader</param-name>
         <param-value>x-forwarded-for</param-value>
       </init-param>
       <init-param>
         <param-name>remoteipproxiesheader</param-name>
         <param-value>x-forwarded-by</param-value>
       </init-param>
       <init-param>
         <param-name>protocolheader</param-name>
         <param-value>x-forwarded-proto</param-value>
       </init-param>
     </filter>

  4)使用可信任代理高级配置

<filter>
       <filter-name>remoteipfilter</filter-name>
       <filter-class>org.apache.catalina.filters.remoteipfilter</filter-class>
       <init-param>
         <param-name>allowedinternalproxies</param-name>
         <param-value>192\.168\.0\.10|192\.168\.0\.11</param-value>
       </init-param>
       <init-param>
         <param-name>remoteipheader</param-name>
         <param-value>x-forwarded-for</param-value>
       </init-param>
       <init-param>
         <param-name>remoteipproxiesheader</param-name>
         <param-value>x-forwarded-by</param-value>
       </init-param>
       <init-param>
         <param-name>trustedproxies</param-name>
         <param-value>proxy1|proxy2</param-value>
       </init-param>
     </filter>

 

七、字符集编码过滤器setcharacterencodingfilter

  提供了一种设置字符集编码的方式,通常情况下默认iso-8859-1编码,但实际生产环境推荐使用utf-8编码,而请求中的编码可以在未指定编码时使用,也可以强制覆盖。

配置示例

<filter>
        <filter-name>setcharacterencodingfilter</filter-name>
        <filter-class>org.apache.catalina.filters.setcharacterencodingfilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
        <init-param>
            <param-name>ignore</param-name>
            <param-value>false</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>setcharacterencodingfilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

参数说明

  1、encoding:指定的字符集编码  

  2、ignore:表示是否忽略客户端请求设置的字符集编码,如果为true那么都会将请求字符集编码覆盖,如果为false,请求没有指定字符集编码时设置。默认为false