एक SQL इंजेक्शन को दोहराएँ, उसे प्रिपेयर्ड स्टेटमेंट से निष्प्रभावी करें, और न्यूनतम विशेषाधिकार लागू करें।
इस पाठ को Kodokon में खोलेंएक SQL इंजेक्शन उसी क्षण होता है जब अविश्वसनीय डेटा को किसी क्वेरी के टेक्स्ट में जोड़ा (concatenate) जाता है। हमलावर एक ऐसी वैल्यू देता है जो स्ट्रिंग को बंद कर देती है और तर्क को हाईजैक कर लेती है। आइए users टेबल पर हमले को दोहराएँ: इनपुट ada' OR '1'='1 को सीधे जोड़ना एक सटीक फ़िल्टर को हमेशा-सही शर्त में बदल देता है।
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
is_admin INTEGER NOT NULL DEFAULT 0
);
INSERT INTO users (id, name, is_admin)
VALUES (1, 'ada', 0), (2, 'root', 1);
-- Dangerous concatenation (NEVER do this)
-- input = ada' OR '1'='1
SELECT * FROM users
WHERE name = 'ada' OR '1'='1';पेलोड काम करता है क्योंकि उद्धरण चिह्न समय से पहले लिटरल 'ada' को बंद कर देता है, फिर OR '1'='1' एक सार्वभौमिक रूप से सही शर्त जोड़ देता है। एक रूप मूल क्वेरी के बाकी हिस्से को कमेंट करने के लिए -- जोड़ता है। सबक: जब तक डेटा और कोड एक ही स्ट्रिंग साझा करते हैं, तब तक कोई भी मैनुअल एस्केपिंग वास्तव में भरोसेमंद नहीं है।
-- Positional placeholder
SELECT * FROM users WHERE name = ?;
-- Named placeholder
SELECT * FROM users WHERE name = :name;इसका उपाय है प्रिपेयर्ड स्टेटमेंट: ड्राइवर पहले क्वेरी की संरचना को कंपाइल करता है, फिर वैल्यू को अलग से बाइंड करता है। बाउंड डेटा को कभी SQL के रूप में पार्स नहीं किया जाता, केवल तुलना की जाती है। एक अतिरिक्त लाभ के रूप में, कंपाइल की गई संरचना पुनः उपयोग योग्य है: क्रमिक रूप से कई वैल्यू बाइंड करना हर कॉल पर प्लान को दोबारा कंपाइल करने से बचाता है।
-- The bound value stays data, not SQL
SELECT * FROM users
WHERE name = :name;
-- :name = ada' OR '1'='1
-- -> 0 rows: no user
-- is literally named that' OR '1'='1 इंजेक्शन में सफल होता है क्योंकि यह...? पैरामीटर के माध्यम से बाइंड कर सकते हैं?:name के साथ