SpringMVC HttpMessageConverterを書き換えXssフィルタリング
5973 ワード
作業では、xss攻撃スクリプトをフィルタリングし、処理手順を記録する必要があります.
content-type=アプリケーション/jsonのみが必要であるため.charset=UTF-8のjsonリクエストが処理されるので、MappingJacksonHttpMesageConverterの一部のメソッドを書き換える必要があります.
注意:MappingJackson 2 HttpMessageConverterを使用している場合は、MappingJackson 2 HttpMessageConverterの一部のメソッドを書き換える必要があります.インタフェースを定義するMessageConverterHandler 実装する必要がある方法を定義するインタフェースを定義します
2.カスタム注記NeedXss
この注記はxssフィルタが必要なフィールドに使用します.
3.実装クラスXssMappingJacksonHttpMessageConverter,このクラスはMessageConverterHandlerを実装し,MappingJacksonHttpMessageConverterを継承する必要がある
コードは次のとおりです.
4.カスタムXssMappingJacksonHttpMessageConverterを使用する構成
SpringMVCのコンフィギュレーションファイルに次のコンフィギュレーションを追加
最後に、意外なことがなければいいはずです.
content-type=アプリケーション/jsonのみが必要であるため.charset=UTF-8のjsonリクエストが処理されるので、MappingJacksonHttpMesageConverterの一部のメソッドを書き換える必要があります.
注意:MappingJackson 2 HttpMessageConverterを使用している場合は、MappingJackson 2 HttpMessageConverterの一部のメソッドを書き換える必要があります.
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>
最後に、意外なことがなければいいはずです.