本帖目的
在web开发等实际应用场景中,许多地方需要获取用户当前真实的使用ip。在先网应用中,例如移动、联通、电信等,不会允许用户直接访问访问服务器的地址,这样做即是我了安全也是为了均衡,而这样操作的结果就是服务器端不能获取用户的真实使用地址,很有可能将一个正常的访问当做是一个攻击,最简单的CSRF攻击即是基于该原理。本帖的目的在于讲述获取用户真实使用ip的方法。
代码讲述
下面代码是具体操作形式,通过下属的代码,我们可以获取到真实的操作ip
private String getRemoteClientAddr(HttpServletRequest request) {
//常用的5种获取原始ip的方式,其中x-forwarded-for 为获取原始ip的最常用方法。其他方式请搜索相关文档
String []ipHeaders = {"x-forwarded-for", "http_client_ip", "Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_X_FORWARDED_FOR"};
String []invalidIps = {null, "unknown"};
String clientIp = null;
for(String ipHeader : ipHeaders) {
clientIp = request.getHeader(ipHeader);
String tempClientIp = StringUtils.substringBefore(clientIp, ",");
clientIp = StringUtils.trimToNull(tempClientIp);
if(!this.isInvalidIp(clientIp, invalidIps)) {
//如果当前ip有效,则不再进行循环
break;
}
}
//再次对获取到的IP进行判断
if(this.isInvalidIp(clientIp, invalidIps)) {
//这种场景是直接访问服务器而没有转接。
clientIp = request.getRemoteAddr();
}
return clientIp;
}
private boolean isInvalidIp(String requestIp, String ...invalidIps) {
for(String invalidIp : invalidIps) {
if(null == invalidIp) {
if(null == requestIp) {
//第一种场景:输入的ip为null,则一定是invalid
return true;
}else {
continue;
}
}else if(invalidIp.equalsIgnoreCase(requestIp)){
//第二种场景:ip类型属于invalid数组类型中的某一个
return true;
}
}
//for循环遍历完成后仍旧没有返回,则认为是 valid类型
return false;
}
ip检索位置
上述方法一般应用于filter中,在request请求到达servlet之前进行判断,确定各项要求是否合法,下面简单介绍filter的使用方法
filter分为两部分:1. java部分,需要实现Filter类;2. web.xml中的配置
java代码部分
Filter类包含三个方法:1. init()方法,在tomcat启动的时候负责filter的初始化;2. dofilter()方法,在tomcat收到http请求时对http请求进行一定处理;3. destroy()方法,在tomcat结束时对指定的资源进行清理。
import java.io.IOException;
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.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
public class CsrfFilter implements Filter {
@Override
public void destroy() {
System.out.println("+++++ destory()+++++");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
filterChain.doFilter(request, response);
}
@Override
public void init(FilterConfig config) throws ServletException {
System.out.println("csrfTilter");
}
}
web.xml中的配置
1. 配置某指定的过滤器:需要在web.xml中配置两个节点,即<filter/>和<filter-mapping/>,其中<filter/>节点用于指明过滤器的名称和指定的过滤器文件;而<filter-mapping/>的作用是指定过滤的内容。
<filter>
<!-- 过滤器的名称 -->
<filter-name>csrf-filter</filter-name>
<!-- 过滤器文件的位置 -->
<filter-class>com.china.filters.csrf.CsrfFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>csrf-filter</filter-name>
<!-- 过滤器所过滤的内容,此处是过滤一切请求 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
2. 常用的spring指定编码格式过滤器:http请求中常常有自己携带的编码方式,当两种编码方式交互时,可能会产生乱码,为了解决该问题,一般强制指定为UTF-8编码格式
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<!-- 指定编码格式为UTF-8 -->
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<!-- 强制编码 -->
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>