2024-12-28
SOP and CORS Basics and Debugging
We are now only a few days away from the end of 2024. Thank you to the many people who have helped me. I am grateful for their support. Looking back, I think it was a year in which I was able to hone my “introspection” skills, which has been a challenge for me. I look forward to working with you again next year.
Introduction
Balancing security and convenience is critical in the development of web applications. In particular, Same-Origin Policy (SOP) and Cross-Origin Resource Sharing (CORS) are essential concepts for controlling resource sharing between the web browser and server. However, these mechanisms are seemingly complex and can lead to unexpected errors and security risks if not properly understood and configured.
This article explains the basics of SOP and CORS using FastAPI, a fast Python web framework, and details how to actually configure and verify them. It also uses Postman to verify request headers and responses, specifically demonstrating the differences in behavior with and without CORS settings.
The scope of this article includes:
- Understanding how Same-Origin Policy (SOP) works and its importance
- Learning the basic concept of Cross-Origin Resource Sharing (CORS) and how to configure it
- Understanding the specific configuration procedures for CORS in FastAPI
- Verifying CORS behavior using Postman and identifying the cause of problems
Same-Origin Policy Basics
Same-Origin Policy (SOP) is part of the security model implemented by browsers to restrict how documents and scripts loaded from one origin can interact with resources from another origin.
This notion of origin is defined by protocol (http or https), host (domain), and port number. For example, https://www.kaza.ooo
is defined as an origin with protocol https
, host www.kaza.ooo
, and port 443
. Note that for the HTTPS protocol, port number 443 is implicitly assigned.
Requests to the same origin are freely allowed by SOP. A script running at https://www.kaza.ooo
can make a request to https://www.kaza.ooo/api/data
of the same origin and retrieve the data without any problem. On the other hand, if the request is made to a different origin (e.g., http://example.org/api/data
), SOP will be applied, and access to the resource from the browser will be blocked, preventing data retrieval. However, this does not apply to retrieving and displaying images, but the SOP restriction is applied in the sense that pixel data cannot be accessed.
The advantage of this is that it avoids the risk of unauthorized use of authentication information such as cookies if the different origins are malicious websites. This is because if a script like JavaScript can freely access resources from one origin to another, it may be vulnerable to attacks that exploit vulnerabilities in the web application. However, this restriction also limits access to trusted origins, which can be undesirable. This represents a trade-off between availability and security. Fortunately, CORS addresses this problem.
CORS Basic Concepts
Cross-Origin Resource Sharing (CORS) is a mechanism to ease the limitations of SOP. It allows requests to be permitted and data to be shared between different origins, provided that specific origins are configured on the server side.
Comparison of Behavior with and without CORS
Specifically, an Access-Control-Allow-Origin
header can be added to the response to allow requests from a specific origin. The configuration in Python and FastAPI is as follows:
app = FastAPI()
origins = [
"http://localhost:8080",
"https://www.kaza.ooo",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
Let's verify this with Postman to see what the request and response headers actually look like. If the origin http://localhost:8080
, which was previously set in allow_origins
, is included in the request header, an Access-Control-Allow-Origin
header will be added to the response.
On the other hand, if the request header contains the origin http://localhost:8081
, which is not set in allow_origins
, the Access-Control-Allow-Origin
header is not added to the response. If the request was made via a web browser, a CORS error would be output.
In both cases, a response code of 200 is returned, but this is because Postman is not a browser. The desktop app Postman is running on its OS, and the web app Postman is probably not subject to the CORS constraint because it sends requests via the Postman cloud server. Mobile apps running on the OS are also not subject to CORS constraints. However, if the endpoint is accessed directly from a web browser, a CORS-related error will be output to the console.
Details of HTTP Headers Related to CORS
In addition to the Access-Control-Allow-Origin
header mentioned above, various other headers related to CORS can be set. Among them, Access-Control-Allow-Credentials
is a very important item when handling credentials such as cookies, HTTP authentication, and SSL certificates. It controls whether or not these credentials are allowed for different origins.
Being able to pass credentials to different origins is beneficial because, for example, users can request data between different origins while maintaining their login status. This leads to an improved user experience. Additionally, in areas like microservice architectures where different microservices are running across multiple domains or subdomains, or in compound SaaS platforms where there are multiple modules and services within the same platform, each running in a different subdomain or domain, the ability to share credentials across origins becomes very powerful.
Conclusion
Is microservices architecture the same as compound SaaS? This is an area I would like to understand better in the future.