CORS
Upon CORS introduction (a measure aimed at mitigating client-side SOP constraints for web services in need for unlimited cross-domain interactions), along with its benefits, a severe security risks has arisen.
The mitigation measure introduced was the pre-flight mechanism. It was developed along with CORS for the purpose of categorizing servers into those aware of the new universally acknowledged browser CORS policy and those unaware about it. This behavior serves as a check for the adequacy of the client-server communication flow. From the client's perspective, it ensures that its requests to the server will be responded to properly and as-expected, thereby preventing a ineffective stream of requests in case of an invalid server configuration. The server ensures that the client's request align with the configuration settings in-use.
If it is necessary to optimize and reduce the amount of traffic between the client and the server, there is a number of options to bypass the need for pre-flight messages: from server-side caching, required due to permanent browser policies for maximum caching periods of responses to pre-flight requests on the client side, to refactoring CORS-safe requests.
CORS-safe requests do not cause pre-flight and are identical in format to requests initiated, for instance, through an HTML form. They are restricted to the HTTP methods of GET, HEAD, and POST, and a limited set of permissible non-standard browser headers, one of which, Content-Type, may bear values such as text/plain
, multipart/form-data
, and application/x-www-form-urlencoded
.
One can talk about the role of pre-flight requests in the security of cross-origin interactions for a long time, especially considering that the need for it, in general, appeared with an introduction of CORS, which, in essence, is a plug in the security hole that appeared with new cross-origin request policies. However, analysed in current context, pre-flight requests really cut off a large layer of the CSRF attack surface, which has expanded greatly since the introduction of CORS.
An excessively permissive CORS policy, notably one that includes (1) any unvalidated or incorrectly validated, via RegEx, reflect/embed of an Origin header (or null) in ACAO (2) incorrect configuration of allowed methods/headers in regards to sensitive endpoints can lead to serious consequences for the safety of service users.
Insufficient origin configuration:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) response;
String providedOrigin = request.getParameter("origin");
res.setHeader("Access-Control-Allow-Origin", providedOrigin);
chain.doFilter(request, response);
}
Validation of the received Origin against an Allow-List:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) response;
String providedOrigin = request.getParameter("origin");
String allowedOrigin = valid(providedOrigin);
res.setHeader("Access-Control-Allow-Origin", allowedOrigin);
chain.doFilter(request, response);
}
private String valid(String providedOrigin) {
if (providedOrigin != null && (providedOrigin.equalsIgnoreCase("https://example.com") || providedOrigin.equalsIgnoreCase("https://example2.com"))) {
return providedOrigin;
}
return "https://example.com";
}