Understanding and Configuring CORS
# CHAPTER 12
Understanding and Configuring CORS
1. Introduction
If you build an API onapi.yoursite.com and a frontend app on app.yoursite.com, and attempt to make an AJAX request, the browser will block it and throw a massive red error in the console. Why? Because of the Same-Origin Policy. To allow modern web apps to communicate with APIs on different domains, we use CORS (Cross-Origin Resource Sharing). However, misconfiguring CORS is a massive security vulnerability. In this chapter, we will demystify CORS, understand the Preflight request, and learn how to configure safe headers in PHP.
2. Learning Objectives
By the end of this chapter, you will be able to:- Explain the Same-Origin Policy (SOP) and why browsers enforce it.
- Understand the purpose and mechanics of CORS.
-
Differentiate between Simple requests and Preflight (
OPTIONS) requests.
-
Identify the extreme danger of using the wildcard
*in production CORS headers.
- Write PHP code to securely configure CORS for specific allowed domains.
3. Beginner-Friendly Explanation
Imagine a strict security guard at an office building (The Web Browser). The rule is: Employees from the Marketing floor can only talk to other employees on the Marketing floor (The Same-Origin Policy).One day, an employee from Marketing (your frontend app) wants to ask a question to the Accounting department (your API on a different domain). The security guard stops them. Before the guard lets the Marketing employee talk to Accounting, the guard calls Accounting on the phone and asks: *"Hey Accounting, do you allow people from Marketing to talk to you?"* (The Preflight Request). If Accounting says *"Yes"*, the conversation happens (CORS is configured correctly). If Accounting says *"No"*, the guard blocks the conversation.
4. Real-World Attack Scenarios
-
The Wildcard Disaster: A developer gets frustrated with CORS errors while building their app. To "fix" it, they set
Access-Control-Allow-Origin: *on an API that uses cookie-based authentication. An attacker sets up an evil websitefreemovies.com. When a victim visitsfreemovies.com, the evil site makes an AJAX request in the background to the vulnerable API. Because the API allows*(everyone), the browser attaches the victim's session cookies, and the attacker steals private data!
5. The Preflight Request (OPTIONS)
When a browser makes a complex cross-origin request (like sending a JSON POST request or sending an Authorization header), it doesn't send the real request immediately.
-
1.
The browser sends an
OPTIONSrequest first.
- 2. The server responds with CORS headers detailing who is allowed to connect, and what methods are allowed.
-
3.
If the browser is satisfied, it *then* sends the actual
POSTrequest.
6. Vulnerable vs Secure Code Examples
Vulnerable PHP (The Lazy "Fix"):
Secure PHP (Strict Whitelisting):
7. CORS Headers Explained
-
Access-Control-Allow-Origin: Who is allowed to call the API? (e.g.,https://myapp.com)
-
Access-Control-Allow-Methods: What HTTP methods can they use? (e.g.,GET, POST)
-
Access-Control-Allow-Headers: What custom headers can they send? (e.g.,Authorization)
-
Access-Control-Allow-Credentials: Are they allowed to send Cookies or HTTP Auth? (Must betrueif your API uses sessions. Cannot betrueif Origin is*).
8. Postman vs. The Browser
CRITICAL KNOWLEDGE: Postman does NOT enforce CORS! CORS is a security feature built into web browsers (Chrome, Firefox, Safari) to protect end-users. If your CORS is misconfigured, your API will work perfectly in Postman, but will completely fail when your React app tries to call it in Chrome. This confuses beginners constantly.9. Best Practices
-
Never Use
*for Authenticated APIs: Only use*for truly public APIs (like a public weather API that requires no login). If an endpoint requires user authentication, explicitly whitelist the allowed domains.
-
Whitelist, Don't Regex: Avoid using complex Regular Expressions to validate the Origin header, as they are often poorly written and can be bypassed (e.g.,
.*myapp\.comallowsevilmyapp.com). Use a strict array of allowed strings.
- Configure at the Server Level: While you can do this in PHP, it is often more efficient to configure CORS headers in your Nginx or Apache server configuration blocks.
10. Common Mistakes
- Reflecting the Origin Blindly:
This entirely defeats the purpose of CORS, as it basically creates a dynamic wildcard.
-
Forgetting the OPTIONS request: If your PHP script requires a JWT token, but you don't return
200 OKearly for theOPTIONSrequest, the browser's preflight check will fail (because preflight requests don't send the JWT).
11. Mini Exercises
- 1. Does Postman enforce CORS policies?
- 2. What HTTP method does a browser use to perform a "Preflight" check?
12. Practice Challenges
Challenge: Set up a simple PHP file that returns{"status": "ok"}. Open a totally different website in your browser (like google.com), open the developer console (F12), and use fetch('http://localhost/your_api.php'). Observe the CORS error. Now, add the correct headers to your PHP file to allow google.com specifically, and try the fetch command again.
13. MCQs with Answers
What is the fundamental browser security mechanism that CORS is designed to selectively bypass?
Why is setting Access-Control-Allow-Origin: * considered a severe security risk on APIs that handle sensitive user data?
If a web application makes a cross-origin POST request with a custom Authorization header, what must the API server do first?
14. Interview Questions
- Q: Explain the concept of CORS. Why do browsers enforce it, and why doesn't Postman enforce it?
- Q: Walk me through the sequence of HTTP requests when a browser initiates a Preflight CORS check.
-
Q: A developer is receiving a CORS error and suggests setting
Access-Control-Allow-Origin: *to fix it quickly. Explain why this is dangerous and how to fix it securely.
15. FAQs
Q: My mobile app (iOS/Android) is getting CORS errors. How do I fix this? A: Native mobile apps do not run in web browsers, so they technically do not enforce CORS. However, if you are building a mobile app using a web-view framework like Ionic, React Native, or Cordova, the underlying web-view *does* enforce CORS. You must whitelistlocalhost or the specific scheme the app uses (e.g., ionic://localhost).
16. Summary
In this chapter, we solved the mystery of the dreaded CORS error. We learned that the Same-Origin Policy is a crucial browser protection mechanism, and CORS is the negotiated handshake (viaOPTIONS preflight requests) to safely bypass it. We emphasized the catastrophic danger of using the wildcard * on authenticated APIs, and demonstrated how to write strict PHP whitelists to ensure only trusted frontend applications can communicate with our backend.