您的位置:首页 > 理论基础 > 计算机网络

SpringMVC 重写HttpMessageConverter进行Xss过滤

2016-05-23 09:56 537 查看
摘要: SpringMVC 重写HttpMessageConverter进行Xss过滤

在工作中,需要对xss攻击脚本过滤,在此记录下处理过程。

由于只需要对content-type=application/json;charset=UTF-8的json请求进行处理,所以需要重写MappingJacksonHttpMessageConverter部分方法。

注意:如果使用的是MappingJackson2HttpMessageConverter,需要重写MappingJackson2HttpMessageConverter部分方法

定义接口MessageConverterHandler

我们定义一个接口来定义我们需要实现的方法

public interface MessageConverterHandler<T, K> {

/**
* 用于在httpMessageConverter read(..)方法完成之后调用
* <p>
* 1.可以对converter映射出的Object进行处理
* </p>
*/
public Object readAfter( T obj, K type );
}

2.自定义注解NeedXss

该注解用于需要xss过滤的字段

@Target( ElementType.FIELD )
@Retention( RetentionPolicy.RUNTIME )
@Documented
public @interface NeedXss {
}

3.实现类XssMappingJacksonHttpMessageConverter,该类需要实现MessageConverterHandler,继承MappingJacksonHttpMessageConverter

代码如下:

//默认会过滤所有请求路径,只会过滤String类型的字段,需要其他类型过滤的请自行完善
public class XssMappingJacksonHttpMessageConverter extends MappingJacksonHttpMessageConverter implements
MessageConverterHandler<Object, Type> {

/**
* 不需要xss过滤的路径
*/
protected static List<String> urls;

static {
urls = new ArrayList<String>();
// for example urls.add("/xxx/xxxxx");
}

//重写该方法,我们只需要加上Object tempObj = this.process( obj, type, inputMessage );
//并返回tempObj,process方法里面我们过滤白名单和进行xss处理
@Override
public Object read( Type type, Class<?> contextClass, HttpInputMessage inputMessage ) throws IOException,
HttpMessageNotReadableException {

JavaType javaType = getJavaType( type, contextClass );

Object obj = readJavaType( javaType, inputMessage );

Object tempObj = this.process( obj, type, inputMessage );

return tempObj;
}

//这个就是父类的readJavaType方法,由于父类该方法是private的,所以我们copy一个用
private Object readJavaType( JavaType javaType, HttpInputMessage inputMessage ) {
try {
return super.getObjectMapper().readValue( inputMessage.getBody(), javaType );
} catch ( IOException ex ) {
throw new HttpMessageNotReadableException( "Could not read JSON: " + ex.getMessage(), ex );
}
}

protected Object process( Object obj, Type type, HttpInputMessage inputMessage ) {
if ( this.isNeedProcess( inputMessage ) ) {
return this.readAfter( obj, type );
} else {
return obj;
}
}

//根据白名单,判断当前请求路径是否需要xss过滤
protected boolean isNeedProcess( HttpInputMessage inputMessage ) {

String url = "";

try {
//经过debug发现inputMessage类型为ServletServerHttpRequest,所以进行下类型转换
ServletServerHttpRequest request = ( ServletServerHttpRequest ) inputMessage;

url = request.getURI().getPath();

//根据白名单做下匹配,当然也可以实现正则什么的,代码就不贴了

} catch ( Exception e ) {
logger.error( "BACK_ERROR," + this.getClass().getCanonicalName() + ",XSS处理-url处理失败,url=" + url + ",ERROR=", e );
return true;
}

return true;

}

//最重要的一步,进行xss过滤
@Override
public Object readAfter( Object obj, Type type ) {
try {
//type实际上就是我们需要convert的model,我们通过反射来完成根据NeedXss注解对String
//的字段进行xss过滤
Class clazz = Class.forName( JSON.toJSONString( type ).replace( "\"", "" ) );

if ( clazz == null ) {
return obj;
}

Field[] fields = clazz.getDeclaredFields();

if ( fields != null && fields.length > 0 ) {
// string类型字段名称列表
List<String> strList = new ArrayList<String>( fields.length );

// 1. 将需要xss处理的string类型的字段放入strlist
for ( int i = 0; i < fields.length; i++ ) {

// 1.1该属性是否有NeedXss.class注解
NeedXss needXss = fields[ i ].getAnnotation( NeedXss.class );
// 1.2如果该没有NeedXss.class注解,则不处理该属性
if ( needXss == null || !( needXss instanceof NeedXss ) ) {
continue;
}

String mod = Modifier.toString( fields[ i ].getModifiers() );
if ( mod.indexOf( "static" ) != -1 )
continue;
// 得到属性的类名
String className = fields[ i ].getType().getSimpleName();
// 得到属性字段名
if ( className.equalsIgnoreCase( "String" ) ) {

strList.add( fields[ i ].getName() );
}

}

// 2.将strlist中的字段进行xss处理
if ( strList.size() > 0 ) {

Object temp = JSON.toJavaObject( ( JSON ) JSON.toJSON( obj ), clazz );

for ( int i = 0; i < strList.size(); i++ ) {
Method set = clazz.getMethod( "set" + strList.get( i ).substring( 0, 1 ).toUpperCase()
+ strList.get( i ).substring( 1 ), String.class );
Method get = clazz.getMethod( "get" + strList.get( i ).substring( 0, 1 ).toUpperCase()
+ strList.get( i ).substring( 1 ) );

Object tempObj = get.invoke( temp );

if ( tempObj == null ) {
break;
}

String content = tempObj.toString();

set.invoke( temp, StringUtils.cleanXss( content ) );
}

return temp;
}

}

} catch ( Exception e ) {
logger.error( "BACK_ERROR," + this.getClass().getCanonicalName() + ",XSS处理失败,obj=" + JSON.toJSONString( obj ) + ",javaType="
+ JSON.toJSONString( type ) + ",ERROR=", e );
return obj;
}

return obj;
}
}

4.配置使用自定义的XssMappingJacksonHttpMessageConverter

在SpringMVC的配置文件里面加上下面的配置

<mvc:annotation-driven >
<mvc:message-converters register-defaults="true">
<!-- 将StringHttpMessageConverter的默认编码设为UTF-8. -->
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8" />
</bean>

<bean class="com.zhubajie.seller.common.converter.XssMappingJacksonHttpMessageConverter">
<property name="prettyPrint" value="false" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>

最后,不出意外应该就是可以啦
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: