ऑथेंटिकेशन बायपास
admin' OR '1'='1WHERE शर्त को हमेशा सत्य बनाकर लॉगिन बायपास करने का प्रयास
उपयोगकर्ता द्वारा दिए गए मान कभी भी SQL टेक्स्ट में इंटरपोलेट नहीं किए जाते — मान पैरामीटर प्लेसहोल्डर के ज़रिए बाइंड किए जाते हैं (डायलेक्ट-विशिष्ट, जैसे $1 या ?)
SQL इंजेक्शन आज भी वेब एप्लिकेशन की सबसे गंभीर कमज़ोरियों में से एक है
SQL इंजेक्शन तब होता है जब अविश्वसनीय डेटा को सुरक्षित पैरामीटर बाइंडिंग के बिना SQL टेक्स्ट में शामिल कर दिया जाता है। हमलावर क्वेरी का अर्थ बदलकर अनधिकृत डेटा तक पहुँच सकते हैं, रिकॉर्ड बदल सकते हैं या अनचाहे ऑपरेशन चला सकते हैं।
admin' OR '1'='1WHERE शर्त को हमेशा सत्य बनाकर लॉगिन बायपास करने का प्रयास
' UNION SELECT password FROM users--दूसरी टेबल से डेटा निकालने के लिए UNION का उपयोग करने का प्रयास
'; DROP TABLE users; --डेटा हटाने के लिए अतिरिक्त स्टेटमेंट जोड़ने का प्रयास
एक्सप्लॉइट: यदि प्लेसहोल्डर और params मेल नहीं खाते, तो ऑथराइज़ेशन जाँच गलत मानों का उपयोग कर सकती हैउदाहरण: WHERE userId=$1 AND isAdmin=$2, लेकिन [123, true] के बजाय params=[true, 123] होने पर गलती से admin एक्सेस मिल सकता है
हर क्वेरी कई सुरक्षा सत्यापन लेयर से गुज़रती है
उपयोगकर्ता द्वारा दिए गए सभी मान बाउंड पैरामीटर में बदले जाते हैं। मान SQL टेक्स्ट में लिटरल के रूप में प्रवेश नहीं करते।
क्वेरी जनरेशन से पहले हर फ़ील्ड नाम को Prisma स्कीमा मेटाडेटा के विरुद्ध सत्यापित किया जाता है।
टेबल नाम, कॉलम नाम और एलियास सत्यापित किए जाते हैं और आवश्यकता के अनुसार सुरक्षित रूप से क्वोट/एस्केप किए जाते हैं।
हर फ़ील्ड टाइप के लिए केवल ज्ञात, सुरक्षित ऑपरेटर की अनुमति है।
सख़्त क्रम सुनिश्चित करता है कि हर प्लेसहोल्डर इंसर्शन क्रम में ठीक एक पैरामीटर से मैप हो, जिससे बेमेल की स्थिति नहीं बनती।
बताई गई डिज़ाइन मान्यताओं (पैरामीटर बाइंडिंग, कोई raw-SQL बायपास नहीं, ड्राइवर का सही उपयोग) के तहत इंजेक्शन प्रतिरोध के प्रमाण-रेखाचित्र
उपयोगकर्ता द्वारा दिए गए सभी मानों V के लिए, ऐसा कोई निष्पादन पथ नहीं है जिसमें V जनरेट की गई क्वेरी स्ट्रिंग में SQL टेक्स्ट के रूप में दिखाई दे।
निर्माण के अनुसार, उपयोगकर्ता मानों को संभालने वाले सभी कोड पथ addParameter(value) को कॉल करते हैं, जो: 1. मान को एक अलग params ऐरे में संग्रहीत करता है 2. SQL टेक्स्ट के लिए एक प्लेसहोल्डर टोकन लौटाता है 3. SQL स्ट्रिंग में केवल प्लेसहोल्डर टोकन जोड़ा जाता है 4. डेटाबेस ड्राइवर SQL टेक्स्ट और पैरामीटर मान अलग-अलग प्राप्त करता है ∴ उपयोगकर्ता मानों को SQL सिंटैक्स के रूप में पार्स नहीं किया जाता
const addParameter = (params: any[], value: any) => {
params.push(value)
const index = params.length
return `$${index}`
}किसी भी जनरेट की गई क्वेरी में फ़ील्ड नामों का समुच्चय F, स्कीमा में परिभाषित फ़ील्ड S का उपसमुच्चय है, अर्थात F ⊆ S।
हर फ़ील्ड संदर्भ के लिए: 1. क्वेरी ऑब्जेक्ट से फ़ील्ड नाम निकाला जाता है 2. स्कीमा मेटाडेटा में लुकअप किया जाता है 3. यदि फ़ील्ड स्कीमा में मौजूद नहीं है, तो एरर थ्रो की जाती है 4. केवल सत्यापित फ़ील्ड SQL जनरेशन तक पहुँचते हैं ∴ मनमाने फ़ील्ड नाम SQL में नहीं आ सकते
const validateField = (field: string, model: Model) => {
if (!model.fields.has(field)) {
throw new Error(`Field ${field} does not exist`)
}
return model.fields.get(field)
}फ़ील्ड F पर लागू किसी भी ऑपरेटर O के लिए, O फ़ील्ड F के टाइप T के लिए अनुमत ऑपरेटरों में से एक होता है।
ऑपरेटर सत्यापन एल्गोरिदम: 1. स्कीमा से फ़ील्ड टाइप T निकालें 2. allowed_ops(T) = { टाइप T के लिए मान्य ऑपरेटर } परिभाषित करें 3. क्वेरी में ऑपरेटर O के लिए: - यदि O ∉ allowed_ops(T), तो एरर थ्रो करें - अन्यथा पैरामीटर बाइंडिंग के साथ ऑपरेटर लागू करें ∴ केवल टाइप के अनुरूप ऑपरेटर उपयोग किए जा सकते हैं
const ALLOWED_OPS: Record<string, string[]> = {
String: ['contains', 'startsWith', 'endsWith'],
Int: ['lt', 'lte', 'gt', 'gte']
}
if (!ALLOWED_OPS[fieldType]?.includes(operator)) {
throw new Error('Invalid operator')
}सभी SQL आइडेंटिफ़ायर I को सत्यापित किया जाता है ताकि कंट्रोल कैरेक्टर रोके जा सकें और हर डायलेक्ट के अनुसार सुरक्षित क्वोटिंग/एस्केपिंग सुनिश्चित हो।
आइडेंटिफ़ायर प्रोसेसिंग: 1. कंट्रोल कैरेक्टर होने पर अस्वीकार करें 2. डायलेक्ट के नियमों के अनुसार आंतरिक क्वोट कैरेक्टर एस्केप करें 3. आवश्यकता होने पर (आरक्षित कीवर्ड या विशेष कैरेक्टर) आइडेंटिफ़ायर क्वोट करें 4. हर डायलेक्ट की आइडेंटिफ़ायर लंबाई सीमा लागू करें ∴ आइडेंटिफ़ायर SQL सिंटैक्स नहीं तोड़ सकते और न ही इंजेक्ट किए गए टोकन जोड़ सकते हैं
const quoteIdentifier = (id: string) => {
if (/[\x00-\x1F]/.test(id)) {
throw new Error('Invalid characters')
}
const escaped = id.replace(/"/g, '""')
const needsQuoting = /[^a-z0-9_]/i.test(id) || isReservedKeyword(id)
return needsQuoting ? `"${escaped}"` : id
}SQL टेक्स्ट में जोड़ी गई हर प्लेसहोल्डर स्थिति N के लिए, params[N-1] में उसी स्थिति के लिए अभिप्रेत सटीक मान होता है, बिना किसी क्रम-परिवर्तन या बेमेल के।
पैरामीटर क्रम की गारंटी: 1. एक ही ट्रैकर इंसर्शन क्रम बनाए रखता है 2. हर add() कॉल मान को params में जोड़ती है और तुरंत अगला प्लेसहोल्डर टोकन देती है 3. SQL टेक्स्ट निर्माण और params निर्माण साथ-साथ (lockstep) चलते हैं 4. कोई मध्यवर्ती क्रम-परिवर्तन ऑपरेशन नहीं होता ∴ शुरू से अंत तक एक-से-एक संबंध बना रहता है
class ParameterTracker {
private params: any[] = []
add(value: any): string {
this.params.push(value)
return `$${this.params.length}`
}
getParams(): any[] {
return this.params
}
}
const tracker = new ParameterTracker()
const sql = `WHERE email = ${tracker.add(email)} AND age > ${tracker.add(age)}`
const params = tracker.getParams()मौजूदा सूट आम SQL इंजेक्शन वेक्टर और एज केस के विरुद्ध सुरक्षा को सत्यापित करता है
const email = req.body.email
const sql = "SELECT * FROM users WHERE email = '" + email + "'"const email = req.body.email
const { sql, params } = toSQL('User', 'findMany', {
where: { email }
})
const result = { sql, params }केंद्रीकृत पैरामीटर ट्रैकिंग सुनिश्चित करती है कि उपयोगकर्ता द्वारा दिया गया हर मान पैरामीटर के रूप में बाउंड हो और उसका क्रम स्थिर रहे
class ParameterTracker {
private params: any[] = []
add(value: any): string {
this.params.push(value)
return `$${this.params.length}`
}
getParams(): any[] {
return this.params
}
}स्कीमा-आधारित सत्यापन मनमाने फ़ील्ड एक्सेस को रोकता है
function validateField(
fieldName: string,
model: ModelInfo
): FieldInfo {
const field = model.fields.get(fieldName)
if (!field) {
throw new Error(
`Field "${fieldName}" does not exist`
)
}
return field
}डायलेक्ट-अवेयर आइडेंटिफ़ायर सत्यापन और क्वोटिंग, आइडेंटिफ़ायर-आधारित सिंटैक्स इंजेक्शन को रोकते हैं
function quoteIdentifier(identifier: string): string {
if (/[\x00-\x1F]/.test(identifier)) {
throw new Error('Invalid control characters')
}
const escaped = identifier.replace(/"/g, '""')
const needsQuoting = /[^a-z0-9_]/i.test(identifier) || isReservedKeyword(identifier)
if (needsQuoting) {
return `"${escaped}"`
}
return identifier
}स्कीमा सत्यापन या फ़ील्ड जाँच को बायपास न करें। ये महत्वपूर्ण सुरक्षा लेयर हैं।
सुनिश्चित करें कि आपका Prisma स्कीमा आपके डेटाबेस की संरचना को सटीक रूप से दर्शाता है।
TypeScript कंपाइल-टाइम सुरक्षा देता है, लेकिन रनटाइम सत्यापन सुरक्षा की एक अतिरिक्त परत (defense in depth) जोड़ता है।
विसंगतियों और दुरुपयोग का पता लगाने के लिए प्रोडक्शन में जनरेट किए गए SQL और पैरामीटर को लॉग करें और उनकी निगरानी करें।
SQL इंजेक्शन से सुरक्षा इस लाइब्रेरी की हर लेयर में शामिल है। सुरक्षा टेस्ट और कार्यान्वयन विवरण की सीधे समीक्षा करें।