概念
filter,过滤器,顾名思义,即在执行相关请求时,通过过滤器可以将请求拦截,并作出处理,再对请求放行,从而达到对请求拦截能力;比如,客户端提交数据时的敏感词过滤,编码的统一过滤,登录过滤等。
Filter的实现原理
Filter创建与使用
- 创建类实现Filter接口
- 实现doFilter方法
- 配置Filter
a. 基于注解配置(添加@WebFilter(需要过滤的内容)注解)
b. 通过web.xml配置(web-app标签内添加)
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>filter.EncodeingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>gbk</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
常用过滤器
编码过滤
package filter;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* @author bxwl
* @create 2020-08-27 12:06
*/
@WebFilter("/*")
public class EncodeingFilter implements Filter {
//存储当前编码格式
String encoding;
//过滤器初始化
@Override
public void init(FilterConfig config) throws ServletException {
encoding = config.getInitParameter("encoding");
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//默认设为urf-8
encoding = encoding == null ? "utf-8":encoding;
//分别设置编码格式
req.setCharacterEncoding(encoding);
resp.setCharacterEncoding(encoding);
//放行
chain.doFilter(req, resp);
}
}
非法访问过滤
登录页面:login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录</title>
</head>
<body>
<h1>用户登录</h1>
<br>
<form action="user">
<input type="hidden" name="method" value="login">
<input type="text" name="username" placeholder="请输入用户名"><br>
<input type="password" name="password" placeholder="请输入密码"><br>
<button>登录</button>
</form>
<p style="color: red;">${msg}</p>
</body>
</html>
admin目录下的modifyPwd.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>修改密码</title>
</head>
<body>
<p>修改密码</p>
</body>
</html>
过滤器:
package filter;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author bxwl
* @create 2020-08-27 11:39
*/
@WebFilter("/admin/*")
public class LoginFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//将servletRequest转换为HttpServletRequest
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)resp;
//从session中获取用户信息
Object obj = request.getSession().getAttribute("user");
if(obj != null){
//用户已登陆,放行
chain.doFilter(request,response);
}else{
//跳转到登录页面
request.setAttribute("msg","请登录后在访问该页面!");
request.getRequestDispatcher("/login.jsp").forward(request,response);
}
}
}
效果图:
XSS过滤
XSS(Cross Site Scripting),跨站脚本攻击,是一种常见的网络攻击方式,通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法(比如表单提交时输入脚本代码或者网页代码)注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。
使用的依赖包:
commons-lang3-3.11.jar
commons-text-1.9.jar
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="user">
<input type="hidden" name="method" value="comm">
<input type="text" name="nickname" placeholder="请输入昵称"><br>
<textarea name="content" cols="50" rows="5" placeholder="请输入评论内容"></textarea><br><br>
<button>发表评论</button>
</form>
</body>
</html>
请求包装器:
package wrapper;
import org.apache.commons.text.StringEscapeUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* 请求包装器:用于包装HttpServletRequest对象
* 可以对请求的参数进行处理,替换敏感词等
* @author bxwl
* @create 2020-08-27 14:06
*/
public class XSSRequest extends HttpServletRequestWrapper {
public XSSRequest(HttpServletRequest request) {
super(request);
}
@Override
public String getParameter(String name) {
String content = super.getParameter(name);
return handler(content);
}
@Override
public String[] getParameterValues(String name) {
String[] oldData = super.getParameterValues(name);
return handlerArray(oldData);
}
@Override
public Map<String, String[]> getParameterMap() {
Map<String, String[]> oldMap = super.getParameterMap();
Map<String, String[]> newMap = new ConcurrentHashMap<>();
//获取所有键的集合
Set<String> keys = oldMap.keySet();
for(String s:keys){
String[] value = oldMap.get(s);
String[] newData = handlerArray(value);
newMap.put(s,newData);
}
return newMap;
}
/**
* 处理传入的文本内容,将其处理为合法的内容并返回
* @param data
* @return
*/
public String handler(String data){
// return data.replace("<","<").replace(">",">");
//将文本数据忽略html解析器,以普通文本返回
return StringEscapeUtils.escapeHtml4(data);
}
/**
* 将原始数据处理后返回新数组
* @param oldData
* @return
*/
public String[] handlerArray(String[] oldData){
//当原始数据不存在返回
if(oldData == null || oldData.length <= 0){
return null;
}
String[] newData = new String[oldData.length];
for (int i = 0; i < oldData.length; i++) {
newData[i] = handler(oldData[i]);
}
return newData;
}
}
过滤器:
package filter;
import com.softeem.wrapper.XSSRequest;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @author bxwl
* @create 2020-08-27 14:00
*/
@WebFilter("/*")
public class XSSFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest)req;
chain.doFilter(new XSSRequest(request), resp);
}
}
总结
- 过滤的实现原理:过滤器基于回调机制实现
- 过滤器(Filter)和拦截器(Interceptor)的区别
a. 拦截器基于反射和代理(proxy)模式实现
b. 过滤器只在请求到达目标之前过滤处理
c. 拦截器会在请求到达之前,以及拦截之后环绕处理 - Servlet过滤器本身并不产生请求和响应对象,它只能提供过滤作用