दिलचस्प पोस्ट
स्ट्रट्स टैग में #,% और $ के बीच अंतर क्या है? लिब निर्देशिका से जार फ़ाइलों को लोड करने का आदेश बाइट सरणी में परिवर्तित करें (जावा) अनुरोध डेटा खोए बिना ASP.NET MVC में रीडायरेक्ट टाईएक्शन कैसे करें पोस्ट पैरामीटर के रूप में jQuery भेजने स्ट्रिंग मैं "" "सिकलाइट में समस्या और सी # के आसपास कैसे प्राप्त करूं? मैं स्ट्रिंग दिनांक को NSDate में कैसे रूपांतरित कर सकता / सकती हूं? स्ट्रिंग को bool के साथ int को परिवर्तित करें / C ++ में विफल म्यूटक्स का उपयोग करते हुए एक आवेदन के सिंगल इंस्टेंस को चलाएं क्या मुझे 'एसिंक रिक्त' ईवेंट हैंडलर्स से बचना चाहिए? मेरे जीआईटी रेपो से अनरेन्फरड ब्लॉब्स कैसे निकालें I स्ट्रिंग में उपस्ट्रिंग की घटनाएं पायथन के साथ फॉर्म-डेटा पोस्ट करने के लिए मल्टीपार्ट पोस्टहोल्डर का उपयोग करना गंदा नाम से घोटाला नाम प्राप्त करना JSON स्ट्रिंग को जेएस ऑब्जेक्ट कन्वर्ट

पीडीओ और तैयार बयान के साथ mysql_ * फ़ंक्शन को बदलना

मैंने हमेशा mysql_connect का सरल कनेक्शन किया है, mysql_pconnect :

 $db = mysql_pconnect('*host*', '*user*', '*pass*'); if (!$db) { echo("<strong>Error:</strong> Could not connect to the database!"); exit; } mysql_select_db('*database*'); 

इस का उपयोग करते हुए मैंने एक क्वेरी बनाने से पहले हमेशा किसी भी डेटा से बचने के लिए सरल विधि का उपयोग किया है, चाहे वह INSERT , SELECT , UPDATE या mysql_real_escape_string का उपयोग करके DELETE

 $name = $_POST['name']; $name = mysql_real_escape_string($name); $sql = mysql_query("SELECT * FROM `users` WHERE (`name` = '$name')") or die(mysql_error()); 

अब मैं समझता हूं कि यह एक हद तक सुरक्षित है!

यह खतरनाक पात्रों से बच जाता है; हालांकि, यह अभी भी अन्य हमलों के लिए कमजोर है जो सुरक्षित वर्णों को शामिल कर सकते हैं, लेकिन डेटा को प्रदर्शित करने या कुछ मामलों में हानिकारक हो सकता है, डेटा को ख़राब तरीके से संशोधित या हटाया जा सकता है

इसलिए, मैंने थोड़ी सी खोज की और पीडीओ, मायसुकली और तैयार बयान के बारे में पता चला। हां, मैं खेल के लिए देर हो सकता है लेकिन मैंने कई, कई ट्यूटोरियल (टीआईजेग, डब्ल्यू .3 सी, ब्लॉग, गूगल सर्च्स) को पढ़ा है और इन्हें एक भी उल्लेख नहीं किया है। यह बहुत अजीब लगता है कि क्यों, उपयोगकर्ता इनपुट से बचने के लिए वास्तव में सुरक्षित नहीं है और कम से कम कहने के लिए अच्छा अभ्यास नहीं है हां, मुझे पता है कि आप इसे से निपटने के लिए रेगेक्स का उपयोग कर सकते हैं, लेकिन फिर भी, मुझे पूरा यकीन है कि यह पर्याप्त नहीं है?

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

अभी मैं समझता हूं कि पीडीओ का इस्तेमाल करते हुए अपने डाटाबेस से जुड़ने के लिए मैं इसका प्रयोग करूँगा

 $hostname = '*host*'; $username = '*user*'; $password = '*pass*'; $database = '*database*' $dbh = new PDO("mysql:host=$hostname;dbname=$database", $username, $password); if ($dbh) { echo 'Connected to database'; } else { echo 'Could not connect to database'; } 

