क्रॉस-ओरिजिन रिसोर्स शेयरिंग (CORS)
Cross-Origin Resource Sharing (CORS) वह तरीका है जिससे server browser को बताता है कि कौन-से दूसरे origins उसके responses पढ़ सकते हैं। Origin किसी URL का scheme, host और port है, यानी वे हिस्से जिन्हें आपने URL, पाथ और क्वेरी पैरामीटर वाले lesson में अलग किया था। Same-origin policy के तहत https://shop.example.com पर चलने वाली script https://api.example.com को request भेज सकती है, लेकिन response तब तक नहीं पढ़ सकती जब तक API CORS headers से इसकी अनुमति न दे।
उदाहरण: shop page fetch('https://api.example.com/v1/cart') call करता है और browser request में Origin: https://shop.example.com जोड़ता है। अगर response में Access-Control-Allow-Origin: https://shop.example.com है, तो page को cart मिल जाता है; वरना उसके code को सिर्फ़ एक generic network error मिलता है और Console में CORS error दिखता है।
यह क्यों ज़रूरी है
जब front end और API अलग-अलग origins पर हों, तो missing या गलत CORS header असली features तोड़ देता है: cart load नहीं होता, save button कुछ नहीं करता, error message कभी नहीं दिखता। अक्सर सिर्फ़ एक environment fail होता है, क्योंकि हर environment के अपने domains और gateway settings होते हैं।
CORS data की सुरक्षा भी करता है: जो server किसी भी origin को user की cookies के साथ भेजे गए responses पढ़ने देता है, वह user की खोली दूसरी websites को भी वह data पढ़ने दे सकता है। Tester के लिए CORS कई "Postman में चलता है, browser में fail होता है" reports की वजह समझाता है।
Origins और same-origin policy
दो URLs का origin तभी एक होता है जब scheme, host और port तीनों बिल्कुल एक हों; path और query से फ़र्क नहीं पड़ता। Subdomain अलग host है और http, https से अलग scheme है, इसलिए shop और उसका API दो अलग origins हैं, भले दोनों एक ही company चलाती हो।
Same-origin policy मुख्य रूप से पढ़ने के बारे में है, भेजने के बारे में नहीं: दूसरे origins के links, forms, images और scripts पहले की तरह काम करते हैं। वह script को दूसरे origin का response पढ़ने से रोकती है। CORS इस नियम को server की शर्तों पर ढीला करता है: server headers भेजता है, browser उन्हें लागू करता है, और browser के बाहर के clients, जैसे curl या Postman, उन्हें नज़रअंदाज़ करते हैं।
Page origin: https://shop.example.com
URL Same origin? Why
https://shop.example.com/cart?id=7 yes only path and query differ
https://shop.example.com:443/help yes 443 is the default https port
http://shop.example.com/cart no scheme differs
https://api.example.com/v1/cart no host differs (subdomain)
https://shop.example.com:8443/cart no port differsSimple और preflighted requests
ऐसी GET, HEAD या POST request जिसमें सिर्फ़ CORS-safelisted headers हों, जैसे Accept या text/plain, multipart/form-data या application/x-www-form-urlencoded वाला Content-Type, तुरंत Origin header के साथ भेज दी जाती है। MDN इसे simple request कहता है; Fetch Standard यह नाम इस्तेमाल नहीं करता। Server इसे process करता है, उसकी CORS settings चाहे जो हों; CORS सिर्फ़ यह तय करता है कि page response पढ़ सकता है या नहीं।
बाकी हर cross-origin request preflighted होती है: PUT, PATCH, DELETE, Content-Type: application/json वाली POST, या Authorization जैसा header। Browser पहले एक OPTIONS request भेजता है जिसमें वह method और headers बताता है जो वह इस्तेमाल करना चाहता है। असली request तभी भेजी जाती है जब इस preflight को ऐसा 2xx response मिले जिसके headers origin, method और headers की अनुमति दें, और फिर उसका response भी दोबारा जाँचा जाता है। जिस preflight का जवाब redirect या error status हो, वह fail होता है और असली request browser से कभी बाहर नहीं जाती।
Credentials (cookies या HTTP authentication, जो दूसरे origin को सिर्फ़ तब भेजे जाते हैं जब script माँगे: fetch में credentials: 'include' से या XMLHttpRequest में withCredentials = true से) नियम और सख़्त करते हैं: दोनों responses में ठीक वही origin होना चाहिए, * कभी नहीं, और Access-Control-Allow-Credentials: true भी; तब allowed methods या headers में * भी wildcard की तरह काम नहीं करता। Preflight ख़ुद कभी cookies नहीं ले जाता।
Simple request: कोई preflight नहीं
- शॉप का पेज
https://shop.example.com - ब्राउज़र
- API
api.example.com
- 1 शॉप का पेज से ब्राउज़र तक: Cart पढ़ता है
GET /v1/cart - 2 ब्राउज़र से API तक: तुरंत भेजता है,
Originके साथOrigin: https://shop.example.com - 3 API से ब्राउज़र तक: Process करके response देता है जवाब CORS settings चाहे जो हों
- 4 ब्राउज़र आंतरिक रूप से:
Access-Control-Allow-Originजाँचता है Page का origin, या cookies न हों तो* - 5 ब्राउज़र से शॉप का पेज तक: Data, या generic network error जवाब
परिणाम: Server request को हर हाल में handle करता है; CORS सिर्फ़ तय करता है कि page जवाब पढ़ सकता है या नहीं।
- शॉप का पेज
Preflighted request: cookies के साथ PUT
- शॉप का पेज
https://shop.example.com - ब्राउज़र
- API
api.example.com
- 1 शॉप का पेज से ब्राउज़र तक: Cart update करता है JSON body,
credentials: 'include'PUT /v1/cart/items/42 - 2 ब्राउज़र से API तक: Preflight, बिना cookies वह method और headers बताता है जो इस्तेमाल होंगे
OPTIONS /v1/cart/items/42 - 3 API से ब्राउज़र तक:
Access-Control-Allow-*के साथ 2xx जवाब - 4 ब्राउज़र आंतरिक रूप से: Origin, method, headers और credentials जाँचता है Redirect, error status या कोई भी mismatch यहीं रोक देता है
- 5 ब्राउज़र से API तक: असली request, cookies के साथ
PUT /v1/cart/items/42 - 6 API से ब्राउज़र तक: ठीक वही origin बताने वाला response जवाब और
Access-Control-Allow-Credentials: true - 7 ब्राउज़र आंतरिक रूप से: Response फिर से जाँचता है
- 8 ब्राउज़र से शॉप का पेज तक: Data, या generic network error जवाब
परिणाम: Preflight की जाँच fail हो तो
PUTकभी नहीं भेजा जाता।- शॉप का पेज
जब तक cache किया हुआ preflight result valid है (Access-Control-Max-Age), browser दूसरे panel के क़दम 2 से 4 छोड़ देता है।
Origin(browser set करता है), और preflight मेंAccess-Control-Request-MethodवAccess-Control-Request-Headers: कौन पूछ रहा है और असली request क्या इस्तेमाल करेगी।Access-Control-Allow-Origin: पढ़ने की अनुमति वाला एक ही origin, या credentials न हों तो*।Access-Control-Allow-Methods,Access-Control-Allow-Headers: preflight response किसकी अनुमति देता है।Access-Control-Allow-Credentials: true: credentials भेजे जाने पर ज़रूरी।Access-Control-Expose-Headers: अतिरिक्त response headers जिन्हें script पढ़ सकती है, जैसेX-Total-Count।Access-Control-Max-Age: कितने seconds तक preflight result दोबारा इस्तेमाल हो सकता है, हर browser की अपनी सीमा के भीतर।Vary: Origin: caches को बताता है कि response origin के हिसाब से बदलता है; जब server origin echo करे तब ज़रूरी।
आम misconfigurations
ज़रूरत से ज़्यादा सख़्त या असंगत settings असली front end को block करके features तोड़ती हैं; ज़रूरत से ज़्यादा ढीली settings दूसरी websites को signed-in user के browser के ज़रिए data पढ़ने देती हैं, इसीलिए OWASP Web Security Testing Guide में CORS शामिल है। कोई दूसरी website असल में कितना कर पाती है, यह cookies के SameSite attribute और browser की third-party cookie settings पर भी निर्भर है (cookies और sessions वाला lesson देखें), लेकिन tester ज़रूरत से ज़्यादा ढीली policy को ही report करता है।
- Features तोड़ता है:
OPTIONSपर authentication, जिससे बिना cookies वाले preflight को401या403मिलता है। - Features तोड़ता है: preflight पर redirect, जैसे trailing slash जोड़ना (HTTP redirects वाला lesson देखें)।
- Features तोड़ता है: CORS headers सिर्फ़ success responses पर, जिससे
400या500page तक generic network error बनकर पहुँचता है। - Features तोड़ता है:
Access-Control-Allow-Originदो बार (application और gateway से) या list के रूप में भेजना; इसमें एक ही value होनी चाहिए। - Data उजागर करता है: किसी भी
OriginकोAccess-Control-Allow-Credentials: trueके साथ echo करना, याOrigin: nullकी अनुमति देना, जिसे कोई भी website sandboxed frame से बना सकती है। - Data उजागर करता है: origins को prefix, suffix या बिना anchor वाले pattern से match करना, जिससे
https://shop.example.com.attacker.testयाhttps://notexample.comपास हो जाता है।
CORS को कैसे टेस्ट करें
शुरुआत असली browser में करें, क्योंकि CORS सिर्फ़ browser लागू करता है। DevTools के Network panel में preflight असली request से ठीक पहले अपनी अलग OPTIONS entry के रूप में दिखता है (छिपा हो तो Fetch/XHR filter हटा दें)। Console बताता है कि response क्यों block हुआ; page के code को सिर्फ़ generic error मिलता है, Chrome में TypeError: Failed to fetch।
फिर requests को curl या CORS Tester से दोबारा भेजें, ज़रूरत का कोई भी Origin set करें और browser वाली जाँचें ख़ुद लागू करें, सिर्फ़ उन systems पर जो आपके अपने हों या जिनकी लिखित अनुमति हो। Test conditions असली callers से निकालें: हर environment का हर front-end origin, हर method और header, cookies के साथ और बिना।
- Allowed origin: सही
Allow-*headers वाला 2xx preflight, और असली response पर भीAccess-Control-Allow-Origin। https://attacker.testऔरnullजैसे unlisted origins, और allowed origin के variants:https://की जगहhttp://, दूसरा port,https://shop.example.com.attacker.testजैसे मिलते-जुलते hosts। कोई भी echo नहीं होना चाहिए।- हर method और header जो front end सच में भेजता है, सिर्फ़
GETनहीं। - Error responses (
401,404,500) पर success जैसे ही CORS headers। - Credentials के साथ:
*नहीं, और जब भी origin echo हो तोVary: Origin।
curl -i -X OPTIONS https://api.example.com/v1/cart/items/42 \
-H "Origin: https://shop.example.com" \
-H "Access-Control-Request-Method: PUT" \
-H "Access-Control-Request-Headers: content-type"आज़माएँ: CORS टेस्टर आज़माएँ: cURL जनरेटर आज़माएँ: HTTP हेडर पार्सर
Worked example: production में block हुआ cart update
Staging में cart की quantity बदलना काम करता है; production में कुछ नहीं होता और Console CORS error दिखाता है। https://shop.example.com वाला front end https://api.example.com को JSON body और cookies के साथ PUT /v1/cart/items/42 भेजता है, इसलिए browser उसका preflight करता है। Tester preflight को curl से दोबारा भेजता है।
Status, origin और credentials सही हैं, लेकिन Access-Control-Allow-Methods में PUT नहीं है, इसलिए browser preflight के बाद रुक जाता है और PUT कभी API तक नहीं पहुँचता; किसी server log में failed update नहीं दिखता। Staging इसलिए चलता है कि उसका gateway अलग से configure है।
Preflight और GET /v1/cart को Origin: https://attacker.test और एक दूसरे असंबंधित origin के साथ दोहराने पर दोनों origins Access-Control-Allow-Credentials: true के साथ echo होते हैं: यह अलग security defect है, जिसे privately report किया जाता है, क्योंकि तब दूसरी websites signed-in customer का data पढ़ सकती हैं।
OPTIONS /v1/cart/items/42 HTTP/1.1
Host: api.example.com
Origin: https://shop.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: content-type
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://shop.example.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Credentials: true
Vary: Originआम गलतियाँ
- यह मान लेना कि CORS error का मतलब है request server तक पहुँची ही नहीं: simple request भेजी और process की जा चुकी होती है, इसलिए कोई
POSTdata बदल भी चुका हो सकता है, जबकि fail हुए preflight के बाद असली request भेजी ही नहीं जाती। - Fix को verified मान लेना क्योंकि अब curl या Postman चलता है। वे CORS को नज़रअंदाज़ करते हैं; आख़िरी जाँच browser में होनी चाहिए।
- सिर्फ़ allowed origin टेस्ट करना, और कभी unlisted, मिलता-जुलता या
nullorigin नहीं। - सिर्फ़
GETऔर success path टेस्ट करना, जिससे missingPUTया500responses पर missing headers पकड़े नहीं जाते। - Testing unblock करने के लिए
Access-Control-Allow-Origin: *माँगना: यह cookies के साथ fail होता है और API को हर website के लिए खोल देता है। - सख़्त किए गए नियम को बहुत जल्दी दोबारा टेस्ट करना: browser
Access-Control-Max-Ageख़त्म होने तक cache किया हुआ, ज़्यादा ढीला preflight result दोबारा इस्तेमाल कर सकता है।
QA का नज़रिया
Team में CORS API reviews और environment checklists का हिस्सा है। जल्दी पूछें कि हर environment में कौन-से origins API को call करते हैं, क्या कोई call cookies भेजती है, front end कौन-से methods और custom headers इस्तेमाल करता है, और configuration किसके पास है: application, gateway या CDN।
CORS defect report करते समय preflight और असली request उनके headers के साथ, exact Origin, browser और Console message attach करें, और expected value बताएँ ("Access-Control-Allow-Methods में PUT होना चाहिए")। ज़्यादा ढीली policy को security finding के रूप में privately report करें, और fix के बाद unlisted-origin वाली जाँच regression suite में रखें।
अभ्यास
तीन preflight responses की समीक्षा करें
https://portal.example.com वाला front end https://api.example.com पर cookies (credentials: 'include') और X-CSRF-Token header के साथ DELETE /v1/sessions/current call करता है। नीचे इस call के तीन preflights पर API के जवाब हैं। हर एक के लिए तय करें कि browser DELETE भेजता है या नहीं, और हर समस्या लिखें।
# A request Origin: https://portal.example.com
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, DELETE
Access-Control-Allow-Headers: X-CSRF-Token
Access-Control-Allow-Credentials: true
# B request Origin: https://portal.example.com
HTTP/1.1 401 Unauthorized
Access-Control-Allow-Origin: https://portal.example.com
Access-Control-Allow-Credentials: true
# C request Origin: https://evil.test
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://evil.test
Access-Control-Allow-Methods: GET, POST, DELETE
Access-Control-Allow-Headers: X-CSRF-Token
Access-Control-Allow-Credentials: true
Vary: Origin- Status: क्या यह 2xx है?
- Credentials वाले नियम के साथ
Access-Control-Allow-Originकी तुलना request origin से करें। - क्या
DELETEऔरX-CSRF-Tokenकी अनुमति है? - क्या
DELETEभेजा जाता है? हर समस्या को functional या security में बाँटें।
मॉडल उत्तर दिखाएँ
A: block, यह functional defect है। Call cookies भेजती है, और credentials के साथ Access-Control-Allow-Origin में ठीक वही origin होना चाहिए, * नहीं। Fix: https://portal.example.com लौटाएँ, और value हर request के हिसाब से चुनी जाए तो साथ में Vary: Origin।
B: block, यह functional defect है। Preflight को 2xx चाहिए; 401 दिखाता है कि OPTIONS का जवाब देने से पहले authentication चलता है, जबकि preflight कभी cookies नहीं ले जाता। DELETE और X-CSRF-Token की अनुमति भी नहीं है। Fix: preflights का जवाब authentication से पहले, पूरे Allow-* headers के साथ दें।
C: browser इसे जाने देता है, और यही समस्या है: API credentials के साथ ऐसा origin स्वीकार करता है जो उसका कोई front end नहीं, इसलिए https://evil.test का page signed-in user की cookies के साथ requests भेज सकता है और उनके responses पढ़ सकता है। यह security defect है; किसी दूसरे असंबंधित origin से पुष्टि करें और privately report करें।
अक्सर पूछे जाने वाले सवाल
क्या CORS मेरे API को attackers से बचाता है?
नहीं। CORS तय करता है कि browser किसी web page को क्या पढ़ने देता है; यह किसी को authenticate नहीं करता। curl, scripts और दूसरे servers किसी भी Origin header के साथ API call कर सकते हैं, इसलिए API को फिर भी authentication और authorisation चाहिए। यह CSRF से बचाव भी नहीं है: simple requests किसी भी CORS जाँच से पहले server तक पहुँच जाती हैं।
Request Postman में चलती है पर browser में fail क्यों होती है?
Postman और curl browsers नहीं हैं और same-origin policy लागू नहीं करते, इसलिए वे न preflight भेजते हैं न Access-Control-* headers जाँचते हैं। Browser दोनों करता है। Network panel में browser का preflight देखें और उसकी तुलना उसी Origin वाली OPTIONS request पर server के असली जवाब से करें।
क्या Access-Control-Allow-Origin: * हमेशा गलत है?
नहीं। Public data के लिए जिसे cookies की ज़रूरत नहीं, जैसे public catalogue, * ठीक और सरल है। यह user की cookies पर निर्भर responses के लिए गलत है (browsers credentials के साथ * वैसे भी reject करते हैं), और ऐसे internal APIs के लिए जोखिम भरा है जो callers को authenticate करने की बजाय अपने network पर भरोसा करते हैं।
संदर्भ
- Fetch StandardCORS को परिभाषित करता है: प्रीफ़्लाइट रिक्वेस्ट, Access-Control-* हेडर और कौन-से रिस्पॉन्स ब्राउज़र पेज को दिखा सकता है।
- Cross-Origin Resource Sharing (CORS) — MDNCORS व्यवहार में कैसे काम करता है: सिंपल बनाम प्रीफ़्लाइटेड रिक्वेस्ट, क्रेडेंशियल और ब्राउज़र की रिपोर्ट की गई त्रुटियाँ।
- OWASP Web Security Testing Guide (WSTG)वेब एप्लिकेशन और API की सुरक्षा कमज़ोरियों को परखने की संदर्भ कार्यप्रणाली, एक-एक टेस्ट के रूप में।
- HTML Living StandardHTML भाषा, नामित कैरेक्टर रेफ़रेंस (एंटिटी) और ब्राउज़रों के पार्सिंग नियमों सहित।
Mutqan tools से अभ्यास करें
CORS कॉन्फ़िगरेशन जाँचें: किसी origin से preflight और सामान्य रिक्वेस्ट भेजकर Access-Control-* हेडर देखें।
मेथड, URL, हेडर, बॉडी और auth विकल्पों से cURL कमांड बनाएँ।
कच्चे HTTP रिक्वेस्ट/रिस्पॉन्स हेडर को व्याख्या सहित एक संरचित तालिका में बदलें।
caching, CORS, security और content negotiation के प्रीसेट से HTTP हेडर तैयार करें।
और गहराई से
इस topic में आपकी प्रगति
प्रगति ट्रैक करने के लिए साइन इन करें
Topics पूर्ण चिह्नित करें, जहाँ छोड़ा था वहीं से जारी रखें और specialisation परीक्षाएँ खोलें।