दिलचस्प पोस्ट
वर्ग << रुबी में स्वयं मुहावरे शरीर का 100% ब्राउज़र ऊँचाई बनाएं साइगविन और मिनजीड के बीच क्या फर्क है? क्या टुकड़ों को वाकई एक खाली कन्स्ट्रक्टर की ज़रूरत है? ऑटोमैपर: "बाकी को अनदेखा करें"? जावा में शट डाउन हुक का उपयोगी उदाहरण? एक संदर्भित संदर्भ क्या है? किसी शर्त से सरणी कैसे फ़िल्टर करें जावा: एसएसएल हैंडशेक क्यों 'डीएच कीपैयर उत्पन्न नहीं कर सकता' अपवाद दे रहा है? आवेदनआप कब कहा जाता है और कब नहीं कहा जाता है मैं jQuery के साथ एक तत्व का चयन कैसे कर सकता हूं? आप फ़ंक्शन के बजाय एक्सपेन <Func <T >> का उपयोग क्यों करेंगे? याद रखें और फ़ाइल इनपुट को फिर से बदलना गिट में फ़ाइल नामों का कैपिटलाइज़ेशन बदलना node.js के बाहर निकलने से पहले सफाई कार्रवाई कर रही है

मैं PHP में एसक्यूएल इंजेक्शन कैसे रोक सकता हूं?

यदि उपयोगकर्ता इनपुट किसी एसक्यूएल क्वेरी में संशोधन के बिना डाला जाता है, तो आवेदन एसक्यूएल इंजेक्शन के लिए कमजोर पड़ता है, जैसे निम्न उदाहरण में:

$unsafe_variable = $_POST['user_input']; mysql_query("INSERT INTO `table` (`column`) VALUES ('$unsafe_variable')"); 

ऐसा इसलिए है क्योंकि उपयोगकर्ता इनपुट की तरह कुछ भी इनपुट कर सकता है value'); DROP TABLE table;-- value'); DROP TABLE table;-- , और क्वेरी बन जाती है:

 INSERT INTO `table` (`column`) VALUES('value'); DROP TABLE table;--') 

ऐसा होने से रोकने के लिए क्या किया जा सकता है?

वेब के समाधान से एकत्रित समाधान "मैं PHP में एसक्यूएल इंजेक्शन कैसे रोक सकता हूं?"

तैयार बयानों और पैरामीटर वाले प्रश्नों का उपयोग करें ये एसक्यूएल स्टेटमेंट हैं जो किसी भी पैरामीटर से अलग से डाटाबेस सर्वर पर भेजे और पार्स किए जाते हैं। इस तरह दुर्भावनापूर्ण SQL इंजेक्शन लगाने के लिए किसी आक्रमणकर्ता के लिए असंभव है।

आपको इसे हासिल करने के लिए मूल रूप से दो विकल्प हैं:

  1. पीडीओ का उपयोग करना (किसी भी समर्थित डेटाबेस ड्राइवर के लिए):

     $stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name'); $stmt->execute(array('name' => $name)); foreach ($stmt as $row) { // do something with $row } 
  2. MySQLi का प्रयोग (MySQL के लिए):

     $stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?'); $stmt->bind_param('s', $name); $stmt->execute(); $result = $stmt->get_result(); while ($row = $result->fetch_assoc()) { // do something with $row } 