अब, फ़ंक्शन के नाम अलग हैं इसलिए अब मेरी mysql_query , mysql_fetch_array , mysql_num_rows आदि काम नहीं करेगा। इसलिए मुझे नए लोगों को पढ़ना / याद रखना है, लेकिन यह वह जगह है जहां मुझे भ्रमित हो रहा है।

यदि मैं एक सम्मिलित / पंजीकरण प्रपत्र से डेटा सम्मिलित करना चाहता हूं, तो मैं इसे करने के बारे में कैसे जाना होगा लेकिन मुख्य रूप से मैं इसके बारे में सुरक्षित रूप से कैसे जाना होगा? मुझे लगता है कि यह वह जगह है जहां तैयार बयान आते हैं, लेकिन उनका उपयोग करके क्या यह mysql_real_escape_string जैसा कुछ उपयोग करने की आवश्यकता को समाप्त कर देता है? मुझे पता है कि mysql_real_escape_string लिए आपको mysql_connect / mysql_pconnect माध्यम से एक डाटाबेस से कनेक्ट होने की आवश्यकता है, इसलिए अब हम इसका उपयोग नहीं कर रहे हैं, यह फ़ंक्शन सिर्फ एक त्रुटि उत्पन्न करेगा?

मैंने पीडीओ विधि से भी अलग-अलग तरीकों से देखा है, उदाहरण के लिए, मैंने देखा है :variable और ? जैसा कि मुझे लगता है कि जगह धारकों के रूप में जाना जाता है (यदि यह गलत है)

लेकिन मुझे लगता है कि यह लगभग एक डाटाबेस से उपयोगकर्ता को लाने के लिए क्या किया जाना चाहिए, यह विचार है

 $user_id = $_GET['id']; // For example from a URL query string $stmt = $dbh->prepare("SELECT * FROM `users` WHERE `id` = :user_id"); $stmt->bindParam(':user_id', $user_id, PDO::PARAM_INT); 

लेकिन फिर मैं कुछ चीजों पर फँस गया हूँ, यदि चर एक संख्या नहीं थी और पाठ की एक स्ट्रिंग थी, तो आपको PDO:PARAM_STR बाद एक लंबाई PDO:PARAM_STR होगा PDO:PARAM_STR अगर मैं गलत नहीं हूँ लेकिन आप एक सेट लंबाई कैसे दे सकते हैं यदि आपको उपयोगकर्ता इन-पटल डेटा से दिए गए मूल्य पर निश्चित नहीं हैं, तो हर बार बदल सकते हैं? किसी भी तरह से, जहां तक ​​मैं आपको तब डेटा प्रदर्शित करना जानता हूं, तब आप करते हैं

 $stmt->execute(); $result = $stmt->fetchAll(); // Either foreach($result as $row) { echo $row['user_id'].'<br />'; echo $row['user_name'].'<br />'; echo $row['user_email']; } // Or foreach($result as $row) { $user_id = $row['user_id']; $user_name = $row['user_name']; $user_email = $row['user_email']; } echo("".$user_id."<br />".$user_name."<br />".$user_email.""); 

अब, क्या यह सब सुरक्षित है?

अगर मैं सही हूं, तो उदाहरण डालने के लिए डेटा डालना होगा:

  $username = $_POST['username']; $email = $_POST['email']; $stmt = $dbh->prepare("INSERT INTO `users` (username, email) VALUES (:username, :email)"); $stmt->bindParam(':username, $username, PDO::PARAM_STR, ?_LENGTH_?); $stmt->bindParam(':email, $email, PDO::PARAM_STR, ?_LENGTH_?); $stmt->execute(); 

क्या वह काम करेगा, और क्या यह भी सुरक्षित है? यदि यह सही है कि मैं ?_LENGTH_? लिए क्या मान ?_LENGTH_? ? क्या मुझे यह सब पूरी तरह से गलत है?

अद्यतन करें

मैंने जो उत्तर अभी तक किया है वह बेहद मददगार रहे हैं, आपको काफी लोग धन्यवाद नहीं दे सकते हैं! प्रत्येक व्यक्ति को थोड़ा अलग से कुछ करने के लिए अपनी आँख खोलने के लिए +1 मिला है शीर्ष उत्तर चुनना मुश्किल है, लेकिन मुझे लगता है कि कर्नल शापल को इसे योग्य माना जाता है क्योंकि सब कुछ बहुत अधिक कवर किया जाता है, यहां तक ​​कि कस्टम लाइब्रेरी के साथ अन्य एरे में भी जाना जाता है जिसे मुझे पता नहीं था!

