Skip to content

Commit 85eb3b9

Browse files
committed
update cors security code
1 parent 6ae0527 commit 85eb3b9

File tree

9 files changed

+168
-59
lines changed

9 files changed

+168
-59
lines changed

src/main/java/org/joychou/config/CorsConfig.java

Lines changed: 0 additions & 29 deletions
This file was deleted.

src/main/java/org/joychou/config/CorsConfig2.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@
2626
// bean.setOrder(0);
2727
// return bean;
2828
// }
29-
//}
29+
//}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package org.joychou.config;
2+
3+
import org.joychou.security.CustomCorsProcessor;
4+
import org.springframework.boot.autoconfigure.web.WebMvcRegistrationsAdapter;
5+
import org.springframework.context.annotation.Bean;
6+
import org.springframework.context.annotation.Configuration;
7+
import org.springframework.web.servlet.config.annotation.CorsRegistry;
8+
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
9+
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
10+
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
11+
12+
@Configuration
13+
public class CustomCorsConfig extends WebMvcRegistrationsAdapter {
14+
15+
/**
16+
* 设置cors origin白名单。区分http和https,并且默认不会拦截同域请求。
17+
*/
18+
@Bean
19+
public WebMvcConfigurer corsConfigurer() {
20+
return new WebMvcConfigurerAdapter() {
21+
@Override
22+
public void addCorsMappings(CorsRegistry registry) {
23+
// 支持一级域名,因为重写了checkOrigin
24+
String[] allowOrigins = {"joychou.org", "http://test.joychou.me"};
25+
registry.addMapping("/cors/sec/webMvcConfigurer") // /**表示所有路由path
26+
.allowedOrigins(allowOrigins)
27+
.allowedMethods("GET", "POST")
28+
.allowCredentials(true);
29+
}
30+
};
31+
}
32+
33+
34+
@Override
35+
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
36+
return new CustomRequestMappingHandlerMapping();
37+
}
38+
39+
40+
/**
41+
* 自定义Cors处理器
42+
* 自定义校验origin,支持一级域名校验 && 多级域名
43+
*/
44+
private static class CustomRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
45+
private CustomRequestMappingHandlerMapping() {
46+
setCorsProcessor(new CustomCorsProcessor());
47+
}
48+
}
49+
}

src/main/java/org/joychou/controller/Cors.java

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,28 @@
1111
import javax.servlet.http.HttpServletResponse;
1212

1313
/**
14-
* @author JoyChou ([email protected])
15-
* @date 2018.10.24
16-
* @desc https://github.com/JoyChou93/java-sec-code/wiki/CORS
14+
* @author JoyChou ([email protected]) @2018.10.24
15+
* https://github.com/JoyChou93/java-sec-code/wiki/CORS
1716
*/
1817

