और सबसे कम मदद आपके द्वारा विकसित फ़ंक्शन से होगी। PHP: \"उद्धरण\"। MySQL क्वेरीज़ लिखना, स्लैश करना, कोट्स से बचना, कोड में खोजना

उद्धरण स्ट्रिंग (11)

मैं प्रश्न लिखने का सबसे अच्छा तरीका ढूंढने का प्रयास कर रहा हूं। मैं सुसंगत रहने के महत्व को भी समझता हूं। अब तक मैं बिना किसी वास्तविक विचार के सिंगल कोट्स, डबल कोट्स और बैकटिक्स का बेतरतीब ढंग से उपयोग कर रहा हूं।

$query = "तालिका में सम्मिलित करें (आईडी, col1, col2) मान (शून्य, val1, val2)";

साथ ही, उपरोक्त उदाहरण में, इस बात पर विचार करें कि "तालिका," "col[n]," और "val[n]" चर हो सकते हैं।

इसके लिए मानक क्या है? आप क्या कर रहे हो?

मैं लगभग 20 मिनट से इसी तरह के प्रश्नों के उत्तर पढ़ रहा हूं, लेकिन इस प्रश्न का कोई निश्चित उत्तर नहीं दिख रहा है।

जवाब

अब मान लीजिए कि आप MySQL क्वेरी में डायरेक्ट पोस्ट वेरिएबल का उपयोग कर रहे हैं तो इसे इस तरह उपयोग करें:

$query = "तालिका में सम्मिलित करें (`id`, `name`, `email`) मान (" ".$_POST["id"]।" " " ".$_POST["name"]।" ", " ".$_POST["ईमेल"].." ")";

MySQL में PHP वेरिएबल का उपयोग करने के लिए यह सबसे अच्छा अभ्यास है।

मुख्य रूप से मैसकल में, इस प्रकार के पहचानकर्ताओं का उपयोग ` , " , " और () प्रश्नों में किया जाता है।

    " या " एक स्ट्रिंग को मान "01/26/2014 00:00:00" या "01/26/2014 00:00:00" के रूप में शामिल करने के लिए उपयोग करें। इस पहचानकर्ता का उपयोग केवल "01/26/2014 00:00:00" स्ट्रिंग फ़ंक्शन के लिए किया जाता है, जैसे कि now() या sum ,max ।

    `एक टेबल या टेबल तालिका को शामिल करने के लिए उपयोग करें, उदाहरण के लिए टेबल_नाम से कॉलम_नाम चुनें जहां आईडी = "2"

    () का उपयोग केवल किसी क्वेरी के कुछ हिस्सों को संलग्न करने के लिए किया जाता है, उदाहरण के लिए टेबल_नाम से कॉलम_नाम चुनें जहां (आईडी = "2" और लिंग = "पुरुष") या नाम = "राकेश।

सभी (अच्छी तरह से समझाए गए) उत्तरों के अलावा, नीचे किसी का भी उल्लेख नहीं किया गया था और मैं अक्सर इस प्रश्नोत्तर पर आता हूं।

संक्षेप में; MySQL सोचता है कि आप गणित करना चाहते हैंअपने स्वयं के टेबल/कॉलम पर और "ईमेल" जैसे हाइफ़न को ई-मेल के रूप में समझें।

जिम्मेदारी से इनकार.इसलिए मैंने सोचा कि मैं इसे उन लोगों के लिए "FYI" उत्तर के रूप में जोड़ूंगा जो डेटाबेस के साथ काम करने में पूरी तरह से नए हैं, और जो पहले से वर्णित तकनीकी शब्दों को नहीं समझ सकते हैं।

(आपके प्रश्न की SQL प्रकृति के संबंध में ऊपर अच्छे उत्तर हैं, लेकिन यदि आप PHP में नए हैं तो यह भी प्रासंगिक हो सकता है।)

यह ध्यान रखना महत्वपूर्ण हो सकता है कि PHP सिंगल और डबल कोट्स को अलग-अलग तरीके से व्यवहार करता है...

एकल-उद्धृत स्ट्रिंग्स "शाब्दिक" हैं और काफी संख्या में WYSIWYG स्ट्रिंग्स हैं। संभावित परिवर्तनीय प्रतिस्थापन के लिए PHP द्वारा दोहरे-उद्धृत स्ट्रिंग की व्याख्या की जाती है (PHP में बैकरेफरेंस वास्तव में स्ट्रिंग नहीं हैं, वे शेल में कमांड निष्पादित करते हैं और परिणाम लौटाते हैं)।

$फू = "बार"; प्रतिध्वनि "वहाँ एक $foo है"; // एक $foo प्रतिध्वनि है "वहाँ एक $foo है"; // एक बार इको है `ls -l`; // ... एक निर्देशिका सूची

यदि कॉलम तालिकाएँ और मान चर हैं, तो दो तरीके हैं:

दोहरे उद्धरण चिह्नों के साथ "" पूरी क्वेरी है:

$query = "$table_name (id, $col1, $col2) मान (शून्य, "$val1", "$val2") में डालें";

$query = "INSERT INTO ".$table_name." (id, ".$col1.", ".$col2.") मान (NULL, ""।$val1.", ""।$val2."" ) ";

एकल उद्धरण चिह्नों के साथ "" :

$query = "INSERT INTO ".$table_name." (id, ".$col1.", ".$col2.") मान (NULL, ".$val1.", ".$val2.");

जब कॉलम/वैल्यू नाम MySQL आरक्षित कीवर्ड के समान हो तो बैकटिक्स `` का उपयोग करें।

टिप्पणी।यदि आप तालिका नाम के साथ कॉलम नाम निर्दिष्ट करते हैं, तो इस तरह बैकटिक्स का उपयोग करें:

`टेबल_नाम` . `कॉलम_नाम`<- Примечание: исключить. из задних клещей.

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

स्ट्रिंग मानों के लिए सिंगल कोट्स का उपयोग किया जाना चाहिए, जैसे VALUES() सूची में। स्ट्रिंग मानों के लिए MySQL द्वारा डबल कोट्स का भी समर्थन किया जाता है, लेकिन सिंगल कोट्स अन्य RDBMSs द्वारा अधिक व्यापक रूप से स्वीकार किए जाते हैं, इसलिए डबल कोट्स के बजाय सिंगल कोट्स का उपयोग करना एक अच्छा विचार है।

MySQL यह भी अपेक्षा करता है कि DATE और DATETIME शाब्दिक मान स्ट्रिंग के रूप में एकल-उद्धृत हों, जैसे "2001-01-01 00:00:00"। अधिक जानकारी के लिए, दिनांक और समय साहित्य दस्तावेज़ देखें, विशेष रूप से हाइफ़न का उपयोग करने के विकल्प - दिनांक स्ट्रिंग में खंड विभाजक के रूप में।

इसलिए आपके उदाहरण का उपयोग करते हुए, मैं PHP स्ट्रिंग को डबल कास्ट करूंगा और "val1", "val2" मानों के लिए सिंगल कोट्स का उपयोग करूंगा। NULL एक MySQL कीवर्ड है और एक गैर-मूल्य है और इसलिए इसका उपयोग नहीं किया जाता है।