लेकिन आप सभी के लिए धन्यवाद 🙂

वेब के समाधान से एकत्रित समाधान "पीडीओ और तैयार बयान के साथ mysql_ * फ़ंक्शन को बदलना"

दिलचस्प सवाल के लिए धन्यवाद हेयर यू गो:

यह खतरनाक पात्रों से बच जाता है,

आपकी अवधारणा पूरी तरह गलत है
वास्तव में "खतरनाक अक्षर" एक मिथक है, कोई भी नहीं है और mysql_real_escape_string से बचने पर केवल एक स्ट्रिंग सीमांकक इस परिभाषा से आप इसकी सीमाएं समाप्त कर सकते हैं – यह केवल तारों के लिए काम करता है

हालांकि, यह अभी भी अन्य हमलों के लिए कमजोर है जो सुरक्षित वर्णों को शामिल कर सकते हैं, लेकिन डेटा को प्रदर्शित करने या कुछ मामलों में हानिकारक हो सकता है, डेटा को ख़राब तरीके से संशोधित या हटाया जा सकता है

आप यहाँ सब कुछ मिश्रण कर रहे हैं
डेटाबेस के बोलते हुए,

  • तार के लिए यह कमजोर नहीं है जब तक आपके स्ट्रिंग उद्धृत और भाग जाए, वे "डेटा को बदनाम करने या हटाने" नहीं कर सकते हैं *
  • अन्य डेटा के लिए टाइप किया गया – हाँ, यह बेकार है । लेकिन इसलिए नहीं कि यह कुछ "असुरक्षित" है, लेकिन सिर्फ अनुचित उपयोग के कारण है।

प्रदर्शित आंकड़ों के लिए, मुझे लगता है कि यह पीडीओ से संबंधित प्रश्न में ऑफोपैक्ट है , क्योंकि पीडीओ का डेटा प्रदर्शित करने के साथ कुछ भी नहीं है

उपयोगकर्ता इनपुट से बचने

^^^ एक और भ्रम की बात है!

  • एक उपयोगकर्ता इनपुट को बचने के साथ पूरी तरह से कुछ नहीं करना है जैसा कि आप पूर्व परिभाषा से सीख सकते हैं, आपको स्ट्रिंग से बचना होगा, जो कुछ भी "उपयोगकर्ता इनपुट" नहीं है इसलिए फिर से:

    • आपके पास बचने के तार हैं, उनके स्रोत की कोई बात नहीं है
    • यह अन्य प्रकार के डेटा से बचने के लिए बेकार है, स्रोत की कोई बात नहीं।

बिंदु मिल गया?
अब, मुझे आशा है कि आप बचने और साथ ही "खतरनाक पात्रों" गलत धारणा की सीमाओं को समझते हैं।

यह मेरी समझ के लिए है कि पीडीओ / तैयार बयानों का उपयोग करना ज्यादा सुरक्षित है

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

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

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

जबकि तैयार बयान कवर – यूग – पूरे 2 अंक! अतिमहत्वपूर्ण 😉

अन्य 2 मुद्दों के लिए मेरे पहले जवाब देखें, PHP में जब डेटाबेस को स्ट्रिंग सबमिट करते हैं तो मुझे htmlspecialchars () का उपयोग करने वाले अवैध वर्णों का ध्यान रखना चाहिए या एक नियमित अभिव्यक्ति का उपयोग करना चाहिए?

अब, फ़ंक्शन के नाम अलग हैं इसलिए अब मेरी mysql_query, mysql_fetch_array, mysql_num_rows आदि काम नहीं करेगा।

यह एक अन्य, पीएचपी प्रयोक्ताओं , एक प्राकृतिक आपदा, एक विपत्ति की गंभीर भ्रम है :

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

वही PDO के लिए भी जाता है!

अब अपने प्रश्न के साथ फिर से।

लेकिन उनका उपयोग करके क्या यह mysql_real_escape_string जैसी चीज़ों का उपयोग करने की आवश्यकता को समाप्त कर सकता है?

हाँ।