यदि आप MySQL के अलावा कोई अन्य डेटाबेस से कनेक्ट हो रहे हैं, तो एक ड्राइवर-विशिष्ट दूसरा विकल्प है जिसे आप (उदाहरण के लिए pg_prepare() और pg_execute() पोस्टग्रेएसक्यूएल के लिए देख सकते हैं। पीडीओ सार्वभौमिक विकल्प है।

कनेक्शन को सही ढंग से सेट करना

ध्यान दें कि जब एक MySQL डाटाबेस का उपयोग करने के लिए PDO का इस्तेमाल किया जाता है तो वास्तविक तैयार बयान डिफ़ॉल्ट रूप से उपयोग नहीं किया जाता है । इसे ठीक करने के लिए आपको तैयार बयान के अनुकरण को अक्षम करना होगा। PDO का उपयोग कर कनेक्शन बनाने का एक उदाहरण है:

 $dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass'); $dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 

उपर्युक्त उदाहरण में त्रुटि मोड कड़ाई से जरूरी नहीं है, लेकिन इसे जोड़ने के लिए सलाह दी जाती है । इस तरह स्क्रिप्ट किसी Fatal Error साथ बंद नहीं होगी जब कुछ गलत हो जाता है और यह डेवलपर को किसी भी गलती को catch का मौका देता है जो PDOException एस के रूप में throw हैं।

क्या अनिवार्य है, पहली सेट विशेषता setAttribute() रेखा है, जो पीडीओ को तैयार किए गए बयानों को निष्क्रिय करने और वास्तविक तैयार बयान का उपयोग करने के लिए कहता है। यह सुनिश्चित करता है कि बयान और मूल्यों को PHP द्वारा पार्स नहीं किया जाता है, इसे भेजने से पहले MySQL सर्वर (संभावित हमलावर को दुर्भावनापूर्ण SQL इंजेक्ट करने का कोई मौका नहीं दे)।

यद्यपि आप कन्स्ट्रक्टर के विकल्पों में charset सेट कर सकते हैं, यह ध्यान रखना महत्वपूर्ण है कि PHP के पुराने संस्करण (<5.3.6) ने DSN में वर्णसेट पैरामीटर को चुपचाप रूप से अनदेखा किया

व्याख्या

क्या होता है कि एसक्यूएल स्टेटमेंट जो आप prepare वह डाटाबेस सर्वर द्वारा पार्स और संकलित किया जाता है। मापदंडों को निर्दिष्ट करके (या तो एक ? या नामांकित पैरामीटर जैसे :name ऊपर दिए गए उदाहरण में :name ) आप डेटाबेस इंजन को बताते हैं जहां आप फ़िल्टर करना चाहते हैं तब जब आप execute , तो तैयार कथन आप निर्दिष्ट पैरामीटर मूल्यों के साथ मिलकर किया जाता है।

यहां महत्वपूर्ण बात यह है कि पैरामीटर मान संकलित कथन के साथ जोड़ दिए जाते हैं, एक एसक्यूएल स्ट्रिंग नहीं। एसक्यूएल इंजेक्शन दुर्भावनापूर्ण स्ट्रिंग को शामिल करते हुए स्क्रिप्ट को चकरा देने से काम करता है जब डेटाबेस को भेजने के लिए एसक्यूएल बनाता है। तो मानकों से वास्तविक एसक्यूएल को अलग से भेजकर, आप जिस चीज़ का इरादा नहीं करते उसके साथ समाप्त होने के जोखिम को सीमित करते हैं। किसी तैयार पैरामीटर का उपयोग करते समय आपके द्वारा भेजे जाने वाले पैरामीटर को केवल तार के रूप में माना जाएगा (हालांकि डेटाबेस इंजिन कुछ अनुकूलन कर सकता है, इसलिए मानदंड संख्या के रूप में भी समाप्त हो सकते हैं)। ऊपर दिए गए उदाहरण में, यदि $name चर में 'Sarah'; DELETE FROM employees 'Sarah'; DELETE FROM employees परिणाम केवल "'Sarah'; DELETE FROM employees" स्ट्रिंग के लिए खोज होगा, "'Sarah'; DELETE FROM employees" , और आप एक खाली तालिका के साथ समाप्त नहीं होंगे

तैयार बयानों का उपयोग करने के लिए एक अन्य लाभ यह है कि यदि आप एक ही सत्र में उसी वक्तव को निष्पादित करते हैं तो यह केवल एक बार पार्स किया जाएगा और संकलित होगा, आपको कुछ गति लाभ देगा।

ओह, और जब से आपने पूछा कि यह कैसे डालने के लिए किया जाए, तो यह एक उदाहरण है (पीडीओ का उपयोग करना):

 $preparedStatement = $db->prepare('INSERT INTO table (column) VALUES (:column)'); $preparedStatement->execute(array('column' => $unsafeValue)); 

गतिशील प्रश्नों के लिए तैयार किए गए बयान का उपयोग किया जा सकता है?

जब भी आप क्वेरी पैरामीटर के लिए तैयार किए गए स्टेटमेंट का उपयोग कर सकते हैं, तो डायनामिक क्वेरी की संरचना को पैरामीटिज्ड नहीं किया जा सकता है और कुछ क्वेरी फीचर को पैरामीटिज्ड नहीं किया जा सकता है।

इन विशिष्ट परिदृश्यों के लिए, सबसे अच्छी बात यह है कि श्वेतसूची फ़िल्टर का उपयोग किया जाता है जो संभावित मूल्यों को प्रतिबंधित करता है।

 // Value whitelist // $dir can only be 'DESC' otherwise it will be 'ASC' if (empty($dir) || $dir !== 'DESC') { $dir = 'ASC'; } 

चेतावनी: प्रश्न का नमूना कोड PHP का mysql एक्सटेंशन का उपयोग करता है, जिसे PHP 5.5.0 में बहिष्कृत किया गया था और पूरी तरह से PHP 7.0.0 में हटा दिया गया था।

यदि आप PHP के हाल के संस्करण का उपयोग कर रहे हैं, तो नीचे उल्लिखित mysql_real_escape_string विकल्प अब उपलब्ध नहीं होगा (हालांकि mysqli::escape_string एक आधुनिक समकक्ष है)। इन दिनों mysql_real_escape_string विकल्प केवल mysql_real_escape_string कोड के लिए PHP के एक पुराने संस्करण पर ही होगा।


आपके पास दो विकल्प हैं – अपने unsafe_variable में विशेष वर्णों से बचने या पैरामीटर की गई क्वेरी का उपयोग करते हुए। दोनों आपको एसक्यूएल इंजेक्शन से बचाएंगे। पैरामीटर की गई क्वेरी को बेहतर अभ्यास माना जाता है लेकिन इससे पहले कि आप इसका उपयोग कर सकें, उसे PHP में एक नया MySQL एक्सटेंशन में बदलना होगा।

हम पहली बार से बचने वाले निचले प्रभाव स्ट्रिंग को कवर करेंगे।

 //Connect $unsafe_variable = $_POST["user-input"]; $safe_variable = mysql_real_escape_string($unsafe_variable); mysql_query("INSERT INTO table (column) VALUES ('" . $safe_variable . "')"); //Disconnect 

यह भी देखें, mysql_real_escape_string फ़ंक्शन का विवरण।

पैरामीटर वाली क्वेरी का उपयोग करने के लिए, आपको MySQL फ़ंक्शंस के बजाय MySQLi का उपयोग करना होगा। अपने उदाहरण को दोबारा लिखने के लिए, हमें निम्नलिखित की तरह कुछ आवश्यकता होगी

 <?php $mysqli = new mysqli("server", "username", "password", "database_name"); // TODO - Check that connection was successful. $unsafe_variable = $_POST["user-input"]; $stmt = $mysqli->prepare("INSERT INTO table (column) VALUES (?)"); // TODO check that $stmt creation succeeded // "s" means the database expects a string $stmt->bind_param("s", $unsafe_variable); $stmt->execute(); $stmt->close(); $mysqli->close(); ?> 

मुख्य फ़ंक्शन जिस पर आप पढ़ना चाहते हैं mysqli::prepare होगा mysqli::prepare

इसके अलावा, जैसा कि दूसरों ने सुझाव दिया है, आपको पीडीओ जैसे कुछ के साथ अमूर्त की एक परत बढ़ाना उपयोगी / आसान हो सकता है।

कृपया ध्यान दें कि जो मामला आपने पूछा है वह काफी आसान है और अधिक जटिल मामलों में अधिक जटिल दृष्टिकोण की आवश्यकता हो सकती है विशेष रूप से:

  • यदि आप उपयोगकर्ता इनपुट के आधार पर एसक्यूएल की संरचना को बदलना चाहते हैं, तो पैरामीटेटेड क्वेरीज़ आपकी मदद नहीं कर रहे हैं, और आवश्यक बचने के लिए mysql_real_escape_string द्वारा कवर नहीं किया गया है। इस तरह के मामले में, आप श्वेतसूची के माध्यम से उपयोगकर्ता के इनपुट को पारित करना बेहतर होगा क्योंकि यह सुनिश्चित करने के लिए कि केवल 'सुरक्षित' मूल्यों के माध्यम से अनुमति दी जाती है
  • यदि आप उपयोगकर्ता इनपुट से एक शर्त में पूर्णांक का उपयोग करते हैं और mysql_real_escape_string दृष्टिकोण लेते हैं, तो आपको नीचे टिप्पणी में बहुपद द्वारा वर्णित समस्या से ग्रस्त होगा। यह मामला जटिल है क्योंकि इंटिजर्स उद्धरण चिह्नों से घिरे नहीं होते, इसलिए आप यह मान्य कर सकते हैं कि उपयोगकर्ता इनपुट में केवल अंक होते हैं।
  • संभावित अन्य मामलों में मुझे पता नहीं है आपको मिल सकता है यह कुछ और सूक्ष्म समस्याओं पर उपयोगी संसाधन है जो आप मुठभेड़ कर सकते हैं।

प्रत्येक उत्तर में केवल समस्या का एक हिस्सा शामिल है।
वास्तव में, चार अलग-अलग क्वेरी पार्टियां हैं जिन्हें हम इसे गतिशील रूप से जोड़ सकते हैं:

  • एक स्ट्रिंग
  • एक संख्या
  • एक पहचानकर्ता
  • एक वाक्यविन्यास कीवर्ड

और तैयार बयान केवल उनमें से 2 शामिल हैं

लेकिन कभी-कभी हमें हमारी क्वेरी को और भी अधिक गतिशील बनाना पड़ता है, ऑपरेटरों या पहचानकर्ताओं को भी जोड़ना।
तो, हमें अलग सुरक्षा तकनीकों की आवश्यकता होगी

सामान्य तौर पर, इस तरह के सुरक्षा दृष्टिकोण श्वेतसूची में आधारित होता है । इस स्थिति में, हर गतिशील पैरामीटर को आपकी स्क्रिप्ट में हार्डकोड किया जाना चाहिए और उस सेट से चुना जाना चाहिए।
उदाहरण के लिए, गतिशील ऑर्डर करने के लिए:

 $orders = array("name","price","qty"); //field names $key = array_search($_GET['sort'],$orders)); // see if we have such a name $orderby = $orders[$key]; //if not, first one will be set automatically. smart enuf :) $query = "SELECT * FROM `table` ORDER BY $orderby"; //value is safe 

हालांकि, पहचानकर्ता को सुरक्षित रखने का एक और तरीका है – भागने जब तक आपके पास एक पहचानकर्ता उद्धृत होता है, तब तक आप दोहरीकरण करके बैकटीक्स से बच सकते हैं।

एक और कदम के रूप में, हम तैयार प्लेसमेंट से कुछ प्लेसहोल्डर (क्वेरी में वास्तविक मान का प्रतिनिधित्व करने के लिए एक प्रॉक्सी) का उपयोग करने के लिए वास्तव में एक शानदार विचार उधार ले सकते हैं और किसी अन्य प्रकार के प्लेसहोल्डर का आविष्कार – एक पहचानकर्ता प्लेसहोल्डर

इसलिए, लंबी कहानी कम करने के लिए: यह एक प्लेसहोल्डर है , तैयार नहीं किए गए बयान को चांदी की बुलेट के रूप में माना जा सकता है।

इसलिए, एक सामान्य सिफारिश के रूप में phrased किया जा सकता है
जब तक आप प्लेसहोल्डर्स (और इन प्लेसहोल्डर द्वारा ठीक से संसाधित किए गए) का उपयोग करते हुए क्वेरी में गतिशील भागों जोड़ रहे हैं, तो आप यह सुनिश्चित कर सकते हैं कि आपकी क्वेरी सुरक्षित है

फिर भी, एसक्यूएल वाक्यविन्यास खोजशब्दों (जैसे AND , DESC और ऐसे) के साथ एक मुद्दा है लेकिन सफेद-लिस्टिंग इस मामले में एकमात्र तरीका है।

अद्यतन करें

हालांकि एसक्यूएल इंजेक्शन संरक्षण के बारे में सर्वोत्तम प्रथाओं पर एक सामान्य करार है, फिर भी कई बुरे व्यवहार भी हैं। और उनमें से कुछ भी PHP उपयोगकर्ताओं के दिमाग में गहराई से निहित हैं। उदाहरण के लिए, इस पृष्ठ पर (ज्यादातर आगंतुकों के लिए अदृश्य होने पर) 80 से अधिक हटाए गए उत्तर – खराब गुणवत्ता के कारण समुदाय द्वारा सभी को हटा दिया गया या बुरा और पुरानी प्रथाओं को बढ़ावा देने के लिए। इससे भी बदतर, कुछ बुरे उत्तरों को हटाया नहीं जाता है, बल्कि उन्हें समृद्ध किया जाता है।

उदाहरण के लिए, वहाँ (1) हैं (2) अभी भी (3) कई (4) उत्तर (5) , जिसमें दूसरा सबसे अपोचित उत्तर है जिसमें आपको मैन्युअल स्ट्रिंग बचने का सुझाव है – एक पुराना दृष्टिकोण जो असुरक्षित साबित हुआ है

या थोड़ा बेहतर जवाब है जो स्ट्रिंग फ़ॉर्मेटिंग की एक और विधि का सुझाव देता है और यहां तक ​​कि अंतिम समाधान के रूप में दावा करता है। बेशक, यह नहीं है। यह विधि नियमित स्ट्रिंग फ़ॉर्मेटिंग से बेहतर नहीं है, फिर भी यह अपनी सभी कमियां रखती है: यह केवल स्ट्रिंग्स पर लागू होती है, और किसी अन्य मैनुअल फॉर्मेटिंग के रूप में, यह अनिवार्य रूप से वैकल्पिक, गैर-अनिवार्य उपाय है, जो किसी भी तरह की मानव त्रुटि से ग्रस्त है।

मुझे लगता है कि यह सब एक बहुत पुराने अंधविश्वास के कारण, ऐसे अधिकारियों जैसे ओडब्ल्यूएएसपी या पीएचपी मैनुअल के समर्थन में है , जो एसक्यूएल इंजेक्शन से बचने और सुरक्षा से बचने के लिए समानता की घोषणा करता है।

इसके बावजूद कि पीएचपी मैनुअल ने उम्र के लिए क्या कहा, *_escape_string द्वारा कोई मतलब नहीं डेटा सुरक्षित है और इसका इरादा कभी नहीं किया गया है स्ट्रिंग के अलावा किसी भी एसक्यूएल भाग के लिए बेकार होने के अलावा, मैन्युअल एस्केपिंग गलत है क्योंकि यह स्वचालित के विपरीत है।

और OWASP इससे भी बदतर बना देता है, उपयोगकर्ता इनपुट से बचने पर बल देता है जो एक बिल्कुल बकवास है: इंजेक्शन संरक्षण के संदर्भ में ऐसा कोई शब्द नहीं होना चाहिए हर चर संभावित खतरनाक है – कोई फर्क नहीं पड़ता स्रोत! या, दूसरे शब्दों में – प्रत्येक चर को एक क्वेरी में ठीक से स्वरूपित किया जाना चाहिए – कोई भी स्रोत नहीं फिर से यह गंतव्य है जो मायने रखता है जब कोई डेवलपर भेड़ को बकरियों से अलग करना शुरू कर देता है (सोच रहा है कि क्या कोई विशेष चर "सुरक्षित" है या नहीं) वह अपने आपदा की दिशा में पहला कदम उठाते हैं। यह भी उल्लेख नहीं है कि यहां तक ​​कि शब्दों का इस्तेमाल प्रविष्टि बिंदु पर भागने वाले थोक को बताता है, बहुत ही जादू उद्धरण की सुविधा के समान – पहले से ही तुच्छ, बहिष्कृत और हटाया गया।

इसलिए, जो भी "भागने" के विपरीत, तैयार बयान वह उपाय है जो वास्तव में एसक्यूएल इंजेक्शन (जब लागू हो) से बचाता है।

यदि आप अभी भी आश्वस्त नहीं हैं, तो मैंने एक कदम-दर-चरण विवरण लिखा है, द हिचहाइकर की गाइड टू एसक्यूएल इंजेक्शन की रोकथाम , जहां मैंने इन सभी मामलों को विस्तार से समझाया और यहां तक ​​कि एक खंड पूरी तरह से खराब व्यवहारों और उनके प्रकटीकरण को समर्पित किया।

पैरामीटर एसक्यूएल प्रश्नों को चलाने के लिए मैं पीडीओ (PHP डेटा ऑब्जेक्ट्स) का उपयोग करने की सलाह देता हूं।

यह केवल एसक्यूएल इंजेक्शन के मुकाबले नहीं बचाता है, यह भी प्रश्नों की गति बढ़ाता है।

और mysql_ , mysqli_ , और pgsql_ फ़ंक्शंस के बजाय पीडीओ का उपयोग करते हुए, आप अपने ऐप को डेटाबेस से कुछ और ही pgsql_ करते हैं, दुर्लभ घटना में आपको डेटाबेस प्रदाता को स्विच करना पड़ता है।

PDO और तैयार प्रश्नों का उपयोग करें

( $conn एक PDO ऑब्जेक्ट है)

 $stmt = $conn->prepare("INSERT INTO tbl VALUES(:id, :name)"); $stmt->bindValue(':id', $id); $stmt->bindValue(':name', $name); $stmt->execute(); 

जैसा कि आप देख सकते हैं, लोगों का सुझाव है कि आप सबसे अधिक तैयार कथनों का इस्तेमाल करते हैं। यह गलत नहीं है, लेकिन जब आपकी क्वेरी केवल प्रति प्रक्रिया एक बार निष्पादित होती है, तो मामूली प्रदर्शन जुर्माना होगा

मुझे इस मुद्दे का सामना करना पड़ रहा था, लेकिन मुझे लगता है कि मैंने इसे बहुत ही परिष्कृत तरीके से हल किया है – जिस तरह से हैकर कोट्स का उपयोग करने से बचने के लिए उपयोग करते हैं मैंने इसका इस्तेमाल अनुकरणित तैयार बयानों के साथ किया। मैं इसका इस्तेमाल सभी प्रकार के एसक्यूएल इंजेक्शन हमलों को रोकने के लिए करता हूं।

मेरा दृष्टिकोण:

  • यदि आप इनपुट को पूर्णांक होने की उम्मीद करते हैं तो सुनिश्चित करें कि यह वास्तव में पूर्णांक है एक चर प्रकार की भाषा में PHP जैसी यह बहुत महत्वपूर्ण है। उदाहरण के लिए आप यह बहुत ही सरल लेकिन शक्तिशाली समाधान का उपयोग कर सकते हैं: sprintf("SELECT 1,2,3 FROM table WHERE 4 = %u", $input);

  • यदि आप पूर्णांक हेक्स से कुछ और की अपेक्षा करते हैं यदि आप इसे हेक्स, आप पूरी तरह से सभी इनपुट से बच जाएगा सी / सी ++ में एक समारोह है mysql_hex_string() , PHP में आप bin2hex() उपयोग कर सकते हैं।

    चिंता न करें कि बचने वाली स्ट्रिंग में इसकी मूल लंबाई का 2x आकार होगा, भले ही आप mysql_real_escape_string उपयोग करते हैं, तो PHP को उसी क्षमता ((2*input_length)+1) आवंटित करना होगा, जो समान है।

  • यह हेक्स पद्धति का उपयोग अक्सर जब आप द्विपदीय डेटा को हस्तांतरित करते हैं, लेकिन मुझे कोई कारण नहीं दिखता कि एसक्यूएल इंजेक्शन हमलों को रोकने के लिए सभी डेटा पर इसका उपयोग क्यों न करें ध्यान दें कि आपको 0x डेटा UNHEX इसके बजाय MySQL फ़ंक्शन UNHEX उपयोग करना होगा।

इसलिए, उदाहरण के लिए, क्वेरी:

 SELECT password FROM users WHERE name = 'root' 

हो जाएगा:

 SELECT password FROM users WHERE name = 0x726f6f74 

या

 SELECT password FROM users WHERE name = UNHEX('726f6f74') 

हेक्स सही एस्केप है इंजेक्ट करने के लिए कोई रास्ता नहीं

UNHEX फ़ंक्शन और 0x उपसर्ग के बीच का अंतर

टिप्पणियों में कुछ चर्चा हुई थी, इसलिए मैं इसे स्पष्ट करना चाहता हूं। ये दोनों दृष्टिकोण बहुत समान हैं, लेकिन वे कुछ मायनों में थोड़ा अलग हैं:

0x उपसर्ग केवल डेटा , जैसे कि चार, varchar, पाठ, ब्लॉक, द्विआधारी आदि के डेटा कॉलम पर इस्तेमाल किया जा सकता है।
साथ ही, इसका उपयोग थोड़ा जटिल है यदि आप रिक्त स्ट्रिंग को सम्मिलित करने वाले हैं। आपको इसे '' साथ पूरी तरह बदलना होगा, या आपको एक त्रुटि मिलेगी

UNHEX () किसी भी कॉलम पर काम करता है; आपको खाली स्ट्रिंग के बारे में चिंता करने की ज़रूरत नहीं है।


हेक्स विधियों को अक्सर हमलों के रूप में उपयोग किया जाता है

ध्यान दें कि इस हेक्स पद्धति का उपयोग अक्सर एक एसक्यूएल इंजेक्शन हमले के रूप में किया जाता है जहां पूर्णांक तारों की तरह होते हैं और केवल mysql_real_escape_string साथ बच जाते हैं। तो आप उद्धरण चिह्नों के उपयोग से बच सकते हैं

उदाहरण के लिए, यदि आप ऐसा कुछ करते हैं:

 "SELECT title FROM article WHERE id = " . mysql_real_escape_string($_GET["id"]) 

एक हमले आपको बहुत आसानी से इंजेक्ट कर सकता है निम्नलिखित स्क्रिप्ट से इंजेक्ट किए गए कोड पर गौर करें:

SELECT … WHERE id = 1 संघ सभी info_schema.tables से तालिका_नाव चुनें

और अब बस तालिका संरचना निकालें:

SELECT … WHERE आईडी = 1 संघ सभी info_schema.column से column_name चुनें जहां तालिका_नाम = 0x61727469636c65

और फिर जो भी डेटा चाहते हैं उसे चुनें क्या यह शांत नहीं है?

लेकिन यदि इंजेक्शन साइट के सांकेतिक शब्दों में बदलनेवाला हेक्स होता है, तो इंजेक्शन संभव नहीं होगा क्योंकि क्वेरी इस प्रकार दिखाई देगी: SELECT ... WHERE id = UNHEX('2d312075...3635')

जरूरी

एसक्यूएल इंजेक्शन को रोकने का सबसे अच्छा तरीका बचने के बजाय तैयार वक्तव्य का उपयोग करना है, क्योंकि स्वीकृत जवाब दर्शाता है।

ऐसी आभा एसक्यूएल और ईज़ीडीबी जैसे पुस्तकालय हैं जो डेवलपर्स को तैयार बयान को आसान उपयोग करने की इजाजत देते हैं। एसक्यूएल इंजेक्शन को रोकने के लिए तैयार बयान बेहतर क्यों हैं इसके बारे में अधिक जानने के लिए, इस mysql_real_escape_string() बाईपास का संदर्भ लें और वर्डप्रेस में हाल ही में तय यूनिकोड एसक्यूएल इंजेक्शन कमजोरियों ।

इंजेक्शन की रोकथाम – mysql_real_escape_string ()

इन हमलों को रोकने के लिए PHP में विशेष रूप से बनाया गया कार्य है आपको केवल एक फंक्शन के कौर का प्रयोग करना है, mysql_real_escape_string

mysql_real_escape_string एक स्ट्रिंग लेता है जो कि एक MySQL क्वेरी में उपयोग किया जा रहा है और सभी एसक्यूएल इंजेक्शन के साथ समान स्ट्रिंग वापस सुरक्षित रूप से भाग निकलने का प्रयास करता है। असल में, यह उन परेशानी उद्धरणों (') को प्रतिस्थापित करेगा जो एक उपयोगकर्ता माइस् SQL-सुरक्षित विकल्प, बच निकलने वाला उद्धरण \' के साथ दर्ज हो सकता है।

नोट: आपको इस फ़ंक्शन का उपयोग करने के लिए डेटाबेस से कनेक्ट होना चाहिए!

// MySQL से कनेक्ट करें

 $name_bad = "' OR 1'"; $name_bad = mysql_real_escape_string($name_bad); $query_bad = "SELECT * FROM customers WHERE username = '$name_bad'"; echo "Escaped Bad Injection: <br />" . $query_bad . "<br />"; $name_evil = "'; DELETE FROM customers WHERE 1 or username = '"; $name_evil = mysql_real_escape_string($name_evil); $query_evil = "SELECT * FROM customers WHERE username = '$name_evil'"; echo "Escaped Evil Injection: <br />" . $query_evil; 

आप MySQL – SQL इंजेक्शन प्रिवेंशन में अधिक विवरण पा सकते हैं।

सुरक्षा चेतावनी : यह उत्तर सुरक्षा सर्वोत्तम प्रथाओं के अनुरूप नहीं है एसक्यूएल इंजेक्शन को रोकने के लिए एस्केपिंग अपर्याप्त है , बजाय तैयार कथनों का उपयोग करें। अपने जोखिम पर नीचे दी गई रणनीति का उपयोग करें (इसके अलावा, mysql_real_escape_string() को PHP 7 में हटा दिया गया था।)

आप इस तरह से बुनियादी कुछ कर सकते हैं:

 $safe_variable = mysql_real_escape_string($_POST["user-input"]); mysql_query("INSERT INTO table (column) VALUES ('" . $safe_variable . "')"); 

यह हर समस्या का समाधान नहीं करेगा, लेकिन यह एक बहुत अच्छा कदम पत्थर है। मैंने स्पष्ट वस्तुओं को छोड़ दिया जैसे कि चर का अस्तित्व, प्रारूप (संख्या, पत्र, आदि) की जाँच करना।

जो भी आप उपयोग करते हैं, वह सुनिश्चित करें कि आप magic_quotes कि आपके इनपुट को magic_quotes या किसी अन्य अच्छी तरह से कचरे से नहीं मिला है, और यदि आवश्यक हो, तो उसे stripslashesstripslashes माध्यम से चलाएं या जो कुछ भी इसे stripslashes

Parameterized query AND input validation is the way to go. There is many scenarios under which SQL injection may occur, even though mysql_real_escape_string() has been used.

Those examples are vulnerable to SQL injection:

 $offset = isset($_GET['o']) ? $_GET['o'] : 0; $offset = mysql_real_escape_string($offset); RunQuery("SELECT userid, username FROM sql_injection_test LIMIT $offset, 10"); 

या

 $order = isset($_GET['o']) ? $_GET['o'] : 'userid'; $order = mysql_real_escape_string($order); RunQuery("SELECT userid, username FROM sql_injection_test ORDER BY `$order`"); 

In both cases, you can't use ' to protect the encapsulation.

Source : The Unexpected SQL Injection (When Escaping Is Not Enough)

In my opinion, the best way to generally prevent SQL injection in your PHP application (or any web application, for that matter) is to think about your application's architecture. If the only way to protect against SQL injection is to remember to use a special method or function that does The Right Thing every time you talk to the database, you are doing it wrong. That way, it's just a matter of time until you forget to correctly format your query at some point in your code.

Adopting the MVC pattern and a framework like CakePHP or CodeIgniter is probably the right way to go: Common tasks like creating secure database queries have been solved and centrally implemented in such frameworks. They help you to organize your web application in a sensible way and make you think more about loading and saving objects than about securely constructing single SQL queries.

There are many ways of preventing SQL injections and other SQL hacks. You can easily find it on the Internet (Google Search). Of course PDO is one of the good solution. But I would like to suggest you some good links prevention from SQL Injection.

What is SQL injection and how to prevent

PHP manual for SQL injection

Microsoft explanation of SQL injection and prevention in PHP

and some other like Preventing SQL injection with MySQL and PHP

Now, why you do you need to prevent your query from SQL injection?

I would like to let you know: Why do we try for preventing SQL injection with a short example below:

Query for login authentication match:

 $query="select * from users where email='".$_POST['email']."' and password='".$_POST['password']."' "; 

Now, if someone (a hacker) puts

 $_POST['email']= admin@emali.com' OR '1=1 

and password anything….

The query will be parsed in the system only upto:

 $query="select * from users where email='admin@emali.com' OR '1=1'; 

The other part will be discarded. So, what will happen? A non-authorized user (hacker) will be able to login as admin without having his password. Now, he can do anything what admin/email person can do. See, it's very dangerous if SQL injection is not prevented.

I favor stored procedures ( MySQL has had stored procedures support since 5.0 ) from a security point of view – the advantages are –

  1. Most databases (including MySQL ) enable user access to be restricted to executing stored procedures. The fine grained security access control is useful to prevent escalation of privileges attacks. This prevents compromised applications from being able to run SQL directly against the database.
  2. They abstract the raw SQL query from the application so less information of the database structure is available to the application. This makes it harder for people to understand the underlying structure of the database and design suitable attacks.
  3. They accept only parameters, so the advantages of parameterized queries are there. Of course – IMO you still need to sanitize your input – especially if you are using dynamic SQL inside the stored procedure.

The disadvantages are –

  1. They (stored procedures) are tough to maintain and tend to multiply very quickly. This makes managing them an issue.
  2. They are not very suitable for dynamic queries – if they are built to accept dynamic code as parameters then a lot of the advantages are negated.

I think if someone wants to use PHP and MySQL or some other dataBase server:

  1. Think about learning PDO (PHP Data Objects) – it is a database access layer providing a uniform method of access to multiple databases.
  2. Think about learning MySQLi
  3. Use native PHP functions like: strip_tags , mysql_real_escape_string or if variable numeric, just (int)$foo . Read more about type of variables in PHP here . If you're using libraries such as PDO or MySQLi, always use PDO::quote() and mysqli_real_escape_string() .

Libraries examples:

—- PDO

—– No placeholders – ripe for SQL injection! It's bad

 $request = $pdoConnection->("INSERT INTO parents (name, addr, city) values ($name, $addr, $city)"); 

—– Unnamed placeholders

 $request = $pdoConnection->("INSERT INTO parents (name, addr, city) values (?, ?, ?); 

—– Named placeholders

 $request = $pdoConnection->("INSERT INTO parents (name, addr, city) value (:name, :addr, :city)"); 

MySQLi

 $request = $mysqliConnection->prepare(' SELECT * FROM trainers WHERE name = ? AND email = ? AND last_login > ?'); $query->bind_param('first_param', 'second_param', $mail, time() - 3600); $query->execute(); 

PS :

PDO wins this battle with ease. With support for twelve different database drivers and named parameters, we can ignore the small performance loss, and get used to its API. From a security standpoint, both of them are safe as long as the developer uses them the way they are supposed to be used

But while both PDO and MySQLi are quite fast, MySQLi performs insignificantly faster in benchmarks – ~2.5% for non-prepared statements, and ~6.5% for prepared ones.

And please test every query to your database – it's a better way to prevent injection.

Type cast if possible your parameters. But it's only working on simple types like int, bool and float.

 $unsafe_variable = $_POST['user_id']; $safe_variable = (int)$unsafe_variable ; mysql_query("INSERT INTO table (column) VALUES ('" . $safe_variable . "')"); 

If you want to take advantage of cache engines, like Redis or Memcached , maybe DALMP could be a choice. It uses pure MySQLi . Check this: DALMP Database Abstraction Layer for MySQL using PHP.

Also you can 'prepare' your arguments before preparing your query so that you can build dynamic queries and at the end have a full prepared statements query. DALMP Database Abstraction Layer for MySQL using PHP.

Using this PHP function mysql_escape_string() you can get a good prevention in a fast way.

उदाहरण के लिए:

 SELECT * FROM users WHERE name = '".mysql_escape_string($name_from_html_form)."' 

mysql_escape_string — Escapes a string for use in a mysql_query

For more prevention you can add at the end …

 wHERE 1=1 or LIMIT 1 

Finally you get:

 SELECT * FROM users WHERE name = '".mysql_escape_string($name_from_html_form)."' LIMIT 1 

For those unsure of how to use PDO (coming from the mysql_ functions), I made a very, very simple PDO wrapper that is a single file. It exists to show how easy it is to do all the common things applications need done. Works with PostgreSQL, MySQL, and SQLite.

Basically, read it while you read the manual to see how to put the PDO functions to use in real life to make it simple to store and retrieve values in the format you want.

I want a single column

 $count = DB::column('SELECT COUNT(*) FROM `user`); 

I want an array(key => value) results (ie for making a selectbox)

 $pairs = DB::pairs('SELECT `id`, `username` FROM `user`); 

I want a single row result

 $user = DB::row('SELECT * FROM `user` WHERE `id` = ?', array($user_id)); 

I want an array of results

 $banned_users = DB::fetch('SELECT * FROM `user` WHERE `banned` = ?', array(TRUE)); 

A few guidelines for escaping special characters in SQL statements.

Don't use MySQL , this extension is deprecated, use MySQLi or PDO .

MySQLi

For manually escaping special characters in a string you can use the mysqli_real_escape_string function. The function will not work properly unless the correct character set is set with mysqli_set_charset .

Example:

 $mysqli = new mysqli( 'host', 'user', 'password', 'database' ); $mysqli->set_charset( 'charset'); $string = $mysqli->real_escape_string( $string ); $mysqli->query( "INSERT INTO table (column) VALUES ('$string')" ); 

For automatic escaping of values with prepared statements, use mysqli_prepare , and mysqli_stmt_bind_param where types for the corresponding bind variables must be provided for an appropriate conversion:

Example:

 $stmt = $mysqli->prepare( "INSERT INTO table ( column1, column2 ) VALUES (?,?)" ); $stmt->bind_param( "is", $integer, $string ); $stmt->execute(); 

No matter if you use prepared statements or mysqli_real_escape_string, you always have to know the type of input data you're working with.

So if you use a prepared statement, you must specify the types of the variables for mysqli_stmt_bind_param function.

And use of mysqli_real_escape_string is for, as the name says, escaping special characters in a string, so it will not make integers safe. The purpose of this function is to prevent breaking the strings in SQL statements, and the damage to the database that it could cause. mysqli_real_escape_string is a useful function when used properly, especially when combined with sprintf.

Example:

 $string = "x' OR name LIKE '%John%"; $integer = '5 OR id != 0'; $query = sprintf( "SELECT id, email, pass, name FROM members WHERE email ='%s' AND id = %d", $mysqli->real_escape_string( $string ), $integer ); echo $query; // SELECT id, email, pass, name FROM members WHERE email ='x\' OR name LIKE \'%John%' AND id = 5 $integer = '99999999999999999999'; $query = sprintf( "SELECT id, email, pass, name FROM members WHERE email ='%s' AND id = %d", $mysqli->real_escape_string( $string ), $integer ); echo $query; // SELECT id, email, pass, name FROM members WHERE email ='x\' OR name LIKE \'%John%' AND id = 2147483647 

I use three different ways to prevent my web application from being vulnerable to SQL injection.

  1. Use of mysql_real_escape_string() , which is a pre-defined function in PHP , and this code add backslashes to the following characters: \x00 , \n , \r , \ , ' , " and \x1a . Pass the input values as parameters to minimize the chance of SQL injection.
  2. The most advanced way is to use PDOs.

I hope this will help you.

Consider the following query:

$iId = mysql_real_escape_string("1 OR 1=1"); $sSql = "SELECT * FROM table WHERE id = $iId";

mysql_real_escape_string() will not protect here. If you use single quotes (' ') around your variables inside your query is what protects you against this. Here is an solution below for this:

$iId = (int) mysql_real_escape_string("1 OR 1=1"); $sSql = "SELECT * FROM table WHERE id = $iId";

This question has some good answers about this.

I suggest, using PDO is the best option.

Edit:

mysql_real_escape_string() is deprecated as of PHP 5.5.0. Use either mysqli or PDO.

An alternative to mysql_real_escape_string() is

 string mysqli_real_escape_string ( mysqli $link , string $escapestr ) 

Example:

 $iId = $mysqli->real_escape_string("1 OR 1=1"); $mysqli->query("SELECT * FROM table WHERE id = $iId"); 

The simple alternative to this problem could be solved by granting appropriate permissions in the database itself. For example: if you are using mysql database. then enter into the database through terminal or the ui provided and just follow this command:

  GRANT SELECT, INSERT, DELETE ON database TO username@'localhost' IDENTIFIED BY 'password'; 

This will restrict the user to only get confined with the specified query's only. Remove the delete permission and so the data would never get deleted from the query fired from the php page. The second thing to do is to flush the privileges so that the mysql refreshes the permissions and updates.

 FLUSH PRIVILEGES; 

more information about flush .

To see the current privileges for the user fire the following query.

 select * from mysql.user where User='username'; 

Learn more about GRANT .

Regarding many useful answers, I hope to add some values to this thread. SQL injection is an attack that can be done through user inputs (Inputs that filled by user and then used inside queries), The SQL injection patterns are correct query syntax while we can call it: bad queries for bad reasons, we assume that there might be bad person that try to get secret information (bypassing access control) that affect the three principles of security (Confidentiality, Integrity, Availability).

Now, our point is to prevent security threats such as SQL injection attacks, the question asking (How to prevent SQL injection attack using PHP), be more realistic, data filtering or clearing input data is the case when using user-input data inside such query, using PHP or any other programming language is not the case, or as recommended by more people to use modern technology such as prepared statement or any other tools that currently supporting SQL injection prevention, consider that these tools not available anymore? How you secure your application?

My approach against SQL injection is: clearing user-input data before sending it to the database (before using it inside any query).

Data filtering for (Converting unsafe data to safe data) Consider that PDO and MySQLi not available, how can you secure your application? Do you force me to use them? What about other languages other than PHP? I prefer to provide general ideas as it can be used for wider border not just for specific language.

  1. SQL user (limiting user privilege): most common SQL operations are (SELECT, UPDATE, INSERT), then, why giving UPDATE privilege to a user that not require it? For example login, and search pages are only using SELECT, then, why using DB users in these pages with high privileges? RULE: do not create one database user for all privileges, for all SQL operations, you can create your scheme like (deluser, selectuser, updateuser) as usernames for easy usage.

see Principle of least privilege

  1. Data filtering: before building any query user input should be validated and filtered, for programmers, it's important to define some properties for each user-input variables: data type, data pattern, and data length . a field that is a number between (x and y) must be exactly validated using exact rule, for a field that is a string (text): pattern is the case, for example, username must contain only some characters lets say [a-zA-Z0-9_-.] the length varies between (x and n) where x and n (integers, x <=n ). Rule: creating exact filters and validation rules are best practice for me.

  2. Use other tools: Here, I will also agree with you that prepared statement (parametrized query) and Stored procedures, the disadvantages here is these ways requires advanced skills which do not exist for most users, the basic idea here is to distinguish between SQL query and the data that being used inside, both approaches can be used even with unsafe data, because the user-input data here not add anything to the original query such as (any or x=x). For more information, please read OWASP SQL Injection Prevention Cheat Sheet .

Now, if you are an advanced user, start using this defense as you like, but, for beginners, if they can't quickly implement stored procedure and prepared the statement, it's better to filter input data as much they can.

Finally, let's consider that user sends this text below instead of entering his username:

 [1] UNION SELECT IF(SUBSTRING(Password,1,1)='2',BENCHMARK(100000,SHA1(1)),0) User,Password FROM mysql.user WHERE User = 'root' 

This input can be checked early without any prepared statement and stored procedures, but to be on safe side, using them starts after user-data filtering and validation.

The last point is detecting unexpected behavior which requires more effort and complexity; it's not recommended for normal web applications. Unexpected behavior in above user input is SELECT, UNION, IF, SUBSTRING, BENCHMARK, SHA, root once these words detected, you can avoid the input.

UPDATE1:

A user commented that this post is useless, OK! Here is what OWASP.ORG provided:

Primary defenses:

Option #1: Use of Prepared Statements (Parameterized Queries)
Option #2: Use of Stored Procedures
Option #3: Escaping all User Supplied Input

Additional defenses:

Also Enforce: Least Privilege
Also Perform: White List Input Validation

As you may know, claiming on an article should be supported by valid argument, at least one reference! Otherwise, it's considered as an attack and bad claim!

Update2:

From the PHP manual, PHP: Prepared Statements – Manual :

Escaping and SQL injection

Bound variables will be escaped automatically by the server. The server inserts their escaped values at the appropriate places into the statement template before execution. A hint must be provided to the server for the type of bound variable, to create an appropriate conversion. See the mysqli_stmt_bind_param() function for more information.

The automatic escaping of values within the server is sometimes considered a security feature to prevent SQL injection. The same degree of security can be achieved with non-prepared statements if input values are escaped correctly.

Update3:

I created test cases for knowing how PDO and MySQLi send the query to MySQL server when using prepared statement:

PDO:

 $user = "''1''"; //Malicious keyword $sql = 'SELECT * FROM awa_user WHERE userame =:username'; $sth = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY)); $sth->execute(array(':username' => $user)); 

Query Log:

  189 Query SELECT * FROM awa_user WHERE userame ='\'\'1\'\'' 189 Quit 

MySQLi:

 $stmt = $mysqli->prepare("SELECT * FROM awa_user WHERE username =?")) { $stmt->bind_param("s", $user); $user = "''1''"; $stmt->execute(); 

Query Log:

  188 Prepare SELECT * FROM awa_user WHERE username =? 188 Execute SELECT * FROM awa_user WHERE username ='\'\'1\'\'' 188 Quit 

It's clear that a prepared statement is also escaping the data, nothing else.

As also mentioned in above statement The automatic escaping of values within the server is sometimes considered a security feature to prevent SQL injection. The same degree of security can be achieved with non-prepared statements, if input values are escaped correctly , therefore, this proves that data validation such as intval() is a good idea for integer values before sending any query, in addition, preventing malicious user data before sending the query is correct and valid approach .

Please see this question for more detail: PDO sends raw query to MySQL while Mysqli sends prepared query, both produce the same result

References:

  1. SQL Injection Cheat Sheet
  2. SQL Injection
  3. Information security
  4. Security Principles
  5. Data validation

A simple way would be to use a PHP framework like CodeIgniter or Laravel which have in-built features like filtering and active-record, so that you don't have to worry about these nuances.

There are so many answers for PHP and MySQL , but here is code for PHP and Oracle for preventing SQL injection as well as regular use of oci8 drivers:

 $conn = oci_connect($username, $password, $connection_string); $stmt = oci_parse($conn, 'UPDATE table SET field = :xx WHERE ID = 123'); oci_bind_by_name($stmt, ':xx', $fieldval); oci_execute($stmt); 

Warning : the approach described in this answer only applies for very specific scenarios and isn't secure since SQL injection attacks do not only rely on being able to inject X=Y .

If the attackers are trying to hack with the form via PHP's $_GET variable or with the URL's query string, you would be able to catch them if they're not secure.

 RewriteCond %{QUERY_STRING} ([0-9]+)=([0-9]+) RewriteRule ^(.*) ^/track.php 

Because 1=1 , 2=2 , 1=2 , 2=1 , 1+1=2 , etc… are the common questions to an SQL database of an attacker. Maybe also it's used by many hacking applications.

But you must be careful, that you must not rewrite a safe query from your site. The code above is giving you a tip, to rewrite or redirect (it depends on you) that hacking-specific dynamic query string into a page that will store the attacker's IP address , or EVEN THEIR COOKIES, history, browser, or any other sensitive information, so you can deal with them later by banning their account or contacting authorities.

Using PDO and MYSQLi is a good practice to prevent SQL injections, but if you really want to work with MySQL functions and queries, it would be better to use

mysql_real_escape_string

 $unsafe_variable = mysql_real_escape_string($_POST['user_input']); 

There are more ability to prevent this: like identify – if the input is a string, number, char or array, there are so many inbuilt functions to detect this. Also it would be better to use these functions to check input data.

is_string

 $unsafe_variable = (is_string($_POST['user_input']) ? $_POST['user_input'] : ''); 

is_numeric

 $unsafe_variable = (is_numeric($_POST['user_input']) ? $_POST['user_input'] : ''); 

And it is so much better to use those functions to check input data with mysql_real_escape_string .

A good idea is to use an 'object-relational mapper' like Idiorm :

 $user = ORM::for_table('user') ->where_equal('username', 'j4mie') ->find_one(); $user->first_name = 'Jamie'; $user->save(); $tweets = ORM::for_table('tweet') ->select('tweet.*') ->join('user', array( 'user.id', '=', 'tweet.user_id' )) ->where_equal('user.username', 'j4mie') ->find_many(); foreach ($tweets as $tweet) { echo $tweet->text; } 

It not only saves you from SQL injections, but from syntax errors too! Also Supports collections of models with method chaining to filter or apply actions to multiple results at once and mutliple connection.

I've written this little function several years ago:

 function sqlvprintf($query, $args) { global $DB_LINK; $ctr = 0; ensureConnection(); // Connect to database if not connected already. $values = array(); foreach ($args as $value) { if (is_string($value)) { $value = "'" . mysqli_real_escape_string($DB_LINK, $value) . "'"; } else if (is_null($value)) { $value = 'NULL'; } else if (!is_int($value) && !is_float($value)) { die('Only numeric, string, array and NULL arguments allowed in a query. Argument '.($ctr+1).' is not a basic type, it\'s type is '. gettype($value). '.'); } $values[] = $value; $ctr++; } $query = preg_replace_callback( '/{(\\d+)}/', function($match) use ($values) { if (isset($values[$match[1]])) { return $values[$match[1]]; } else { return $match[0]; } }, $query ); return $query; } function runEscapedQuery($preparedQuery /*, ...*/) { $params = array_slice(func_get_args(), 1); $results = runQuery(sqlvprintf($preparedQuery, $params)); // Run query and fetch results. return $results; } 

This allows running statements in an one-liner C#-ish String.Format like:

 runEscapedQuery("INSERT INTO Whatever (id, foo, bar) VALUES ({0}, {1}, {2})", $numericVar, $stringVar1, $stringVar2); 

It escapes considering the variable type. If you try to parameterize table, column names, it would fail as it puts every string in quotes which is invalid syntax.

SECURITY UPDATE: The previous str_replace version allowed injections by adding {#} tokens into user data. This preg_replace_callback version doesn't cause problems if the replacement contains these tokens.