1918
@RestController
2019
@RequestMapping("/cors")
2120
public class Cors {
2221

23-
protected static String info = "{\"name\": \"JoyChou\", \"phone\": \"18200001111\"}";
24-
protected static String[] urlwhitelist = {"joychou.com", "joychou.me"};
22+
private static String info = "{\"name\": \"JoyChou\", \"phone\": \"18200001111\"}";
23+
private static String[] urlwhitelist = {"joychou.org", "joychou.me"};
24+
2525

2626
@RequestMapping("/vuln/origin")
27-
private static String vuls1(HttpServletRequest request, HttpServletResponse response) {
27+
public static String vuls1(HttpServletRequest request, HttpServletResponse response) {
2828
String origin = request.getHeader("origin");
2929
response.setHeader("Access-Control-Allow-Origin", origin); // 设置Origin值为Header中获取到的
3030
response.setHeader("Access-Control-Allow-Credentials", "true"); // cookie
3131
return info;
3232
}
3333

3434
@RequestMapping("/vuln/setHeader")
35-
private static String vuls2(HttpServletResponse response) {
35+
public static String vuls2(HttpServletResponse response) {
3636
// 后端设置Access-Control-Allow-Origin为*的情况下,跨域的时候前端如果设置withCredentials为true会异常
3737
response.setHeader("Access-Control-Allow-Origin", "*");
3838
return info;
@@ -41,40 +41,67 @@ private static String vuls2(HttpServletResponse response) {
4141

4242
@CrossOrigin("*")
4343
@RequestMapping("/vuln/crossOrigin")
44-
private static String vuls3(HttpServletResponse response) {
44+
public static String vuls3() {
45+
return info;
46+
}
47+
48+
49+
/**
50+
* 重写Cors的checkOrigin校验方法
51+
* 支持自定义checkOrigin,让其额外支持一级域名
52+
* 代码:org/joychou/security/CustomCorsProcessor
53+
*/
54+
@CrossOrigin(origins = {"joychou.org", "http://test.joychou.me"})
55+
@RequestMapping("/sec/crossOrigin")
56+
public static String secCrossOrigin() {
4557
return info;
4658
}
4759

4860

49-
// https://github.com/JoyChou93/java-sec-code/blob/master/src/main/java/org/joychou/config/webMvcConfigurer.java
61+
/**
62+
* WebMvcConfigurer设置Cors
63+
* 支持自定义checkOrigin
64+
* 代码:org/joychou/config/CorsConfig.java
65+
*/
5066
@RequestMapping("/sec/webMvcConfigurer")
5167
public CsrfToken getCsrfToken_01(CsrfToken token) {
5268
return token;
5369
}
5470

5571

56-
// https://github.com/JoyChou93/java-sec-code/blob/master/src/main/java/org/joychou/security/WebSecurityConfig.java
72+
/**
73+
* spring security设置cors
74+
* 不支持自定义checkOrigin,因为spring security优先于setCorsProcessor执行
75+
* 代码:org/joychou/security/WebSecurityConfig.java
76+
*/
5777
@RequestMapping("/sec/httpCors")
5878
public CsrfToken getCsrfToken_02(CsrfToken token) {
5979
return token;
6080
}
6181

6282

63-
// https://github.com/JoyChou93/java-sec-code/blob/master/src/main/java/org/joychou/filter/SecCorsFilter.java
64-
@RequestMapping("/sec/corsFitler")
83+
/**
84+
* 自定义filter设置cors
85+
* 支持自定义checkOrigin
86+
* 代码:org/joychou/filter/OriginFilter.java
87+
*/
88+
@RequestMapping("/sec/originFilter")
6589
public CsrfToken getCsrfToken_03(CsrfToken token) {
6690
return token;
6791
}
6892

6993

70-
// https://github.com/JoyChou93/java-sec-code/blob/master/src/main/java/org/joychou/filter/CorsFilter.java
71-
@RequestMapping("/sec/Filter")
94+
/**
95+
* CorsFilter设置cors。
96+
* 不支持自定义checkOrigin,因为corsFilter优先于setCorsProcessor执行
97+
* 代码:org/joychou/filter/BaseCorsFilter.java
98+
*/
99+
@RequestMapping("/sec/corsFilter")
72100
public CsrfToken getCsrfToken_04(CsrfToken token) {
73101
return token;
74102
}
75103

76104

77-
// http://localhost:8080/cors/sec/checkOrigin
78105
@RequestMapping("/sec/checkOrigin")
79106
public String seccode(HttpServletRequest request, HttpServletResponse response) {
80107
String origin = request.getHeader("Origin");

src/main/java/org/joychou/filter/SecCorsFilter.java renamed to src/main/java/org/joychou/filter/BaseCorsFilter.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,26 @@
99

1010
/**
1111
* 由于CorsFilter和spring security冲突,所以改为下面的代码。
12-
* CorsFilter可以参考config/CorsConfig2的代码。
1312
*/
1413
@Component
1514
@Order(Ordered.HIGHEST_PRECEDENCE)
16-
public class SecCorsFilter extends CorsFilter {
15+
public class BaseCorsFilter extends CorsFilter {
1716

18-
public SecCorsFilter() {
17+
public BaseCorsFilter() {
1918
super(configurationSource());
2019
}
2120

2221
private static UrlBasedCorsConfigurationSource configurationSource() {
2322
CorsConfiguration config = new CorsConfiguration();
2423
config.setAllowCredentials(true);
25-
config.addAllowedOrigin("http://test.joychou.org");
26-
config.addAllowedOrigin("https://test.joychou.org");
24+
config.addAllowedOrigin("joychou.org"); // 不支持
25+
config.addAllowedOrigin("http://test.joychou.me");
2726
config.addAllowedHeader("*");
2827
config.addAllowedMethod("GET");
2928
config.addAllowedMethod("POST");
3029

3130
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
32-
source.registerCorsConfiguration("/cors/sec/corsFitler", config);
31+
source.registerCorsConfiguration("/cors/sec/corsFilter", config);
3332

3433
return source;
3534
}

src/main/java/org/joychou/filter/OriginFilter.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@
1111
import org.slf4j.Logger;
1212
import org.slf4j.LoggerFactory;
1313

14+
1415
/**
1516
* 推荐使用该全局方案修复Cors跨域漏洞,因为可以校验一级域名。
1617
* @author JoyChou @ 2019.12.19
17-
*
18+
*
1819
*/
19-
20-
@WebFilter(filterName = "OriginFilter", urlPatterns = "/cors/sec/Filter")
20+
@WebFilter(filterName = "OriginFilter", urlPatterns = "/cors/sec/originFilter")
2121
public class OriginFilter implements Filter {
2222

2323
private static String[] urlwhitelist = {"joychou.org", "joychou.me"};
@@ -41,7 +41,10 @@ public void doFilter(ServletRequest req, ServletResponse res, FilterChain filter
4141

4242
// 以file协议访问html,origin为字符串的null,所以依然会走安全check逻辑
4343
if ( origin != null && SecurityUtil.checkURLbyEndsWith(origin, urlwhitelist) == null) {
44-
logger.error("[-] Origin check error.");
44+
logger.error("[-] Origin check error. " + "Origin: " + origin +
45+
"\tCurrent url:" + request.getRequestURL());
46+
response.setStatus(response.SC_FORBIDDEN);
47+
response.getWriter().println("Invaid cors config by joychou.");
4548
return;
4649
}
4750

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package org.joychou.security;
2+
3+
import org.apache.commons.lang.StringUtils;
4+
import org.slf4j.Logger;
5+
import org.slf4j.LoggerFactory;
6+
import org.springframework.util.CollectionUtils;
7+
import org.springframework.web.cors.CorsConfiguration;
8+
import org.springframework.web.cors.DefaultCorsProcessor;
9+
10+
import java.util.List;
11+
12+
public class CustomCorsProcessor extends DefaultCorsProcessor {
13+
14+
private static final Logger logger = LoggerFactory.getLogger(CustomCorsProcessor.class);
15+
16+
17+
/**
18+
* 跨域请求,会通过此方法检测请求源是否被允许
19+
*
20+
* @param config CORS 配置
21+
* @param requestOrigin 请求源
22+
* @return 如果请求源被允许,返回请求源;否则返回 null
23+
*/
24+
@Override
25+
protected String checkOrigin(CorsConfiguration config, String requestOrigin) {
26+
27+
// 支持checkOrigin原装的域名配置
28+
String result = super.checkOrigin(config, requestOrigin);
29+
if (result != null) {
30+
return result;
31+
}
32+
33+
List<String> allowedOrigins = config.getAllowedOrigins();
34+
if (StringUtils.isBlank(requestOrigin)
35+
|| CollectionUtils.isEmpty(allowedOrigins)) {
36+
return null;
37+
}
38+
39+
return customCheckOrigin(allowedOrigins, requestOrigin);
40+
}
41+
42+
43+
/**
44+
* 用host的endsWith来校验requestOrigin
45+
*/
46+
private String customCheckOrigin(List<String> allowedOrigins, String requestOrigin) {
47+
48+
// list转String[]
49+
String[] arrayAllowOrigins = allowedOrigins.toArray(new String[allowedOrigins.size()]);
50+
51+
if ( SecurityUtil.checkURLbyEndsWith(requestOrigin, arrayAllowOrigins) != null) {
52+
logger.info("[+] Origin: " + requestOrigin );
53+
return requestOrigin;
54+
}
55+
logger.error("[-] Origin: " + requestOrigin );
56+
return null;
57+
}
58+
59+
60+
}

src/main/java/org/joychou/security/WebSecurityConfig.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ protected void configure(HttpSecurity http) throws Exception {
6262
.ignoringAntMatchers(csrfExcludeUrl) // 不进行csrf校验的uri,多个uri使用逗号分隔
6363
.csrfTokenRepository(new CookieCsrfTokenRepository());
6464
http.exceptionHandling().accessDeniedHandler(new CsrfAccessDeniedHandler());
65-
// http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
65+
// http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());«
6666

6767
http.cors();
6868

@@ -85,8 +85,8 @@ CorsConfigurationSource corsConfigurationSource()
8585
{
8686
// Set cors origin white list
8787
ArrayList<String> allowOrigins = new ArrayList<String>();
88-
allowOrigins.add("http://test.joychou.org");
89-
allowOrigins.add("https://test.joychou.org"); // 区分http和https,并且默认不会拦截同域请求。
88+
allowOrigins.add("joychou.org");
89+
allowOrigins.add("https://test.joychou.me"); // 区分http和https,并且默认不会拦截同域请求。
9090

9191
CorsConfiguration configuration = new CorsConfiguration();
9292
configuration.setAllowedOrigins(allowOrigins);

src/main/resources/templates/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<p>
1111
<a th:href="@{/codeinject?filepath=/tmp;cat /etc/passwd}">CmdInject</a>&nbsp;&nbsp;
1212
<a th:href="@{/jsonp/getToken?_callback=test}">JSONP</a>&nbsp;&nbsp;
13-
<a th:href="@{cors/sec/Filter}">Cors</a>&nbsp;&nbsp;
13+
<a th:href="@{cors/sec/originFilter}">Cors</a>&nbsp;&nbsp;
1414
<a th:href="@{/path_traversal/vul?filepath=../../../../../etc/passwd}">PathTraversal</a>&nbsp;&nbsp;
1515
<a th:href="@{/sqli/jdbc/vul?username=joychou}">SqlInject</a>&nbsp;&nbsp;
1616
<a th:href="@{/ssrf/urlConnection?url=file:///etc/passwd}">SSRF</a>&nbsp;&nbsp;

0 commit comments

Comments
 (0)