लेकिन मुझे लगता है कि यह लगभग एक डाटाबेस से उपयोगकर्ता को लाने के लिए क्या किया जाना चाहिए, यह विचार है

लाने के लिए नहीं है, लेकिन क्वेरी के लिए कोई भी डेटा जोड़ने के लिए !

आपको PDO के बाद एक लंबाई दी जानी चाहिए: PARAM_STR अगर मैं गलत नहीं हूँ

आप कर सकते हैं, लेकिन आपको ऐसा करने की आवश्यकता नहीं है

अब, क्या यह सब सुरक्षित है?

डेटाबेस सुरक्षा के संदर्भ में इस कोड में केवल कोई कमजोर स्पॉट नहीं हैं I यहाँ सुरक्षित करने के लिए कुछ नहीं

प्रदर्शित सुरक्षा के लिए – बस इस साइट को XSS खोजशब्द के लिए खोजें

आशा है कि मैं इस मामले पर कुछ प्रकाश डाला

बीटीडब्लू, लंबे आवेषण के लिए आप फ़ंक्शन के कुछ उपयोग कर सकते हैं मैंने किसी दिन लिखा, पीडीओ का उपयोग कर सहायक फ़ंक्शन डालें / अपडेट करें

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

 $sql = 'SELECT * FROM `users` WHERE `name`=?s AND `type`=?s AND `active`=?i'; $data = $db->getRow($sql,$_GET['name'],'admin',1); 

लेकिन ज़ाहिर है कि आप तैयार कथनों का उपयोग करके एक ही कोड प्राप्त कर सकते हैं।


