Cross-Origin Resource Sharing (CORS) is a crucial aspect of web security that allows or restricts resources on a web server depending on where the request is coming from. We’ll explore how CORS works, its implications, and how to configure it in Spring Boot with Kotlin.
Understanding Headers Related to CORS
CORS relies on specific HTTP headers to control resource sharing between different origins. Here are the most important ones:
-
Request Headers:
-
Origin
: Indicates the origin (protocol + domain + port) from where the request originates. Example:
Origin: http://localhost:3000
-
-
Response Headers:
-
Access-Control-Allow-Origin
: Specifies the allowed origin(s) for the requested resource. If set to*
, it allows all origins.
Access-Control-Allow-Origin: http://localhost:3000
-
-
Access-Control-Allow-Methods
:
Lists the allowed HTTP methods for cross-origin requests (e.g.,GET
,POST
,PUT
).
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
-
Access-Control-Allow-Headers
:
Specifies the allowed headers for requests, such asAuthorization
orContent-Type
.
Access-Control-Allow-Headers: Authorization, Content-Type
-
Access-Control-Allow-Credentials
:
Allows cookies and other credentials to be included in cross-origin requests. Must be set totrue
explicitly.
Access-Control-Allow-Credentials: true
-
Preflight Requests:
- Browsers send an additional OPTIONS request to verify whether the actual request is permitted. The server responds with the necessary CORS headers.
Why Does CORS Affect Browsers but Not Mobile Apps?
CORS is a browser-enforced security mechanism. Here’s why:
-
Web Security Model:
- Browsers implement the same-origin policy, which restricts scripts on one origin from accessing resources on another origin.
- CORS headers allow servers to relax these restrictions for specific origins.
-
Mobile and Other Clients:
- Non-browser clients like mobile apps, Postman, or cURL do not enforce the same-origin policy. They directly send HTTP requests without validating CORS headers.
- This is why CORS is primarily a browser-related concern.
-
Implications:
- While CORS protects users from malicious cross-origin scripts, backend APIs still need proper authentication and authorization mechanisms to secure data.
How to Set Up CORS in Spring Boot with Kotlin
In Spring Boot, you can configure CORS globally or at the controller level. Here’s an example of setting it up in Kotlin:
Global Configuration with @Bean
The following Kotlin code configures CORS for all endpoints:
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.web.cors.CorsConfiguration
import org.springframework.web.cors.UrlBasedCorsConfigurationSource
import org.springframework.web.filter.CorsFilter
@Configuration
class CorsConfig {
@Bean
fun corsConfigurationSource(): UrlBasedCorsConfigurationSource {
val configuration = CorsConfiguration()
// Allow requests from specific origins
configuration.allowedOrigins = listOf("http://localhost:3000") // Replace with specific origin for production
// Allow credentials (cookies, authorization headers, etc.)
configuration.allowCredentials = true
// Allow specific HTTP methods
configuration.allowedMethods = listOf("GET", "POST", "PUT", "DELETE", "OPTIONS")
// Allow specific headers
configuration.allowedHeaders = listOf("Authorization", "Content-Type")
// Apply CORS settings to all paths
val source = UrlBasedCorsConfigurationSource()
source.registerCorsConfiguration("/**", configuration)
return source
}
}
CORS with Controller-Level Annotations
You can also configure CORS for specific controllers or endpoints:
import org.springframework.web.bind.annotation.CrossOrigin
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController
@RestController
class ExampleController {
@CrossOrigin(origins = ["http://localhost:3000"], allowCredentials = "true")
@GetMapping("/example")
fun exampleEndpoint(): String {
return "CORS Configured!"
}
}
What Is Affected by allowCredentials
?
Impacts of allowCredentials
The allowCredentials
setting controls whether browser-managed credentials, such as cookies, are included in cross-origin requests:
-
Cookies:
- When
allowCredentials = true
, cookies (e.g., session tokens) are sent automatically with the request if the client setswithCredentials: true
. - If
allowCredentials = false
, cookies are not included in the request, even if the client specifieswithCredentials: true
.
- When
-
TLS Client Certificates:
-
allowCredentials
enables the inclusion of TLS client certificates in cross-origin requests.
-
-
Basic Authentication Headers:
- Automatically included in requests when
allowCredentials = true
and the request requires Basic Authentication.
- Automatically included in requests when
What Is NOT Affected by allowCredentials
?
The allowCredentials
setting does not affect manually added headers like the Authorization
header used for Bearer tokens:
-
Authorization Header:
- Bearer tokens included in the
Authorization
header are manually set by the client and are unaffected byallowCredentials
. - Example:
axios.get("https://api.example.com/data", { headers: { Authorization: `Bearer ${token}` } });
- Bearer tokens included in the
-
Custom Headers:
- Any headers explicitly added to the request (e.g.,
X-Custom-Header
) are unaffected byallowCredentials
.
- Any headers explicitly added to the request (e.g.,
Why Authorization Is Unaffected
The browser’s role in enforcing CORS focuses on automatically managing credentials, such as cookies and certificates. Headers explicitly added by the client are outside the scope of browser-enforced CORS rules, so they are unaffected by allowCredentials
.
Best Practices for CORS Configuration
-
Specific Origins:
- Avoid using
*
forallowedOrigins
ifallowCredentials = true
. The CORS specification disallows this combination. - Example:
configuration.allowedOrigins = listOf("http://localhost:3000") configuration.allowCredentials = true
- Avoid using
-
Credentials:
- If your application relies on cookies or other credentials, ensure
allowCredentials = true
and configureAccess-Control-Allow-Credentials
on the server. - Cookies will only work if the client sets
withCredentials: true
(e.g., in Axios).
- If your application relies on cookies or other credentials, ensure
-
Preflight Requests:
- Handle OPTIONS requests by including appropriate headers in your CORS configuration.
-
Avoid Wildcards in Production:
- Using
*
forallowedMethods
andallowedHeaders
is acceptable for development but should be replaced with specific values in production.
- Using
-
Security First:
- CORS headers are not a substitute for authentication and authorization. Ensure proper security mechanisms are in place on the backend.
Takeaway
- CORS is a browser-enforced security feature that allows or restricts cross-origin resource sharing.
- CORS does not affect mobile apps and non-browser clients, but backend APIs should still use authentication.
- In Spring Boot with Kotlin, you can configure CORS globally or at the controller level.
- Follow best practices, like setting specific origins and ensuring compatibility between
allowCredentials
andallowedOrigins
, to avoid security issues.
By understanding and properly configuring CORS, you can build secure and flexible web applications that seamlessly handle cross-origin requests.
Top comments (0)