SpringMVC HttpMessageConverterを書き換えXssフィルタリング

5973 ワード

作業では、xss攻撃スクリプトをフィルタリングし、処理手順を記録する必要があります.
content-type=アプリケーション/jsonのみが必要であるため.charset=UTF-8のjsonリクエストが処理されるので、MappingJacksonHttpMesageConverterの一部のメソッドを書き換える必要があります.
注意:MappingJackson 2 HttpMessageConverterを使用している場合は、MappingJackson 2 HttpMessageConverterの一部のメソッドを書き換える必要があります.
  • インタフェースを定義する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>

    最後に、意外なことがなければいいはずです.