Request MappingHandlerMappingの経歴を書き直します。

8515 ワード

最近会社の製品は安全審査をしました。バックエンドが提供するインターフェースには安全なHttp方法の不備があります。安全でないHTTP方法は、TRACE、PUT、DELETE、COPYなどを含む。その中で最も一般的なTRACE方法は、主にテストまたは診断のためにサーバによって受信された要求を再現することができ、悪意のある攻撃者は、この方法を利用してクロスストーカー攻撃(すなわちXST攻撃)を行うことができ、これによってフィッシング、管理者のクッキーなどを盗むことができる。
原因分析
この問題を引き起こした原因は実は簡単です。開発者がインターフェースを開発する時に、Request Mappingの中のmethod属性を指定していないからです。Methodが指定されていないとシステムはデフォルトでTRACE以外の7つの方法をサポートします。だから、これは私が書き直したいRequest MappingHandlerMappingの原因です。
もちろん他の方法もあります。例えば、Request Mappingを採用していて、methodを指定していないところを検索して、コードの中でmethodを明確に指定します。この方法は考え方が一番簡単ですが、やはり人は怠け者です。また、将来のコード開発において、もし誰かがMethodを指定しないなら、この問題は当然存在します。だから私たちはhttpインターフェースマッピング関係のロジックをロードするために変更したいです。
Methodが指定されていない場合は、GETとPOSTのみがサポートされます。methodを明確に指定した場合は、指定されたmethodを保留します。
なぜ書き換えたのですか?Request MappingHandlerMappingです。
まず後端から供給されるHttp要求は、Request Mapping(または派生GetMapping/PostMappingなど)によって実現される。http要請を受けた後、http要求を具体的なControllerにマッピングする方法はどうなりますか?答えはHandlerMappingというインターフェイスです。この具体的なマッピングプロセスの詳細は後にしますが、HandlerMappingインターフェースのマッピング方法getHandlerはAbstracthandlerMappingで実現されますが、AbstracthandlerMappingの非抽象的なサブクラスはRequest MapplerMappingです。
Request MappingHandlerMappingのどの方法を書き直しますか?
Request MappingHandlerMappingにおけるget MappingForMethod法から,界面のマッピング情報は,2つの部分から構成されていることがわかる。一部はController類からのRequest Mapping注解であり、一部は方法によるRequest Mapping注解である。したがって、この方法ではcreateRequest MappingInfoを2回呼び出してから再結合します。
@Override
    protected RequestMappingInfo getMappingForMethod(Method method, Class> handlerType) {
        RequestMappingInfo info = createRequestMappingInfo(method);
        if (info != null) {
            RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
            if (typeInfo != null) {
                info = typeInfo.combine(info);
            }
        }
        return info;
    }
本当にcreateRequest MappingInfoは代理方法があります。
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
        RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
        RequestCondition> condition = (element instanceof Class ?
                getCustomTypeCondition((Class>) element) : getCustomMethodCondition((Method) element));
        return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
    }
createRequest MappingInfoで、私たちが変えたいところを見つけました。Request MappingInfoにmethodを設定する時自分のロジックを追加すればいいです。
protected RequestMappingInfo createRequestMappingInfo(
            RequestMapping requestMapping, RequestCondition> customCondition) {

        return RequestMappingInfo
                .paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
                .methods(requestMapping.method())
                .params(requestMapping.params())
                .headers(requestMapping.headers())
                .consumes(requestMapping.consumes())
                .produces(requestMapping.produces())
                .mappingName(requestMapping.name())
                .customCondition(customCondition)
                .options(this.config)
                .build();
    }
これで、Request MappingHandlerMappingは以下の通り書き換えられます。
public class HttpSafetyRequestMappingHandlerMapping extends RequestMappingHandlerMapping{

    private RequestMappingInfo.BuilderConfiguration config = new RequestMappingInfo.BuilderConfiguration();

    @Override
    protected RequestMappingInfo createRequestMappingInfo(RequestMapping requestMapping,
                                                          RequestCondition> customCondition) {
        //   Controller    RequestMapping    Method,    GET POST
        RequestMethod[] methods = { RequestMethod.GET, RequestMethod.POST };

        if(requestMapping.method().length != 0){
            methods = requestMapping.method();
        }

        return RequestMappingInfo
                .paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
                .methods(methods)
                .params(requestMapping.params())
                .headers(requestMapping.headers())
                .consumes(requestMapping.consumes())
                .produces(requestMapping.produces())
                .mappingName(requestMapping.name())
                .customCondition(customCondition)
                .options(config)
                .build();
    }