इनमें से कोई भी तालिका या स्तंभ पहचानकर्ता आरक्षित शब्द नहीं है या ऐसे वर्णों का उपयोग नहीं करता है जिन्हें उद्धृत करने की आवश्यकता है, लेकिन फिर भी मैंने उन्हें पीछे की ओर उद्धृत किया है (उस पर बाद में और अधिक...)।

RDBMS-संबंधित फ़ंक्शंस (जैसे कि MySQL में NOW()) को उद्धृत नहीं किया जाना चाहिए, हालांकि उनके तर्क समान नियमों या पहले से उल्लिखित नियमों को उद्धृत करने के अधीन हैं।

बैकटिक(`) तालिका और कॉलम ┬──── ┬──┬───────┐ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ $query = " `तालिका` में सम्मिलित करें (`id`, `col1`, `col2`, `date`, `updated`) मान (शून्य, "val1", "val2", "2001-01-01", अभी())"; गैर-उद्धृत कीवर्ड ─────┴┴┴┘ │ │ │ │ │ │ │││││ एकल-उद्धृत (") स्ट्रिंग्स ──────────┴─ ───┴── एकल-उद्धृत (") दिनांक ───┴── गैर-उद्धृत फ़ंक्शन ──┴┴┴┴┘

परिवर्तनीय प्रक्षेप

वेरिएबल्स के लिए उद्धरण पैटर्न नहीं बदलते हैं, हालांकि यदि आप वेरिएबल्स को सीधे एक स्ट्रिंग में इंटरपोल करना चाहते हैं, तो इसे PHP में डबल उद्धृत किया जाना चाहिए। बस यह सुनिश्चित करें कि आप SQL में उपयोग के लिए वेरिएबल्स से ठीक से बचें। (ऐसी एपीआई का उपयोग करने की अनुशंसा की जाती है जो SQL इंजेक्शन के खिलाफ बचाव के रूप में तैयार कथनों का समर्थन करती है।)

// कुछ वैरिएबल प्रतिस्थापनों के साथ भी यही बात है // यहां, एक वैरिएबल तालिका का नाम $table बैकटिक-उद्धृत है, और VALUES सूची में चर // एकल-उद्धृत हैं $query = "INSERT INTO `$टेबल`(`id`, `col1`, `col2`, `date`) मान (शून्य, "$val1", "$val2", "$तारीख")";

तैयार किये गये वक्तव्य

तैयार बयानों के साथ काम करते समय, यह निर्धारित करने के लिए दस्तावेज़ीकरण से परामर्श लें कि क्या बयान भरने वालों को शामिल किया जाना चाहिए। PHP, PDO और MySQLi में उपलब्ध सबसे लोकप्रिय API शामिल हैं अनधिकृतप्लेसहोल्डर, अन्य भाषाओं में अधिकांश तैयार निर्देश एपीआई की तरह:

// नामित पैरामीटर के साथ पीडीओ उदाहरण, गैर-उद्धृत $query = "तालिका में डालें (आईडी', कॉल1, कॉल2, तारीख) मान (:आईडी, कॉल1, कॉल2, तारीख)" ; // MySQLi उदाहरण के साथ? पैरामीटर, गैर-उद्धृत $query = "तालिका में सम्मिलित करें (id, col1, col2, date) मान (?, ?, ?, ?)";

प्रतीक जो पहचानकर्ताओं में पिछला संदर्भ लौटाते हैं:

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

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

विपरीत अनुमानों के बारे में अधिक जानने के लिए इस उत्तर को देखें।

अब डबल कोट्स और सिंगल कोट्स के बारे में (माइकल ने पहले ही इसका उल्लेख किया है)।

लेकिन मान को परिभाषित करने के लिए, आपको सिंगल या डबल कोट्स का उपयोग करना होगा। आइए एक और उदाहरण देखें.

`टेबलनाम` (`आईडी, `शीर्षक`) मानों में सम्मिलित करें (शून्य, शीर्षक 1);

यहां मैं जानबूझकर शीर्षक1 को उद्धरण चिह्नों में लपेटना भूल गया हूं। सर्वर अब शीर्षक1 को कॉलम नाम (यानी पहचानकर्ता) के रूप में स्वीकार करेगा। इसलिए, यह इंगित करने के लिए कि यह एक मान है, आपको दोहरे या एकल उद्धरण चिह्नों का उपयोग करना होगा।