* (yes I am aware of the Schiflett's scaring tales)

मैं कभी बाँध परम () या परम प्रकार या लंबाई के साथ परेशान नहीं।

मैं सिर्फ पैरामीटर मानों की एक सरणी को निष्पादित (), इस तरह से पारित करता हूं:

 $stmt = $dbh->prepare("SELECT * FROM `users` WHERE `id` = :user_id"); $stmt->execute( array(':user_id' => $user_id) ); $stmt = $dbh->prepare("INSERT INTO `users` (username, email) VALUES (:username, :email)"); $stmt->execute( array(':username'=>$username, ':email'=>$email) ); 

यह बस के रूप में प्रभावी और आसान कोड है

आपको मेरी प्रस्तुति एसक्यूएल इंजेक्शन मिथ्स एंड फेलासीज या मेरी किताब एसक्यूएल एंटीपेटर्नेस में भी रुचि हो सकती है : डाटाबेस प्रोग्रामिंग के नुकसान से बचना

हां, कुछ PDO में एक नामित प्लेसहोल्डर है? एक अनाम प्लेसहोल्डर है वे आपको एक या एक से सभी मूल्यों को एक बार बाँध सकते हैं।

तो, मूल रूप से चार विकल्पों को आपकी क्वेरी को मूल्यों के साथ प्रदान करने में मदद मिलती है

बाइंड वैल्यू ( एक के साथ एक )

यह आपके प्लेसहोल्डर को जैसे ही आप इसे कहते हैं, उसके लिए एक ठोस मान को बांधता है। आप कड़ी मेहनत से कोडित स्ट्रिंग्स भी बाँध सकते हैं जैसे bindValue(':something', 'foo') यदि वांछित हो

एक पैरामीटर प्रकार प्रदान करना वैकल्पिक है (लेकिन सुझाया गया है)। हालांकि, जब से डिफ़ॉल्ट PDO::PARAM_STR , तब आपको इसे निर्दिष्ट करने की आवश्यकता होती है जब यह स्ट्रिंग नहीं है इसके अलावा, PDO यहां की लंबाई का ध्यान रखेगा – कोई लम्बाई पैरामीटर नहीं है

 $sql = ' SELECT * FROM `users` WHERE `name` LIKE :name AND `type` = :type AND `active` = :active '; $stm = $db->prepare($sql); $stm->bindValue(':name', $_GET['name']); // PDO::PARAM_STR is the default and can be omitted. $stm->bindValue(':type', 'admin'); // This is not possible with bindParam(). $stm->bindValue(':active', 1, PDO::PARAM_INT); $stm->execute(); ... 

मैं आमतौर पर इस दृष्टिकोण को पसंद करते हैं I मुझे यह सबसे साफ और सबसे अधिक लचीला लगता है

बाइंडपरम के साथ एक-एक करके ()

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

 $sql = 'SELECT * FROM `users` WHERE `id` = :id'; $stm = $db->prepare($sql); $id = 0; $stm->bindParam(':id', $id, PDO::PARAM_INT); $userids = array(2, 7, 8, 9, 10); foreach ($userids as $userid) { $id = $userid; $stm->execute(); ... } 

आप केवल एक बार तैयार करते हैं और बाँध करते हैं, जो कि सीपीयू चक्रों को सुरक्षित करता है। 🙂

सभी नामित प्लेसहोल्डर के साथ एक बार

आप केवल execute() करने के execute() एक सरणी में ड्रॉप करें execute() । आपकी कुंजी में प्रत्येक कुंजी एक नामित प्लेसहोल्डर है (देखें बिल कराविन्स का जवाब) सरणी का क्रम महत्वपूर्ण नहीं है।

एक तरफ ध्यान दें: इस दृष्टिकोण से आप पीडीओ को डेटा टाइप संकेतों (पीडीओ :: पैरामट आदि आदि) नहीं दे सकते। AFAIK, पीडीओ अनुमान लगाने की कोशिश करता है

सभी एक ही बार अनाम प्लेसहोल्डर के साथ

आप निष्पादित करने के लिए एक सरणी भी छोड़ते हैं, लेकिन यह संख्यात्मक रूप से अनुक्रमित है (कोई स्ट्रिंग कुंजी नहीं है)। मान आपके अनाम प्लेसहोल्डरों को आपके क्वेरी / अररे में दिखाई देने वाले क्रम में एक-एक करके प्रतिस्थापित करेगा – पहले एरेम मान पहले प्लेसहोल्डर को बदल देता है और आगे भी। Erm410 का उत्तर देखें

सरणी और नामित प्लेसहोल्डर के साथ, आप डेटा प्रकार संकेत नहीं दे सकते।

क्या वे आम में है

  • उन सभी के लिए आपको प्लेसहोल्डर के रूप में अधिक मूल्य देने / प्रदान करने की आवश्यकता होती है। यदि आप बहुत अधिक / कुछ बाध्य करते हैं, तो पीडीओ आपके बच्चे खाएंगे
  • आपको बचने के बारे में सावधानी बरतने की ज़रूरत नहीं है, पीडीओ इसे संभालता है। तैयार पीडीओ स्टेटमेंट एसक्यूएल इंजेक्शन डिजाइन द्वारा सुरक्षित हैं। हालांकि, यह exec () और क्वेरी () के लिए सही नहीं है – आपको सामान्यतः केवल उन दो हार्डकोड प्रश्नों के लिए उपयोग करना चाहिए।

यह भी ध्यान रखें कि पीडीओ अपवाद फेंकता है । वे उपयोगकर्ता को संभावित रूप से संवेदनशील जानकारी प्रकट कर सकते हैं। आपको अपने शुरुआती पीडीओ सेटअप को एक प्रयास / पकड़ ब्लॉक में डाल देना चाहिए!

यदि आप नहीं चाहते हैं कि अपवाद बाद में फेंक दें, तो आप त्रुटि मोड को चेतावनी के अनुसार सेट कर सकते हैं।

 try { $db = new PDO(...); $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING) } catch (PDOException $e) { echo 'Oops, something went wrong with the database connection.'; } 

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

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

 $id = '1; MALICIOUS second STATEMENT'; mysql_query("SELECT * FROM `users` WHERE `id` = $id"); /* selects user with id 1 and the executes the malicious second statement */ $stmt = $pdo->prepare("SELECT * FROM `users` WHERE `id` = ?") /* Tells DB to expect a single statement with a single parameter */ $stmt->execute(array($id)); /* selects user with id '1; MALICIOUS second STATEMENT' ie returns empty set. */ 

इस प्रकार, सुरक्षा के संदर्भ में, आपके ऊपर दिए गए उदाहरण ठीक लग रहे हैं।

अंत में, मैं सहमत हूं कि बाध्यकारी मापदंड अलग-अलग हैं और यह PDOStatement-> execute () () ( http://www.php.net/manual/en/pdostatement.execute.php देखें) के पास पारित एक सरणी के साथ प्रभावी ढंग से किया जाता है।