spring-security使用-安全防护HttpFirewall(七)

类图

 

 

 默认提供2种实现 defaultfHttpFirewall 看源码可以看出来比较宽松,我们一般使用StrictHttpFirewall

限制请求方法

如果需要修改可以自定义StrictHttpFirewall 

public class StrictHttpFirewall implements HttpFirewall {
    //空的集合
    private static final Set<String> ALLOW_ANY_HTTP_METHOD = Collections.unmodifiableSet(Collections.emptySet());
    private Set<String> allowedHttpMethods = createDefaultAllowedHttpMethods();
    //设置允许的请求方式
    private static Set<String> createDefaultAllowedHttpMethods() {
        Set<String> result = new HashSet();
        result.add(HttpMethod.DELETE.name());
        result.add(HttpMethod.GET.name());
        result.add(HttpMethod.HEAD.name());
        result.add(HttpMethod.OPTIONS.name());
        result.add(HttpMethod.PATCH.name());
        result.add(HttpMethod.POST.name());
        result.add(HttpMethod.PUT.name());
        return result;
    }
    public void setUnsafeAllowAnyHttpMethod(boolean unsafeAllowAnyHttpMethod) {
        //如果是false则设置空的集合
        this.allowedHttpMethods = unsafeAllowAnyHttpMethod ? ALLOW_ANY_HTTP_METHOD : createDefaultAllowedHttpMethods();
    }

    private void rejectForbiddenHttpMethod(HttpServletRequest request) {
        if (this.allowedHttpMethods != ALLOW_ANY_HTTP_METHOD) {
            //如果不存在运行的方法里面 则抛出异常
            if (!this.allowedHttpMethods.contains(request.getMethod())) {
                throw new RequestRejectedException("The request was rejected because the HTTP method \"" + request.getMethod() + "\" was not included within the whitelist " + this.allowedHttpMethods);
            }
        }
    }
}

使用方式

@Bean
HttpFirewall httpFirewall() {
    StrictHttpFirewall firewall = new StrictHttpFirewall();
    firewall.setUnsafeAllowAnyHttpMethod(true);
    return firewall;
}

请求地址不能有分号

如地址:http://localhost:8080/index;id=ddd

public class StrictHttpFirewall implements HttpFirewall {
    private Set<String> encodedUrlBlacklist = new HashSet();
    private Set<String> decodedUrlBlacklist = new HashSet();

    //;的urlecod和decode的几种
    private static final List<String> FORBIDDEN_SEMICOLON = Collections.unmodifiableList(Arrays.asList(";", "%3b", "%3B"));
    public void setAllowSemicolon(boolean allowSemicolon) {
        //如果是false则删除调
        if (allowSemicolon) {
            this.urlBlacklistsRemoveAll(FORBIDDEN_SEMICOLON);
        } else {
            this.urlBlacklistsAddAll(FORBIDDEN_SEMICOLON);
        }
    }
    //加入到校验list
    private void urlBlacklistsAddAll(Collection<String> values) {
        this.encodedUrlBlacklist.addAll(values);
        this.decodedUrlBlacklist.addAll(values);
    }
    //清除到校验list
    private void urlBlacklistsRemoveAll(Collection<String> values) {
        this.encodedUrlBlacklist.removeAll(values);
        this.decodedUrlBlacklist.removeAll(values);
    }

    private void rejectedBlacklistedUrls(HttpServletRequest request) {
        Iterator var2 = this.encodedUrlBlacklist.iterator();

        String forbidden;
        do {
            if (!var2.hasNext()) {
                var2 = this.decodedUrlBlacklist.iterator();

                do {
                    if (!var2.hasNext()) {
                        return;
                    }

                    forbidden = (String)var2.next();
                } while(!decodedUrlContains(request, forbidden));

                throw new RequestRejectedException("The request was rejected because the URL contained a potentially malicious String \"" + forbidden + "\"");
            }

            forbidden = (String)var2.next();
        } while(!encodedUrlContains(request, forbidden));

        throw new RequestRejectedException("The request was rejected because the URL contained a potentially malicious String \"" + forbidden + "\"");
    }
}

必须是可打印的 ASCII 字符

private static boolean containsOnlyPrintableAsciiCharacters(String uri) {
    int length = uri.length();
    for (int i = 0; i < length; i++) {
        char c = uri.charAt(i);
        if (c < '\u0020' || c > '\u007e') {
            return false;
        }
    }
    return true;
}

不能使用双斜杠

@Bean
HttpFirewall httpFirewall() {
    StrictHttpFirewall firewall = new StrictHttpFirewall();
    firewall.setAllowUrlEncodedDoubleSlash(true);
    return firewall;
}

% 不被允许

如果需要去掉

@Bean
HttpFirewall httpFirewall() {
    StrictHttpFirewall firewall = new StrictHttpFirewall();
//允许%的配置 firewall.setAllowUrlEncodedPercent(
true); return firewall; }

反斜杠不被允许

如果需要去掉

@Bean
HttpFirewall httpFirewall() {
    StrictHttpFirewall firewall = new StrictHttpFirewall();
    firewall.setAllowBackSlash(true);
    firewall.setAllowUrlEncodedSlash(true);
    return firewall;
}

. 不被允许

如果需要去掉

@Bean
HttpFirewall httpFirewall() {
    StrictHttpFirewall firewall = new StrictHttpFirewall();
    firewall.setAllowUrlEncodedPeriod(true);
    return firewall;
}

入口处

  public FirewalledRequest getFirewalledRequest(HttpServletRequest request) throws RequestRejectedException {
        this.rejectForbiddenHttpMethod(request);
        this.rejectedBlacklistedUrls(request);
        this.rejectedUntrustedHosts(request);
        if (!isNormalized(request)) {
            throw new RequestRejectedException("The request was rejected because the URL was not normalized.");
        } else {
            String requestUri = request.getRequestURI();
            if (!containsOnlyPrintableAsciiCharacters(requestUri)) {
                throw new RequestRejectedException("The requestURI was rejected because it can only contain printable ASCII characters.");
            } else {
                return new FirewalledRequest(request) {
                    public void reset() {
                    }
                };
            }
        }
    }

 

posted @ 2021-01-29 10:22  意犹未尽  阅读(2256)  评论(0编辑  收藏  举报