Having a permissive Cross-Origin Resource Sharing policy is security-sensitive. It has led in the past to the following vulnerabilities:
Same origin policy in browsers prevents, by default and for security-reasons, a javascript frontend to perform a cross-origin HTTP request to a resource that has a different origin (domain, protocol, or port) from its own. The requested target can append additional HTTP headers in response, called CORS, that act like directives for the browser and change the access control policy / relax the same origin policy.
Access-Control-Allow-Origin: untrustedwebsite.com
. Access-Control-Allow-Origin: *
origin
header. There is a risk if you answered yes to any of those questions.
Access-Control-Allow-Origin
header should be set only for a trusted origin and for specific resources. Access-Control-Allow-Origin
header. Prefer whitelisting domains over blacklisting or
allowing any domain (do not use * wildcard nor blindly return the Origin
header content without any checks). Java servlet framework:
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setHeader("Content-Type", "text/plain; charset=utf-8"); resp.setHeader("Access-Control-Allow-Origin", "*"); // Sensitive resp.setHeader("Access-Control-Allow-Credentials", "true"); resp.setHeader("Access-Control-Allow-Methods", "GET"); resp.getWriter().write("response"); }
Spring MVC framework:
@CrossOrigin // Sensitive @RequestMapping("") public class TestController { public String home(ModelMap model) { model.addAttribute("message", "ok "); return "view"; } }
CorsConfiguration config = new CorsConfiguration(); config.addAllowedOrigin("*"); // Sensitive config.applyPermitDefaultValues(); // Sensitive
class Insecure implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*"); // Sensitive } }
User-controlled origin:
public ResponseEntity<String> userControlledOrigin(@RequestHeader("Origin") String origin) { HttpHeaders responseHeaders = new HttpHeaders(); responseHeaders.add("Access-Control-Allow-Origin", origin); // Sensitive return new ResponseEntity<>("content", responseHeaders, HttpStatus.CREATED); }
Java Servlet framework:
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setHeader("Content-Type", "text/plain; charset=utf-8"); resp.setHeader("Access-Control-Allow-Origin", "trustedwebsite.com"); // Compliant resp.setHeader("Access-Control-Allow-Credentials", "true"); resp.setHeader("Access-Control-Allow-Methods", "GET"); resp.getWriter().write("response"); }
Spring MVC framework:
@CrossOrigin("trustedwebsite.com") // Compliant @RequestMapping("") public class TestController { public String home(ModelMap model) { model.addAttribute("message", "ok "); return "view"; } }
CorsConfiguration config = new CorsConfiguration(); config.addAllowedOrigin("http://domain2.com"); // Compliant
class Safe implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("safe.com"); // Compliant } }
User-controlled origin validated with an allow-list:
public ResponseEntity<String> userControlledOrigin(@RequestHeader("Origin") String origin) { HttpHeaders responseHeaders = new HttpHeaders(); if (trustedOrigins.contains(origin)) { responseHeaders.add("Access-Control-Allow-Origin", origin); } return new ResponseEntity<>("content", responseHeaders, HttpStatus.CREATED); }