● CWE-942 · OWASP A05:2021

CORS की ग़लत कॉन्फ़िगरेशन (CWE-942): Origin लौटाने से डेटा कैसे लीक होता है और इसे कैसे ठीक करें

जो API हर Origin को उसी origin वाले Access-Control-Allow-Origin और Access-Control-Allow-Credentials: true के साथ जवाब देता है, वह हर वेबसाइट को विज़िटर की cookies के साथ अपने responses पढ़ने देता है। suffix जाँच, null origin और लौटाए गए origins same-origin policy को कैसे तोड़ते हैं, और exact-match allowlist जो इसे ठीक करती है, Express और cors के उदाहरण के साथ।

आसान भाषा में (ELI5)

बैंक का क्लर्क आपका बैलेंस उस व्यक्ति को पढ़कर सुना देता है जिसे आप भेजें, बशर्ते संदेशवाहक एक चिट्ठी दिखाए कि वह किसके लिए काम करता है और क्लर्क की सूची उस नाम को मंज़ूरी दे। एक क्लर्क का नियम है: 'जिस भी नाम के अंत में शर्मा आए, उसे मंज़ूर करो।' एक अजनबी 'वर्मा-शर्मा' की चिट्ठी के साथ संदेशवाहक भेजता है, क्लर्क मंज़ूर कर देता है, और आपका बैलेंस ऐसे व्यक्ति को सुनाया जाता है जिसे आपने कभी नहीं भेजा। Origin लौटाना इसका आलसी रूप है, जिसमें क्लर्क हर नाम को मंज़ूर कर देता है। उपाय नामों की एक छोटी, सटीक सूची है जिसका अक्षर-अक्षर मिलान हो।

इस पेज के मुख्य शब्द

Same-origin policy
browser किसी script को केवल उसके अपने origin (scheme, host और port) के responses पढ़ने देते हैं। CORS response headers वह तरीका हैं जिससे सर्वर जानबूझकर नामित origins के लिए यह नियम ढीला करता है।
Credentials के साथ Access-Control-Allow-Origin
अगर response Access-Control-Allow-Origin में caller का origin लिखे और Access-Control-Allow-Credentials: true भेजे, तो उस origin की script उन रिक्वेस्ट के responses पढ़ सकती है जिनमें यूज़र की cookies गई थीं। browser credentials के साथ * को ठुकराते हैं, इसीलिए ग़लत कॉन्फ़िगर किए सर्वर origin को ही लौटा देते हैं।
Origin लौटाना और suffix मिलान
Origin header को response में कॉपी करना हर साइट पर भरोसा करना है। endsWith('example.com') जैसी जाँच, substring मिलान या बिना anchor और बिना escape किए dots वाले regular expressions भी https://attacker-example.com को स्वीकार कर लेते हैं।
null origin
sandbox किए iframes, data: URLs और कुछ redirects Origin: null भेजते हैं। कोई भी हमलावर इसे बना सकता है, इसलिए null की अनुमति देना सबको अनुमति देने जैसा है।
Vary: Origin
जब Access-Control-Allow-Origin रिक्वेस्ट पर निर्भर हो, तो response में Vary: Origin होना चाहिए ताकि साझा caches एक origin के CORS headers दूसरे को न दें। cors package dynamic origins के लिए इसे जोड़ देता है।

हमले का चरण-दर-चरण प्रवाह

चरण 1

पीड़ित API की साइट पर लॉग-इन है

उसके browser में api.example.com की session cookie है जो cross-site रिक्वेस्ट पर भी भेजी जाती है।

चरण 2

वह हमलावर के domain का पेज खोलता है

एक script fetch('https://api.example.com/api/account', { credentials: 'include' }) बुलाती है। https://attacker-example.com का ऐसा पेज जो केवल console में response की लंबाई लिखता है, यह मामला दिखाता है।

चरण 3

API origin को मंज़ूर कर देता है

suffix जाँच attacker-example.com को स्वीकार कर लेती है, इसलिए response Access-Control-Allow-Origin में वही origin और साथ में Access-Control-Allow-Credentials: true भेजता है।

चरण 4

script निजी डेटा पढ़ लेती है

browser खाते का JSON हमलावर की script को दे देता है, जो उसे कहीं भी भेज सकती है। 2016 में James Kettle ने यह पैटर्न कई Bitcoin exchanges पर पाया, जहाँ इससे API keys और wallet डेटा उजागर होते थे।

सोर्स कोड: कमज़ोर बनाम सुरक्षित कार्यान्वयन

कमज़ोर कार्यान्वयन
// server.js: example.com पर ख़त्म होने वाला हर origin और null cookies के साथ पढ़ सकते हैं
import express from 'express';
import cors from 'cors';
import { accountFor, requireSession } from './account.js';

const app = express();

// true लौटाने पर cors caller का Origin credentials के साथ लौटा देता है
app.use(cors({
  origin: (origin, callback) => callback(null, !origin || origin === 'null' || origin.endsWith('example.com')),
  credentials: true,
}));

// मंज़ूर origins के लिए पढ़ने योग्य निजी खाता डेटा
app.get('/api/account', requireSession, (req, res) => {
  res.json(accountFor(req.session.userId));
});
सुरक्षित और सुदृढ़ फ़िक्स
// server.js: केवल दो सटीक origins
import express from 'express';
import cors from 'cors';
import { accountFor, requireSession } from './account.js';

const app = express();

// scheme और host सहित पूरे origins, सटीक तुलना
const ALLOWED_ORIGINS = new Set(['https://app.example.com', 'https://admin.example.com']);

// अनजान या ग़ायब Origin को कोई CORS header नहीं; cors Vary: Origin जोड़ता है
app.use(cors({
  origin: (origin, callback) => callback(null, origin !== undefined && ALLOWED_ORIGINS.has(origin)),
  credentials: true,
  methods: ['GET', 'POST'],
  maxAge: 600,
}));

// निजी डेटा कभी साझा caches में नहीं जाता
app.get('/api/account', requireSession, (req, res) => {
  res.set('Cache-Control', 'no-store');
  res.json(accountFor(req.session.userId));
});

इंजीनियरिंग और सिस्टम सुरक्षा चेकलिस्ट

स्रोत

← पूरी सुरक्षा निर्देशिका देखें सभी कमज़ोरी गाइड →