`टेबलनाम` (`आईडी, `शीर्षक`) मानों में सम्मिलित करें (शून्य, "शीर्षक1");

अब, PHP के साथ मिलकर, डबल कोट्स और सिंगल कोट्स क्वेरी लिखना बहुत आसान बनाते हैं। आइए आपके प्रश्न में क्वेरी के संशोधित संस्करण को देखें।

$query = "'तालिका' में सम्मिलित करें (`id`, `col1`, `col2`) मान (शून्य, "$val1", "$val2"");

अब, PHP में डबल कोट्स का उपयोग करके, आप वेरिएबल्स $val1 और $val2 को उनके मानों का उपयोग कराएंगे, इस प्रकार एक वैध क्वेरी बनाएंगे। पसंद

$val1 = "मेरा मूल्य 1"; $val2 = "मेरा मूल्य 2"; $query = "'तालिका' में सम्मिलित करें (`id`, `col1`, `col2`) मान (शून्य, "$val1", "$val2"");

`तालिका` में सम्मिलित करें (`id`, `col1`, `col2`) मान (शून्य, "मेरा मान 1", "मेरा मान 2")

यहां कई उपयोगी उत्तर थे, जिनका समापन आम तौर पर दो बिंदुओं पर होता है।

  1. बैकटिक्स (`) का उपयोग पहचानकर्ता नामों के आसपास किया जाता है।
  2. सिंगल कोट्स (") का उपयोग मूल्यों के आसपास किया जाता है।

और जैसा @माइकल बर्कोव्स्की ने कहा

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

एक ऐसा मामला है जहां पहचानकर्ता नहीं हो सकता है आरक्षित कीवर्डया शामिल हैं रिक्त स्थान वर्णया सीमित सेट के बाहर के पात्रलेकिन निश्चित रूप से उनके आसपास बैकलिंक्स की आवश्यकता होती है।

123E10 एक वैध पहचानकर्ता नाम है, लेकिन एक वैध पूर्णांक शाब्दिक भी है।

[विस्तार से बताए बिना कि आपको इस तरह का आईडी नाम कैसे मिलेगा] मान लीजिए कि मैं 123456e6 नामक एक अस्थायी तालिका बनाना चाहता हूं।

बैकटिक्स पर कोई त्रुटि नहीं.

डीबी > अस्थायी तालिका बनाएं `123456e6` (`आईडी` चार (8)); क्वेरी ठीक है, 0 पंक्तियाँ प्रभावित (0.03 सेकंड)

यदि आप कॉलबैक का उपयोग नहीं करते हैं तो त्रुटि होगी।

DB > अस्थायी तालिका बनाएं 123451e6 (`id` char (8)); त्रुटि 1064 (42000): आपके SQL सिंटैक्स में कोई त्रुटि है; लाइन 1 पर "123451e6 (`आईडी` चार (8))" के पास उपयोग करने के लिए सही सिंटैक्स के लिए अपने मारियाडीबी सर्वर संस्करण से संबंधित मैनुअल की जांच करें।

हालाँकि, 123451a6 एक अच्छा आईडी नाम है (बैकटिक्स के बिना)।

डीबी > अस्थायी तालिका बनाएं 123451ए6 (`आईडी` चार (8)); क्वेरी ठीक है, 0 पंक्तियाँ प्रभावित (0.03 सेकंड)

ऐसा पूरी तरह से इसलिए है क्योंकि 1234156e6 भी एक घातीय संख्या है।

स्ट्रिंग मानों के लिए सिंगल कोट्स का उपयोग किया जाना चाहिए, जैसे VALUES() सूची में।

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

PHP और MySQL के साथ संयुक्त होने पर, डबल कोट्स और सिंगल कोट्स क्वेरी लिखने के समय को बहुत सरल बना देते हैं।

MySQL में दो प्रकार के उद्धरण हैं:

  1. "स्ट्रिंग शाब्दिक शामिल करने के लिए
  2. `तालिका और स्तंभ नाम जैसे पहचानकर्ताओं को शामिल करने के लिए

और फिर "यह एक विशेष मामला है। इसका उपयोग किया जा सकता है।" एकसर्वर के sql_mode के आधार पर एक समय में उपरोक्त लक्ष्यों में से:

  1. गलती करना"वर्ण" का उपयोग स्ट्रिंग अक्षर को घोंसला बनाने के लिए किया जा सकता है "
  2. ANSI_QUOTES मोड में "प्रतीक का उपयोग पहचानकर्ताओं को शामिल करने के लिए किया जा सकता है, ANSI_QUOTES

निम्न क्वेरी SQL मोड के आधार पर भिन्न परिणाम (या त्रुटियाँ) उत्पन्न करेगी:

तालिका से "कॉलम" चुनें जहां foo = "बार"

ANSI_QUOTES अक्षम

क्वेरी स्ट्रिंग शाब्दिक "कॉलम" का चयन करेगी जहां कॉलम फू स्ट्रिंग "बार" के बराबर है

ANSI_QUOTES सक्षम किया गया

क्वेरी कॉलम कॉलम का चयन करेगी जहां कॉलम फू कॉलम के बराबर है

कब इस्तेमाल करें

  • मेरा सुझाव है कि आप " का उपयोग करने से बचें ताकि आपका कोड SQL मोड पर निर्भर न हो
  • हमेशा पहचानकर्ता शामिल करें क्योंकि यह अच्छा अभ्यास है (एसओ पर कुछ प्रश्न इस पर चर्चा करते हैं)

" " और " " के प्रयोग में स्पष्ट अंतर है।

जब " " का प्रयोग सर्वत्र किया जाता है, तो कोई "परिवर्तन या अनुवाद" नहीं होता है। इसे वैसे ही मुद्रित किया जाता है।

" " के साथ, यह जो कुछ भी घेरता है वह इसके मूल्य में "अनुवादित या रूपांतरित" हो जाता है।

अनुवाद/रूपांतरण से मेरा तात्पर्य यह है: एकल उद्धरण चिह्नों में मौजूद किसी भी चीज़ का उनके मूल्यों में "अनुवाद" नहीं किया जाएगा। उन्हें स्वीकार किया जाएगा क्योंकि वे उद्धरण के अंदर हैं। उदाहरण: a=23 , फिर echo "$a" मानक आउटपुट पर $a उत्पन्न करेगा। जबकि echo "$a" मानक आउटपुट पर 23 उत्पन्न करेगा।

(PHP 4 >= 4.3.0, PHP 5)

mysql_real_escape_string - SQL कथन में उपयोग के लिए स्ट्रिंग में विशेष वर्णों को छोड़ देता है

विवरण

mysql_real_escape_string (स्ट्रिंग $unescaped_string [, संसाधन $link_identifier = NULL]): डोरी

कनेक्शन के वर्तमान वर्ण सेट को ध्यान में रखते हुए, unescaped_string में विशेष वर्णों से बच जाता है ताकि इसे इसमें रखना सुरक्षित हो mysql_query(). यदि बाइनरी डेटा सम्मिलित करना है, तो इस फ़ंक्शन का उपयोग किया जाना चाहिए।

mysql_real_escape_string() MySQL के लाइब्रेरी फ़ंक्शन को mysql_real_escape_string कहते हैं, जो निम्नलिखित वर्णों के लिए बैकस्लैश जोड़ता है: \x00, \एन, \आर, \ , " , " और \x1a.

MySQL को क्वेरी भेजने से पहले डेटा को सुरक्षित बनाने के लिए इस फ़ंक्शन का उपयोग हमेशा (कुछ अपवादों के साथ) किया जाना चाहिए।

सावधानी

सुरक्षा: डिफ़ॉल्ट वर्ण सेट

कैरेक्टर सेट को या तो सर्वर स्तर पर या एपीआई फ़ंक्शन के साथ सेट किया जाना चाहिए mysql_set_charset()इसे प्रभावित करने के लिए mysql_real_escape_string() . अधिक जानकारी के लिए चरित्र सेट पर अवधारणा अनुभाग देखें।

पैरामीटर

unescaped_string

वह स्ट्रिंग जिससे बचना है.

लिंक_पहचानकर्ता

MySQL कनेक्शन. यदि लिंक पहचानकर्ता निर्दिष्ट नहीं है, तो अंतिम लिंक खोला गया mysql_कनेक्ट()ऐसा माना जाता है। यदि ऐसा कोई लिंक नहीं मिलता है, तो वह एक लिंक बनाने का प्रयास करेगा mysql_कनेक्ट()बिना किसी तर्क के बुलाया गया था। यदि कोई कनेक्शन नहीं मिलता है या स्थापित नहीं होता है, तो ई_चेतावनीस्तर की त्रुटि उत्पन्न होती है।

वापसी मान

बची हुई स्ट्रिंग लौटाता है, या असत्यत्रुटि पर.

त्रुटियाँ/अपवाद

बिना MySQL कनेक्शन के इस फ़ंक्शन को निष्पादित करने से भी उत्सर्जन होगा ई_चेतावनीलेवल PHP त्रुटियाँ। इस फ़ंक्शन को केवल वैध MySQL कनेक्शन के साथ ही निष्पादित करें।

उदाहरण

उदाहरण #1 सरल mysql_real_escape_string() उदाहरण

//जोड़ना
$लिंक = mysql_connect("mysql_host", "mysql_user", "mysql_password")
या मरो(mysql_error());

//सवाल
$क्वेरी = स्प्रिंटफ ( "चुनें * उन उपयोगकर्ताओं से जहां उपयोगकर्ता = "%s" और पासवर्ड = "%s"",
mysql_real_escape_string($उपयोगकर्ता),
mysql_real_escape_string($password));
?>

उदाहरण #2 mysql_real_escape_string() एक कनेक्शन उदाहरण की आवश्यकता है

यह उदाहरण दर्शाता है कि यदि इस फ़ंक्शन को कॉल करते समय MySQL कनेक्शन मौजूद नहीं है तो क्या होगा।

उपरोक्त उदाहरण कुछ इस प्रकार आउटपुट देगा:

चेतावनी: mysql_real_escape_string(): लाइन 5 पर /this/test/script.php में ऐसी कोई फ़ाइल या निर्देशिका नहीं है चेतावनी: mysql_real_escape_string(): लाइन 5 पर /this/test/script.php में सर्वर का लिंक स्थापित नहीं किया जा सका बूल(गलत) स्ट्रिंग(41) "उन अभिनेताओं से चुनें* जहां अंतिम_नाम = """

उदाहरण #3 SQL इंजेक्शन अटैक का एक उदाहरण

// हमने $_POST["password"] की जांच नहीं की, यह कुछ भी हो सकता है जो उपयोगकर्ता चाहता था! उदाहरण के लिए:
$_POST ["उपयोगकर्ता नाम" ] = "सहायता";
$_POST ["पासवर्ड" ] = "" या ""='' ;

// यह जांचने के लिए डेटाबेस को क्वेरी करें कि क्या कोई मेल खाने वाला उपयोगकर्ता है
$क्वेरी = ($_POST ["उपयोगकर्ता नाम" ]) "और पासवर्ड=" ($_POST ["पासवर्ड" ]) "" ;
mysql_query($query);

// इसका मतलब है कि MySQL को भेजी गई क्वेरी होगी:
प्रतिध्वनि $क्वेरी ;
?>

क्वेरी MySQL को भेजी गई:

इससे कोई भी व्यक्ति बिना वैध पासवर्ड के लॉग इन कर सकेगा।

टिप्पणियाँ

उपयोग करने से पहले एक MySQL कनेक्शन आवश्यक है mysql_real_escape_string() अन्यथा स्तर की त्रुटि ई_चेतावनीउत्पन्न होता है, और असत्यलौटा दिया जाता है. यदि link_identifier परिभाषित नहीं है, तो अंतिम MySQL कनेक्शन का उपयोग किया जाता है।

टिप्पणी: mysql_real_escape_string() बचता नहीं % और _ . यदि इनके साथ संयुक्त किया जाए तो ये MySQL में वाइल्डकार्ड हैं पसंद, अनुदान, या रद्द करना.

8 साल पहले

बस एक छोटा सा फ़ंक्शन जो मूल mysql_real_escape_string की नकल करता है लेकिन जिसके लिए सक्रिय MySQL कनेक्शन की आवश्यकता नहीं है। डेटाबेस क्लास में एक स्थिर फ़ंक्शन के रूप में कार्यान्वित किया जा सकता है। आशा है कि यह किसी की मदद करेगा।

फ़ंक्शन mysql_escape_mimic ($inp) (
यदि(is_array($inp))
वापसी array_map (__METHOD__, $inp);

यदि(!खाली($inp ) && is_string ($inp )) (
वापसी str_replace (सरणी("\\" , "\0" , "\n" , "\r" , """ , """ , "\x1a" ), सरणी("\\\\" , "\ \0" , "\\n" , "\\r" , "\\"" , "\\"" , "\\Z" ), $inp );
}

वापसी $inp ;
}
?>

13 साल पहले

ध्यान दें कि दस्तावेज़ में उल्लिखित अनुसार mysql_real_escape_string बैकस्लैश को \x00, \n, \r, और \x1a में नहीं जोड़ता है, लेकिन वास्तव में वर्ण को प्रश्नों के लिए MySQL स्वीकार्य प्रतिनिधित्व से बदल देता है (उदाहरण के लिए \n को "\ से बदल दिया जाता है) n" शाब्दिक)। (\, ", और " दस्तावेज़ के रूप में बच गए हैं) इससे यह नहीं बदलता है कि आपको इस फ़ंक्शन का उपयोग कैसे करना चाहिए, लेकिन मुझे लगता है कि यह जानना अच्छा है।

6 साल पहले

भागने की कोई भी चर्चा हर किसी को यह बताए बिना पूरी नहीं होती है कि आपको मूल रूप से व्याख्या किए गए कोड को उत्पन्न करने के लिए बाहरी इनपुट का उपयोग कभी नहीं करना चाहिए। यह SQL कथनों, या ऐसी किसी भी चीज़ के लिए लागू होता है जिस पर आप किसी भी प्रकार का "eval" फ़ंक्शन कॉल करेंगे।

इसलिए, इस बेहद टूटे हुए फ़ंक्शन का उपयोग करने के बजाय, पैरामीट्रिक तैयार कथनों का उपयोग करें।

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

इसका क्या मतलब है?

इसका मतलब है कि इस तरह SQL स्टेटमेंट बनाने के बजाय:

"X (A) मानों में सम्मिलित करें("।$_POST["a"].)"

आपको इस तरह दिखने वाले कथन को निष्पादित करने के लिए mysqli के तैयार() फ़ंक्शन() का उपयोग करना चाहिए:

"X (A) मानों में सम्मिलित करें(?)"

ध्यान दें: इसका मतलब यह नहीं है कि आपको कभी भी गतिशील SQL कथन उत्पन्न नहीं करना चाहिए। इसका मतलब यह है कि आपको उन कथनों को उत्पन्न करने के लिए कभी भी उपयोगकर्ता द्वारा प्रदान किए गए डेटा का उपयोग नहीं करना चाहिए। उपयोगकर्ता द्वारा प्रदान किए गए किसी भी डेटा को कथन के बाद पैरामीटर के रूप में पारित किया जाना चाहिए तैयार किया गया.

इसलिए, उदाहरण के लिए, यदि आप एक छोटा ढांचा बना रहे हैं और अनुरोध यूआरआई के आधार पर एक तालिका में सम्मिलित करना चाहते हैं, तो $_SERVER["REQUEST_URI"] मान (या कोई भी) न लेना आपके हित में है इसका हिस्सा) और इसे सीधे अपनी क्वेरी के साथ जोड़ दें। इसके बजाय, आपको $_SERVER["REQUEST_URI"] मान के उस हिस्से को पार्स करना चाहिए जो आप चाहते हैं, और उसे किसी प्रकार के फ़ंक्शन या सहयोगी सरणी के माध्यम से किसी गैर-उपयोगकर्ता के लिए मैप करें प्रदान किया गया मूल्य। यदि मैपिंग कोई मूल्य उत्पन्न नहीं करती है, तो आप जानते हैं कि उपयोगकर्ता द्वारा प्रदान किए गए डेटा में कुछ गड़बड़ है।

इसका पालन न करना रूबी ऑन रेल्स फ्रेमवर्क में कई एसक्यूएल-इंजेक्शन समस्याओं का कारण रहा है, भले ही यह पैरामीट्रिक तैयार कथनों का उपयोग करता है। इस तरह एक समय पर GitHub को हैक कर लिया गया था। इसलिए, कोई भी भाषा इस समस्या से अछूती नहीं है। इसीलिए यह एक सामान्य सर्वोत्तम अभ्यास है और PHP के लिए कुछ विशिष्ट नहीं है और आपको इसे वास्तव में क्यों अपनाना चाहिए।

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

9 साल पहले

SQL इंजेक्शन के बारे में उदाहरण #2 में एक दिलचस्प विचित्रता है: AND को OR पर प्राथमिकता दी जाती है, इसलिए इंजेक्ट की गई क्वेरी वास्तव में WHERE (उपयोगकर्ता = "सहायता" और पासवर्ड = "") या "" = "" के रूप में निष्पादित होती है, इसलिए इसके बजाय एक मनमाना उपयोगकर्ता नाम (इस मामले में "सहायता") के अनुरूप डेटाबेस रिकॉर्ड वापस करने पर, यह वास्तव में सभी डेटाबेस रिकॉर्ड लौटाएगा। किसी विशेष क्रम में नहीं। इसलिए एक हमलावर किसी भी खाते के रूप में लॉग इन करने में सक्षम हो सकता है, लेकिन जरूरी नहीं कि किसी भी खाते के साथ यह कौन सा खाता है, इस पर नियंत्रण रखें.

निःसंदेह एक आक्रमण संभावित व्यक्ति रुचि के विशिष्ट उपयोगकर्ताओं को लक्षित करने के लिए अपने मापदंडों को आसानी से संशोधित कर सकता है:

//उदा. हमलावर के मूल्य
$_POST ["उपयोगकर्ता नाम" ] = "" ;
$_POST["पासवर्ड"] = "" या उपयोगकर्ता = "प्रशासक" और "" = "";

//विकृत क्वेरी
$ प्रश्न = "चुनें * उन उपयोगकर्ताओं से जहां उपयोगकर्ता ="$_POST [उपयोगकर्ता नाम ] "और पासवर्ड =" $_POST [पासवर्ड ] "" ;

प्रतिध्वनि $क्वेरी ;

// MySQL को भेजी गई क्वेरी पढ़ेगी:
// चुनें * उन उपयोगकर्ताओं से जहां उपयोगकर्ता = "" और पासवर्ड = "" या उपयोगकर्ता = "प्रशासक" और "" = "";
// जो किसी को भी "प्रशासक" नामक खाते तक पहुंच प्राप्त करने की अनुमति देगा

?>

1 साल पहले

@फीडर
मैंने उनके नोट को इस प्रकार विस्तृत किया:
$string = "asda\0sd\x1aas\\\\\\\dasd\"asdasd\na\"\"sdasdad";
$array1 = array("\\\\\\\", "\0", "\n", "\r", """, """, "\x1a");
$array2 = array('\\\\\\\\\\\\\\\', '\\0', '\\\n', '\\\r', '\\\ " ", "\\\"", "\\\Z");
प्रतिध्वनि($स्ट्रिंग);
इको(PHP_EOL);
for($i=0; $i अगर ($i==0)
$p = "/(?अन्य
$p = "/(?प्रतिध्वनि($i);
प्रतिध्वनि($p);
प्रतिध्वनि($array2[$i]);
$स्ट्रिंग = preg_replace($p, $array2[$i], $string);
प्रतिध्वनि('\t');
प्रतिध्वनि($स्ट्रिंग);
इको(PHP_EOL);
}
इको(PHP_EOL);
प्रतिध्वनि($स्ट्रिंग);

2 वर्ष पहले

नम्ब सफारी में सैम को उद्धृत करने के लिए

["हर किसी को यह बताए बिना भागने की कोई भी चर्चा पूरी नहीं होती है कि आपको मूल रूप से व्याख्या किए गए कोड को उत्पन्न करने के लिए बाहरी इनपुट का उपयोग कभी नहीं करना चाहिए। यह SQL कथनों, या किसी भी चीज़ के लिए जाता है जिसे आप किसी भी प्रकार के "eval" फ़ंक्शन पर कॉल करेंगे।

इसलिए, इस बेहद टूटे हुए फ़ंक्शन का उपयोग करने के बजाय, पैरामीट्रिक तैयार कथनों का उपयोग करें।

ईमानदारी से, SQL स्टेटमेंट बनाने के लिए उपयोगकर्ता द्वारा प्रदान किए गए डेटा का उपयोग करना पेशेवर लापरवाही माना जाना चाहिए और पैरामीट्रिक तैयार स्टेटमेंट का उपयोग न करने के लिए आपको अपने नियोक्ता या ग्राहक द्वारा जवाबदेह ठहराया जाना चाहिए।

सैम सही है...

हालाँकि, मुझे नहीं लगता कि सभी तरह की सफाई बंद कर देना और कार्य को केवल पैरामीट्रिक तैयार बयानों पर सौंप देना समझदारी है।

किसी विशेष परिस्थिति में काम करने वाला एक विशेष डेवलपर हमेशा वैध इनपुट (उस संदर्भ के लिए विशिष्ट) के बारे में अधिक जानता होगा।

यदि आप किसी उपयोगकर्ता को वह मान देने के लिए कहते हैं जो आपने उन्हें पहले ही दे दिया है और आप जानते हैं कि ऐसे सभी मान AB****** से शुरू होते हैं और स्ट्रिंग की लंबाई 7 या 11 होनी चाहिए, लेकिन कभी भी कोई अन्य लंबाई नहीं होनी चाहिए, तो आपके पास है एक अच्छे प्री-सैनिटाइज़र का आधार - एक स्ट्रिंग की विभिन्न स्वीकार्य लंबाई विरासत डेटा का संकेत दे सकती है।

मैं कभी भी किसी दुर्भावनापूर्ण उपयोगकर्ता द्वारा फॉर्म के माध्यम से भेजे गए बकवास को पैरामीट्रिक तैयार किए गए बयानों में नहीं डालना चाहूंगा, मैं हमेशा पहले अपनी स्वयं की विवेक जांच करना चाहूंगा और कुछ मामलों में सावधानी बरतने में गलती हो सकती है और बस डेटाबेस ऑप को पूरी तरह से निरस्त करना चुनें।

इस तरह से मेरा डीबी सुरक्षित बनाए गए असुरक्षित बयानों से अवरुद्ध नहीं होता है - यह बस अवरुद्ध नहीं होता है जो कि बेहतर है।

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

इसके अलावा जहाँ तक मैं आधिकारिक दस्तावेज़ में पढ़ सकता हूँ
==============================================

"पलायन और एसक्यूएल इंजेक्शन

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

इससे मुझे पता चलता है कि खतरे को आंतरिक रूप से वैकल्पिक प्रबंधन से टाला जाता है, निरस्तीकरण से नहीं।

इसका मतलब यह है कि तैयार किए गए बयानों में अधूरे रूपांतरण के साथ एक बड़ी परियोजना, किसी संगठन के विभिन्न हिस्सों में विरासत कोड या एक-दूसरे से बात करने वाले सर्वर सभी बुरी खबरों को एक प्रतिरक्षा स्थान या स्थिति से उस स्थान तक पहुंचा सकते हैं जो प्रतिरक्षा नहीं है।

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


सबसे पहले, इस बारे में थोड़ा कि सामान्य तौर पर इन स्लैश की आवश्यकता क्यों है।
यदि हम किसी डेटा को किसी क्वेरी में प्रतिस्थापित करते हैं, तो इस डेटा को SQL कमांड से अलग करने के लिए, उन्हें उद्धरण चिह्नों में रखा जाना चाहिए।
उदाहरण के लिए, यदि आप लिखते हैं
* तालिका से चुनें जहां नाम = बिल
तब डेटाबेस तय करेगा कि बिल किसी अन्य फ़ील्ड का नाम है, उसे नहीं ढूंढेगा, और एक त्रुटि फेंक देगा। इसलिए, प्रतिस्थापित डेटा (इस मामले में, नाम बिल) को उद्धरण चिह्नों में संलग्न किया जाना चाहिए - फिर डेटाबेस इसे एक स्ट्रिंग पर विचार करेगा, जिसका मान नाम फ़ील्ड को निर्दिष्ट किया जाना चाहिए:
* तालिका से चुनें जहां नाम = "बिल"
हालाँकि, उद्धरण डेटा में भी दिखाई दे सकते हैं। जैसे,
तालिका से चुनें * जहां नाम = "डी"आर्टगनन"
यहां डेटाबेस तय करेगा कि "D" डेटा है, और Artagnan एक कमांड है जिसे वह नहीं जानता है, और एक त्रुटि भी देगा। इसलिए, डेटाबेस को यह समझाने के लिए सभी डेटा का पता लगाना आवश्यक है कि उनमें पाए गए उद्धरण चिह्न (और कुछ अन्य विशेष वर्ण) डेटा को संदर्भित करते हैं।
परिणामस्वरूप, हमें एक सही अनुरोध प्राप्त होगा जिससे त्रुटियाँ नहीं होंगी:
तालिका से चुनें * जहां नाम = "D\"Artagnan"

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

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

उपरोक्त सभी स्ट्रिंग डेटा और तिथियों पर लागू होते हैं। संख्याओं को बिना पीछे किए या उद्धरण चिह्नों से घिरे बिना डाला जा सकता है। यदि आप ऐसा करते हैं तो अनिवार्य रूप से!क्वेरी में डालने से पहले डेटा को वांछित प्रकार में बाध्य करें, उदाहरण के लिए:
$आईडी = अंतराल ($आईडी);
हालाँकि, सरलता (और विश्वसनीयता) के लिए, आप संख्याओं के साथ स्ट्रिंग की तरह काम कर सकते हैं (क्योंकि MySQL अभी भी उन्हें वांछित प्रकार में परिवर्तित करता है)। तदनुसार, हम अनुरोध में डाले गए किसी भी डेटा का पता लगाएंगे और उसे उद्धरण चिह्नों में संलग्न करेंगे।

इसके अलावा, एक और नियम है - वैकल्पिक, लेकिन त्रुटियों से बचने के लिए इसका पालन किया जाना चाहिए:
फ़ील्ड और तालिकाओं के नाम पीछे के सिंगल कोट्स में संलग्न होने चाहिए - "`" (इस प्रतीक वाली कुंजी "1" कुंजी के बाईं ओर एक मानक कीबोर्ड पर स्थित है)। आखिरकार, फ़ील्ड का नाम mysql के साथ मेल खा सकता है कीवर्ड, लेकिन यदि हम बैक कोट का उपयोग करते हैं, तो MySQL समझ जाएगा कि सब कुछ सही है:
`तालिका` से चुनें * जहां `दिनांक` = "2006-04-04"
आपको इन उद्धरण चिह्नों के बीच अंतर करना चाहिए और एक को दूसरे के साथ भ्रमित नहीं करना चाहिए। आपको यह भी याद रखना चाहिए कि बैकटिक्स स्लैश से बच नहीं पाते हैं।

इसलिए, हमने सीखा है कि अनुरोध में डेटा को सही ढंग से कैसे प्रतिस्थापित किया जाए।
लेकिन! गतिशील क्वेरी निर्माण डेटा प्रतिस्थापन तक सीमित नहीं है। अक्सर हमें किसी क्वेरी में SQL कमांड और फ़ील्ड नाम को प्रतिस्थापित करना पड़ता है। और यहां हम सुरक्षा के विषय पर आगे बढ़ते हैं:

एसक्यूएल इंजेक्शन हैकर हमले की एक विधि है जब किसी स्क्रिप्ट में स्थानांतरित किए गए डेटा को इस तरह से संशोधित किया जाता है कि इस स्क्रिप्ट में उत्पन्न क्वेरी अपने इच्छित उद्देश्य से पूरी तरह से अलग प्रदर्शन करना शुरू कर देती है।
ऐसे हमलों से बचाव के नियमों को दो बिंदुओं में विभाजित किया जा सकता है:
1. डेटा के साथ कार्य करना।
2. क्वेरी नियंत्रण के साथ कार्य करना।

हमने ऊपर पहले बिंदु पर विस्तार से चर्चा की। यह कहा जा सकता है कि वास्तव में यह कोई बचाव नहीं है। किसी क्वेरी में डेटा जोड़ने के नियमों का अनुपालन, सबसे पहले, SQL SYNTAX की आवश्यकताओं द्वारा निर्धारित होता है। और साइड इफ़ेक्ट के तौर पर हमें हैकिंग से भी सुरक्षा मिलती है।

दूसरा बिंदु अधिक कठिन है, क्योंकि डेटा के लिए कोई एक सार्वभौमिक नियम नहीं है - बैकटिक्स फ़ील्ड नाम को हैकर द्वारा संशोधित होने से नहीं बचाएगा। तालिका नाम, SQL कथन, LIMIT कमांड पैरामीटर और अन्य कथनों की सुरक्षा के लिए उद्धरणों का उपयोग करना संभव नहीं है।
इसलिए, किसी क्वेरी में नियंत्रण तत्वों को प्रतिस्थापित करते समय मूल नियम यह है:
यदि आपको किसी क्वेरी में SQL कथन या फ़ील्ड, डेटाबेस, तालिकाओं के नाम को गतिशील रूप से सम्मिलित करने की आवश्यकता है, तो किसी भी परिस्थिति में आपको उन्हें सीधे क्वेरी में सम्मिलित नहीं करना चाहिए।
ऐसे परिवर्धन के लिए सभी विकल्प आपकी स्क्रिप्ट में अग्रिम रूप से लिखे जाने चाहिए और उपयोगकर्ता द्वारा दर्ज किए गए के आधार पर चुने जाने चाहिए।
उदाहरण के लिए, यदि आपको ऑपरेटर द्वारा ऑर्डर में फ़ील्ड नाम पास करने की आवश्यकता है, तो किसी भी परिस्थिति में आपको इसे सीधे प्रतिस्थापित नहीं करना चाहिए। हमें पहले इसकी जांच करनी होगी. उदाहरण के लिए, मान्य मानों की एक सरणी बनाएं और इसे अनुरोध में तभी प्रतिस्थापित करें जब पारित पैरामीटर इस सरणी में मौजूद हो:
$ ऑर्डर = सरणी ("नाम", "मूल्य", "मात्रा");
$कुंजी = array_search($_GET["सॉर्ट"], $ऑर्डर));
$orderby = $orders [ $key ];
$ प्रश्न = "'तालिका' से ऑर्डर द्वारा चुनें *$orderby " ;

