文章目录
- 0.前言
- 1.参考文档
- 2.基础介绍
- 3.解决方案
- 3.1. `@CrossOrigin`限制指定来源
- 3.1. `@ `WebMvcConfigurer` 限制指定来源
- 3.3. 其他用法
- 1. 在方法上使用`@CrossOrigin`:
- 2. 在Controller上使用`@CrossOrigin`:
- 3. 设置多个源:
- 4. 设置所有源:
- 5. 设置允许的HTTP方法:
- 6. 设置允许的请求头:
- 7. 设置是否支持凭证:
0.前言
背景: 一直零散的使用着Spring Boot 的各种组件和特性,从未系统性的学习和总结,本次借着这个机会搞一波。共同学习,一起进步。哈哈
CVE-2020-5408 是一个在Spring Framework中的跨站请求伪造(Cross-Site Request Forgery, CSRF)漏洞。该漏洞主要是由于Spring Framework在处理跨站资源共享(Cross-Origin Resource Sharing, CORS)时的错误配置。
请注意,对于已经在生产环境中运行的应用,修改CORS配置可能会影响到正常的功能。因此,在实施这个修复之前,应该先进行充分的测试。
1.参考文档
官方的Spring文档对@CrossOrigin注解的描述:Spring Framework - Enabling CORS
Spring Framework的CORS配置如果不正确可能导致跨站请求伪造攻击(CSRF)。为了减少这种风险 应该遵循以下最佳实践:
-
不要允许所有的源(即避免使用
@CrossOrigin(origins = "*")
)。相反, 应该明确指定允许的源。我后面会有示例 -
限制允许的HTTP方法。例如,你可能只想允许GET和POST请求。
这种我们基本都不会限制死,其实价值也不大
。 -
如果可能,避免允许带有凭证的请求。如果你必须允许带凭证的请求,那么确保应用程序在处理这些请求时有足够的安全措施。
-
在CORS(跨源资源共享)中,一个跨源的请求默认情况下不会发送任何凭据信息,比如HTTP Cookies或HTTP Authentication信息。这样设计的目的是出于安全考虑,防止用户的敏感数据被非法利用。
然而,有时候,我们确实需要在跨源请求中携带这些凭据信息。比如,我们可能需要访问另一个域名下的某个API,而这个API又需要我们提供身份验证信息才能成功访问。在这种情况下,我们可以设置CORS配置,允许请求带有凭证。
在Fetch API或XMLHttpRequest中,我们可以通过设置credentials
选项为include
来实现这一点。而在服务器端,比如使用Spring框架,我们可以通过在@CrossOrigin
注解中设置allowCredentials
为true
来允许请求带有凭证。
如果服务器允许请求带有凭证,那么它就不能在处理CORS请求时将Access-Control-Allow-Origin
头设置为*
,因为浏览器会出于安全考虑而阻止这样的请求。服务器必须明确指定允许的源。
有关CORS和CSRF的参考资料:
-
Spring Framework - CORS
-
MDN Web Docs - Cross-Origin Resource Sharing (CORS)
-
OWASP - Cross-Site Request Forgery (CSRF)
2.基础介绍
简单来说,CORS是一种安全机制,用于控制哪些外部源可以访问到你的应用。在默认情况下,浏览器会阻止跨源(即,不同的域、协议或端口)的 HTTP 请求,以保护用户的隐私。然而,CORS 允许开发者指定哪些外部源可以访问应用,从而打破了这个限制。
在CVE-2020-5408中,Spring Framework的默认CORS配置允许所有的外部源访问应用。这意味着,一个恶意的外部源可以在用户不知情的情况下发起请求,这可能会导致诸如数据泄露、账户劫持等问题。
为了修复这个漏洞,开发者需要显式地配置CORS,指定哪些外部源可以访问应用。例如,可以使用 @CrossOrigin
注解来限制特定的控制器或处理器方法,或者在全局范围内配置 WebMvcConfigurer
。这样,只有信任的外部源才能访问应用,从而防止跨站请求伪造攻击。
3.解决方案
3.1. @CrossOrigin
限制指定来源
特定的控制器配置CORS。
@CrossOrigin
注解告诉Spring Framework只接受来自 http://trusted-domain.com
的请求。来自其他源的请求将被拒绝。
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
@CrossOrigin(origins = "http://trusted-domain.com") // 只允许这个域的请求
@GetMapping("/endpoint")
public String getEndpoint() {
return "Hello, World!";
}
}
3.1. @
WebMvcConfigurer` 限制指定来源
如果需要为整个应用配置CORS,可以实现 WebMvcConfigurer
接口,如下所示:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MyConfiguration implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 对所有的URL路径生效
.allowedOrigins("http://trusted-domain.com") // 只允许这个域的请求
.allowedMethods("GET", "POST", "PUT", "DELETE"); // 允许的HTTP方法
}
}
addCorsMappings
方法定义了一个CORS映射,它适用于所有的URL路径,并且只允许来自 http://trusted-domain.com
的 GET
, POST
, PUT
, DELETE
请求。
3.3. 其他用法
@CrossOrigin
是一个Spring MVC提供的注解,用于处理CORS(跨源资源共享)。
1. 在方法上使用@CrossOrigin
:
@RestController
public class MyController {
@CrossOrigin(origins = "http://domain2.com")
@GetMapping("/endpoint")
public String getEndpoint() {
return "Hello, World!";
}
}
@CrossOrigin
注解用在了getEndpoint
方法上,只有来自"http://domain2.com"的请求才能访问这个端点。
2. 在Controller上使用@CrossOrigin
:
@CrossOrigin(origins = "http://domain2.com")
@RestController
public class MyController {
@GetMapping("/endpoint")
public String getEndpoint() {
return "Hello, World!";
}
}
@CrossOrigin
注解用在了MyController
类上,意味着这个类中的所有方法都只允许"http://domain2.com"的请求。
3. 设置多个源:
@CrossOrigin(origins = {"http://domain1.com", "http://domain2.com"})
在这个示例中,允许"http://domain1.com"和"http://domain2.com"的请求。
4. 设置所有源:
@CrossOrigin(origins = "*")
在这个示例中,允许所有的请求,这个引发安全漏洞的配置,在生产环境禁止使用。
5. 设置允许的HTTP方法:
@CrossOrigin(origins = "http://domain2.com", methods = {RequestMethod.GET, RequestMethod.POST})
只允许GET和POST请求。
6. 设置允许的请求头:
@CrossOrigin(origins = "http://domain2.com", allowedHeaders = {"header1", "header2"})
在这个示例中,只允许包含"header1"和"header2"的请求。
7. 设置是否支持凭证:
允许请求带有凭证。
@CrossOrigin(origins = "http://domain2.com", allowCredentials = "true")