    @Override
    protected RequestMappingInfo getMappingForMethod(Method method, Class> handlerType) {
        RequestMappingInfo info = createRequestMappingInfo(method);
        if (info != null) {
            RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
            if (typeInfo != null) {
                info = typeInfo.combine(info);
            }
        }
        return info;
    }

    private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
        RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
        RequestCondition> condition = (element instanceof Class ?
                getCustomTypeCondition((Class>) element) : getCustomMethodCondition((Method) element));
        if(requestMapping == null){
            return null;
        }
        //          RequestMapping,Controller        
        if(element instanceof Class){
            return super.createRequestMappingInfo(requestMapping, condition);
        } else {
            return createRequestMappingInfo(requestMapping, condition);
        }
    }

    @Override
    public void afterPropertiesSet() {
        this.config = new RequestMappingInfo.BuilderConfiguration();
        this.config.setUrlPathHelper(getUrlPathHelper());
        this.config.setPathMatcher(getPathMatcher());
        this.config.setSuffixPatternMatch(useSuffixPatternMatch());
        this.config.setTrailingSlashMatch(useTrailingSlashMatch());
        this.config.setRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch());
        this.config.setContentNegotiationManager(getContentNegotiationManager());
        super.afterPropertiesSet();
    }
}
置き換え方法
ゲートウェイサービスはSpring bootを使って開発されます。org.springframework.boot.autoconfigure.web.WebMvcAutoConfigurationから入手できます。このような中に一つの内部の種類があります。EnbleWebMvcConfigrationは引き続きcreateRequest MappingHandlerMapping方法を書き直しました。我々は、WebMvcConfigrationSupport類において、Request MappingHandlerMappingの例の取得は、request MappingHandlerMapping法によりBen注釈を追加して実現されることを知っている。
これらの関係:
WebMvcConfigurationSupport
^
|   
DelegatingWebMvcConfiguration
^
|   
EnableWebMvcConfiguration
^      ^ 
|      | @Import
| WebMvcAutoConfigurationAdapter
|        ^      
|             |
|        |
WebMvcAutoConfiguration

WebMvcConfigrationSupportのrequest MappingHandlerMapping方法では、Request MappinghanlderMappingは、createRequest Mappler Mappling Handler Mappingを呼び出すことによって実現される。ですから、Request MappinghanlderMappingの実現をカバーするには、createRequest MappingHandlerMappingを書き換えるだけでいいです。EnbleWebMvcConfigrationはこの方法を下記のように書き換えました。
        @Override
        protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
            if (this.mvcRegistrations != null
                    && this.mvcRegistrations.getRequestMappingHandlerMapping() != null) {
                return this.mvcRegistrations.getRequestMappingHandlerMapping();
            }
            return super.createRequestMappingHandlerMapping();
        }
上記のコードから分かるように、EnbleWebMvcConfigrationはRequest MappingHandlerMappingを差し替える方式を提供しました。それはつまりWebMvcRegistrationです。WebMvcRegistrationはインターフェースであり、デフォルトの空実装があります。WebMvcRegistration sAdapterは、その中をカバーするget Request MappingHandlerMapping方法だけでいいです。
@Component
public class SafetyWebMvcRegistrationsAdapter extends WebMvcRegistrationsAdapter{

    @Override
    public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
        return new HttpSafetyRequestMappingHandlerMapping();
    }
}
これでSping bootでRequest Mappinghandler Mappingを置き換えることができました。
でも、もう一つのサービスはSpring mvcを採用しています。上の交換は有効ではありません。サービス中のWebApplication Contectは@EnbaleWebMvcで注入する構成ですので。この注釈で導入されたのは実はDelegating WebMvcConfigrationです。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
@EnbleWebMvcを@Importに置き換えればいいです。またはDelegatingWebMvcConfigrationを書き換えて、createRequest MappingHandlerMapping方法をカバーしてもいいです。
回転:https://heqiao2010.github.io