हम उपयोगकर्ता द्वारा दर्ज किए गए शब्द के लिए पूर्व-वर्णित विकल्पों की सरणी खोजते हैं, और यदि हमें वह मिलता है, तो हम सरणी के संबंधित तत्व का चयन करते हैं। यदि कोई मिलान नहीं मिलता है, तो सरणी का पहला तत्व चुना जाएगा।
इस प्रकार, अनुरोध में जो प्रतिस्थापित किया गया है वह वह नहीं है जो उपयोगकर्ता ने दर्ज किया है, बल्कि वह है जो हमारी स्क्रिप्ट में लिखा गया था।
अन्य सभी मामलों में भी ऐसा ही किया जाना चाहिए।
उदाहरण के लिए, यदि WHERE क्लॉज गतिशील रूप से उत्पन्न होता है:
अगर (!खाली($_GET ["कीमत" ])) $कहाँ .= "कीमत= "" . mysql_real_escape_string ($_GET [ "कीमत" ]). """ ;
$query = "चयन करें * `तालिका` से कहां $कहां";

मेरे लिए ऐसे मामले की कल्पना करना कठिन है जहां किसी तालिका का नाम किसी क्वेरी में गतिशील रूप से डाला जा सकता है, लेकिन यदि ऐसा होता है, तो नाम को केवल स्क्रिप्ट में पूर्व-परिभाषित सेट से ही डालने की आवश्यकता होती है।
LIMIT ऑपरेटर के मापदंडों को अंकगणितीय संचालन या intval() फ़ंक्शन का उपयोग करके एक पूर्णांक प्रकार पर मजबूर किया जाना चाहिए।
यह मत सोचिए कि यहां सूचीबद्ध उदाहरण गतिशील क्वेरी निर्माण के सभी विकल्पों को समाप्त कर देते हैं। आपको बस सिद्धांत को समझने और ऐसे सभी मामलों में इसे लागू करने की आवश्यकता है।

मेरे काम की प्रकृति के कारण, मुझे वेब एप्लिकेशन के स्रोत कोड का सुरक्षा ऑडिट करना पड़ता है।
ढेर सारे वेब एप्लिकेशन और ढेर सारे कोड...

यह कोई रहस्य नहीं है कि SQL इंजेक्शन कमजोरियाँ सभी सर्वर-साइड वेब एप्लिकेशन कमजोरियों में सबसे आम हैं। ऐसे प्लेटफ़ॉर्म और ढाँचे हैं जहाँ ऐसी चीज़ों को लगभग पूरी तरह से बाहर रखा गया है, उदाहरण के लिए ORM वगैरह। लेकिन आँकड़े लगातार हमें इंटरनेट पर सरल संयोजित SQL प्रश्नों के साथ वेब अनुप्रयोगों की पूर्ण प्रबलता के बारे में बताते हैं। इसके अलावा, ऐसे मामले भी हैं जहाँ ORM है आम तौर पर यह लागू नहीं हो सकता, उदाहरण के लिए, जब न केवल अभिव्यक्ति के पैरामीटर, बल्कि ऑपरेटर स्तर पर क्वेरी तर्क भी उपयोगकर्ता डेटा पर निर्भर होना चाहिए।

तो, चलिए शुरू करते हैं।

बेकार चरित्र का पलायन
83% PHP वेब अनुप्रयोगों में SQL इंजेक्शन के प्रति संवेदनशील पाया गया
जैसे पात्रों के लिए एस्केप फ़ंक्शन का उपयोग करना
mysql_escape_string
mysql_real_escape_string
addlashes
बिना उद्धरण चिह्न के. अधिकतर यह स्वयं को संख्यात्मक मापदंडों (सभी प्रकार के *_id) में प्रकट करता है।
उदाहरण
$sql = "उपयोगकर्ता सूची से उपयोगकर्ता का चयन करें जहां उपयोगकर्ता आईडी = ".mysql_real_escape_string ($ _ GET ["uid"]);

यह सुरक्षित कोड प्रतीत होता है, लेकिन केवल सतह पर। मेरे अभ्यास में PHP में SQL इंजेक्शन का सबसे आम पैटर्न यहां सामने आया है। इस भेद्यता पर हमला करने के लिए, एक हमलावर को हमले वेक्टर में " " \x00 \r \n \x1a वर्णों का उपयोग करने से बचना होगा।
उदाहरण के लिए:
/index.php?uid=-777 यूनियन उपयोगकर्ता सूची से पासवर्ड चुनें

कोड में खोजें
भाषा के शब्दार्थ से जटिल। सरल खोज के लिए आप egrep का उपयोग कर सकते हैं:
egrep -Rin "(select|update|insert|delete|replace).*(from|set|into).*(mysql_escape_string|mysql_real_escape_string|adslashes)" . | grep -v "[\""]["\"]"

खोज अभिव्यक्ति का तर्क इस प्रकार है: फ़िल्टरिंग फ़ंक्शन के बाईं ओर उन सभी पंक्तियों को ढूंढें जिनमें उद्धरण वर्णों ("", "", "", "") का कोई क्रम नहीं है। बेशक, यह विधि 100% से बहुत दूर है, लेकिन सिमेंटिक विश्लेषण करने के लिए नियमित अभिव्यक्ति की आवश्यकता होना असंभव है।
जानकारी प्रदर्शित करना आसान बनाने के लिए, आप कंसोल में फ़ंक्शन को रंग में हाइलाइट कर सकते हैं:
egrep -Rin "(select|update|insert|delete|replace).*(from|set|into).*(mysql_escape_string|mysql_real_escape_string|adslashes)" . | grep -v "[\""]["\"]" | egrep --color "(mysql_escape_string|mysql_real_escape_string|adslashes)"

इस वाइल्डकार्ड भेद्यता से बचाने के लिए, टाइप कास्टिंग का उपयोग करना सबसे अच्छा है।
यह हमेशा तेजी से काम करता है और सभी प्रकार की फ़िल्टरिंग और स्क्रीनिंग की तुलना में अधिक विश्वसनीय है।
उपरोक्त उदाहरण के लिए, पैच इस प्रकार हो सकता है:
$sql = "उपयोगकर्ता सूची से उपयोगकर्ता का चयन करें जहां उपयोगकर्ता आईडी = ".intval ($_GET["uid"]);

यह लघु निबंध का समापन करता है। मैं सभी वेब डेवलपर्स से आग्रह करता हूं कि वे ऐसे डिज़ाइनों के लिए अपने स्रोतों की जांच करने का प्रयास करें। इससे भी बेहतर, लोगों के लिए दी गई खोज स्क्रिप्ट का विस्तार करें।

इसलिए मूल रूप से मैंने MySQL और PHP के क्षेत्रों में गहराई से खोजबीन की... विशेष रूप से डेटाबेस और फॉर्म इनपुट के साथ काम करते समय मुझे सुरक्षा उपाय करने चाहिए। अब तक मैंने निम्नलिखित को अत्यधिक अनुशंसित पाया है:

  1. तैयार किये गये वक्तव्य
  2. _real_escape_string() का उपयोग करना
  3. जादुई उद्धरणों का उपयोग न करें क्योंकि यह डेटाबेस को भ्रमित करता है और आपको "आपने इसे कॉल नहीं किया..." जैसी चीज़ें देता है।

यह सब बढ़िया है और मैं इस पर नजर रख रहा हूं। हालाँकि, मैं सोच रहा था कि क्या मुझे डॉलर चिह्न [$], प्रतिशत चिह्न [%] और शायद अन्य जैसे वर्णों से बचना चाहिए। क्या क्वेरी ने डॉलर चिह्न की व्याख्या शायद PHP वैरिएबल के रूप में की होगी? LIKE सिंटैक्स के बारे में मैंने क्या सुना है जो % प्रतीक या यहां तक ​​कि वाइल्डकार्ड का उपयोग करता है? तैयार किए गए बयानों में तकनीकी रूप से इन सबका ध्यान रखा जाना चाहिए, लेकिन मैं सिर्फ सुरक्षित रहना चाहता था और यह सुनिश्चित करना चाहता था कि मैंने सब कुछ ठीक से कवर कर लिया है। ऐसे मामलों में जहां मैं तैयार किए गए बयानों का उपयोग करना भूल जाता हूं या बस उनकी उपेक्षा करता हूं, मुझे उम्मीद थी कि रक्षा की यह दूसरी पंक्ति मुझे बता सकती है कि मैं चक्कर से छुटकारा पा सकता हूं।

यहाँ मैं वर्तमान में भागने के लिए उपयोग कर रहा हूँ:

फ़ंक्शन एस्केप($कनेक्शन, $डेटा)( $new_data = ट्रिम($डेटा); $new_data = i_real_escape_string($कनेक्शन, $new_data); $new_data = addcslashes($new_data, "%_$"); $new_data = htmlspecialchars ($new_data, ENT_NOQUOTES); $new_data लौटाएं; )

तो क्या ये सही है? क्या मैं कुछ बहुत ग़लत कर रहा हूँ? कृपया ध्यान दें कि डेटाबेस डेटा लौटाते समय मुझे $,% और _ वर्णों से पहले बैकस्लैश को हटाना होगा।

क्या मैं कुछ बहुत ग़लत कर रहा हूँ?

सबसे पहले आपके शोध के बारे में.

तैयार किए गए बयान- एकमात्रअद्भुत चीज़ जो आपको मिली.

हालाँकि mysqli_real_escape_string का उपयोग करना (यह मानते हुए कि आप तैयार कथनों का उपयोग कर रहे हैं) होगा बेकार और हानिकारक(एक ऐसा परिणाम बनाना जिसे आपने स्वयं नोट किया हो: "आपने कॉल किया है\t...")।

और जादुई उद्धरण लंबे समय से भाषा से हटा दिए गए हैं - इसलिए वास्तव में उनका कोई मूल्य नहीं है।

तो आपके अधिकांश प्रारंभिक आधार भी स्पष्ट रूप से गलत हैं।

अब आपके प्रश्न पर.

क्या क्वेरी ने डॉलर चिह्न की व्याख्या शायद PHP वैरिएबल के रूप में की होगी?

LIKE सिंटैक्स के बारे में मैंने क्या सुना है जो % प्रतीक या यहां तक ​​कि वाइल्डकार्ड का उपयोग करता है?

हां, तुमने यह सही सुना। LIKE ऑपरेटर का सटीक उद्देश्य एक पैटर्न खोज करना है। इन वर्णों को LIKE में अक्षम करने का कोई मतलब नहीं होगा।

हर बार जब आप LIKE ऑपरेटर का उपयोग करने जा रहे हों, तो आपको यह तय करना होगा कि किस विशिष्ट वर्ण का उपयोग करना है और किसे अस्वीकार करना है। आप एक बार के समाधान का उपयोग नहीं कर सकते. यह उल्लेख करने की आवश्यकता नहीं है कि अन्य सभी MySQL इंटरैक्शन में % चिह्न का कोई विशेष अर्थ नहीं है।

तैयार किए गए वक्तव्यों को तकनीकी रूप से इन सबका ध्यान रखना चाहिए

तैयार किए गए कथनों का $ या % चिह्नों से कोई लेना-देना नहीं है। तैयार किए गए कथन SQL इंजेक्शन को संदर्भित करते हैं, लेकिन कोई भी चरित्र इसका कारण नहीं बन सकता है (आप "इंजेक्शन" को उचित रूप से उपयोग किया जाने वाला LIKE ऑपरेटर नहीं कह सकते, क्या आप ऐसा कर सकते हैं?)।

अंत में, सबसे खराब स्थिति में।

यदि आप तैयार कथनों का उपयोग करना भूल जाते हैं या उनका पालन करने की उपेक्षा करते हैं,

कुछ भी तुम्हें नहीं बचाएगा.

और सबसे कम मदद आपके द्वारा विकसित फ़ंक्शन से होगी।

संक्षेप।

  1. इस सुविधा से छुटकारा पाएं.
  2. उपयोग भराव*क्वेरी में प्रत्येक व्यक्तिगत चर का प्रतिनिधित्व करने के लिए।
  3. इनपुट में % और _ वर्णों से तभी बचें जब उनका उपयोग LIKE ऑपरेटर में किया जाएगा और आप नहीं चाहते कि उनकी व्याख्या की जाए।
  4. आउटपुट के लिए htmlspecialchars() का उपयोग करें, mysql इनपुट का नहीं।

*यदि यह शब्द आपके लिए अपरिचित है तो तैयार कथन पढ़ें।

आपको डॉलर चिह्न से बचने की ज़रूरत नहीं है। MySQL इस वर्ण को विशेष रूप से नहीं देखता है, और PHP इसे केवल स्रोत कोड में पहचानता है, स्ट्रिंग मानों में नहीं (जब तक कि आप स्ट्रिंग पर eval को कॉल नहीं करते हैं, लेकिन यह पूरी तरह से अन्य कीड़ा है)।

आपको केवल % और _ से बचने की आवश्यकता होगी यदि आप उपयोगकर्ता इनपुट को LIKE तर्क के रूप में उपयोग कर रहे थे और आप नहीं चाहते थे कि उपयोगकर्ता वाइल्डकार्ड का उपयोग करने में सक्षम हो। यदि आप किसी खोज फ़ॉर्म को संसाधित कर रहे हैं तो ऐसा हो सकता है। डेटाबेस में भंडारण करते समय आपको इसका उपयोग करने की आवश्यकता नहीं है।

डेटाबेस तक पहुँचते समय आपको htmlspecialchars का उपयोग करने की आवश्यकता नहीं है। इसका उपयोग केवल XSS इंजेक्शन को रोकने के लिए HTML पेज पर उपयोगकर्ता को डेटा प्रदर्शित करते समय किया जाना चाहिए।

यह इस बात पर निर्भर करता है कि कौन सा डेटा और इसका उपयोग किस लिए किया जाता है।

यदि आप पाते हैं कि PHP के डिफ़ॉल्ट आउट-ऑफ-द-बॉक्स स्टेटमेंट बहुत बड़े और जटिल हैं, तो मेरा सुझाव है कि आपको सरलीकृत प्रश्नों का अंदाजा देने के लिए जीथब पर उपलब्ध कुछ कक्षाओं पर एक नज़र डालें।

इस वर्ग के साथ प्रश्न सम्मिलित करने का एक उदाहरण

$डेटा = ऐरे ("लॉगिन" => "एडमिन", "सक्रिय" => सत्य, "फर्स्टनाम" => "जॉन", "लास्टनाम" => "डो", "पासवर्ड" => $db->func( "SHA1(?)", ऐरे ("सीक्रेटपासवर्ड+नमक"), // पासवर्ड = SHA1("सीक्रेटपासवर्ड+नमक") "createdAt" => $db->now(), // createAt = NOW() " समाप्त हो रहा है" => $db->अभी("+1Y") // समाप्त हो रहा है = अभी() + अंतराल 1 वर्ष // समर्थित अंतराल [s]दूसरा, [m]inute, [h]घंटा, [d]दिन, [महीने वर्ष); $id = $db->insert('users', $data); यदि ($id) इको "उपयोगकर्ता बनाया गया था। Id="। $आईडी; अन्यथा प्रतिध्वनि "सम्मिलित विफल:"। $db->getLastError();