და ყველაზე ნაკლები დახმარება იქნება თქვენ მიერ შემუშავებული ფუნქციიდან. PHP: \"ციტატები\". Mysql მოთხოვნების წერა, სლეშები, ციტატების გაქცევა კოდში ძიება

ციტატების სტრიქონი (11)

ვცდილობ გავარკვიო კითხვების დაწერის საუკეთესო გზა. მე ასევე მესმის თანმიმდევრულობის მნიშვნელობა. აქამდე მე შემთხვევით ვიყენებდი ერთ ბრჭყალებს, ორმაგ ბრჭყალებსა და უკუღმა ყოველგვარი რეალური ფიქრის გარეშე.

$query = "ჩასმა ცხრილში (id, col1, col2) VALUES (NULL, val1, val2)";

ასევე, ზემოთ მოყვანილ მაგალითში გაითვალისწინეთ, რომ "ცვლადი", "col[n]" და "val[n]" შეიძლება იყოს ცვლადები.

რა არის ამის სტანდარტი? Რას აკეთებ?

დაახლოებით 20 წუთია ვკითხულობ მსგავს კითხვებზე პასუხებს, მაგრამ ამ კითხვაზე საბოლოო პასუხი არ ჩანს.

პასუხები

ახლა დავუშვათ, რომ იყენებთ პირდაპირ პოსტის ცვლადს MySQL შეკითხვაში, შემდეგ გამოიყენეთ იგი ასე:

$query = "ჩასმა `ცხრილში` (`id`, `სახელი`, `ელფოსტა`) VALUES (" ".$_POST["id"]." ", " ".$_POST["name"]." ", " ".$_POST["ელფოსტა"].." ")";

ეს არის საუკეთესო პრაქტიკა MySQL-ში PHP ცვლადების გამოსაყენებლად.

ძირითადად Mysql-ში, ამ ტიპის იდენტიფიკატორები გამოიყენება ` , " , " და () შეკითხვებში.

    " ან " გამოიყენეთ სტრიქონის ჩასართავად, როგორც მნიშვნელობა "01/26/2014 00:00:00" ან "01/26/2014 00:00:00" . ეს იდენტიფიკატორი გამოიყენება მხოლოდ "01/26/2014 00:00:00" სიმებიანი ფუნქციისთვის, როგორიცაა now() ან sum ,max .

    ` გამოიყენეთ ცხრილის ან ცხრილის ცხრილის დასამატებლად, მაგ. აირჩიეთ სვეტის_სახელი ცხრილის_სახელიდან, სადაც id = "2"

    () გამოიყენება მხოლოდ მოთხოვნის ნაწილების უბრალოდ ჩასართავად, მაგალითად, აირჩიეთ სვეტის_სახელი ცხრილის_სახელიდან, სადაც (id = "2" და სქესი = "მამრობითი") ან სახელი = "რაკეში".

ყველა (კარგად ახსნილი) პასუხის გარდა, ქვემოთ არცერთი არ იყო ნახსენები და მე ხშირად მოვდივარ ამ კითხვა-პასუხზე.

Მოკლედ; MySQL ფიქრობს, რომ გინდა მათემატიკასაკუთარ მაგიდაზე/სვეტზე და დეფისების ინტერპრეტაცია, როგორიცაა "ელ.ფოსტა", როგორც ელფოსტა.

პასუხისმგებლობის უარყოფა.ამიტომ ვიფიქრე, რომ დავამატო ეს, როგორც "FYI" პასუხი მათთვის, ვინც სრულიად ახალია მონაცემთა ბაზებთან მუშაობაში და ვისაც შეიძლება არ ესმოდეს უკვე აღწერილი ტექნიკური ტერმინები.

(ზემოთ არის კარგი პასუხები თქვენი შეკითხვის SQL ბუნებასთან დაკავშირებით, მაგრამ ეს ასევე შეიძლება იყოს შესაბამისი, თუ თქვენ ახალი ხართ PHP-ში.)

შეიძლება მნიშვნელოვანი იყოს იმის აღნიშვნა, რომ PHP განსხვავებულად ეპყრობა ერთ და ორმაგ ციტატებს...

ერთციტირებული სტრიქონები არის „ლიტერატურული“ და საკმაოდ ბევრი WYSIWYG სტრიქონებია. ორმაგი ციტირებული სტრიქონები ინტერპრეტირებულია PHP-ის მიერ ცვლადის შესაძლო ჩანაცვლებისთვის (PHP-ში უკანა მითითებები არ არის ზუსტად სტრიქონები, ისინი ასრულებენ ბრძანებას shell-ში და აბრუნებენ შედეგს).

$foo = "ბარი"; echo "არსებობს $foo"; // არსებობს $foo echo "არსებობს $foo"; // არის ბარი ექო `ls -l`; // ... დირექტორია სია

თუ cols ცხრილები და მნიშვნელობები ცვლადებია, მაშინ არსებობს ორი გზა:

ორმაგი ბრჭყალებით "" სრული მოთხოვნაა:

$query = "INSERT INTO $table_name (id, $col1, $col2) VALUES (NULL, "$val1", "$val2")";

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

ერთი ბრჭყალებით "" :

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

გამოიყენეთ backticks ``, როდესაც სვეტის/მნიშვნელობის სახელი მსგავსია MySQL რეზერვირებული საკვანძო სიტყვის.

Შენიშვნა.თუ თქვენ მიუთითებთ სვეტის სახელს ცხრილის სახელთან ერთად, გამოიყენეთ უკუსვლები, როგორიცაა:

`მაგიდის_სახელი`. `სვეტის_სახელი`<- Примечание: исключить. из задних клещей.

Backtick უნდა იყოს გამოყენებული ცხრილისა და სვეტის იდენტიფიკატორებისთვის, მაგრამ საჭიროა მხოლოდ მაშინ, როდესაც იდენტიფიკატორი არის MySQL რეზერვირებული საკვანძო სიტყვა ან როდესაც იდენტიფიკატორი შეიცავს სივრცეში სიმბოლოებს ან სიმბოლოებს შეზღუდული ნაკრების მიღმა (იხ. ქვემოთ). ხშირად რეკომენდირებულია, რომ თავიდან აიცილოთ დაჯავშნილი საკვანძო სიტყვები სვეტების ან ცხრილების იდენტიფიკატორად, თუ ეს შესაძლებელია, რათა თავიდან აიცილოთ ციტატების პრობლემა.

ერთი ბრჭყალები უნდა იყოს გამოყენებული სტრიქონების მნიშვნელობებისთვის, როგორიცაა VALUES() სიაში. ორმაგი ბრჭყალები მხარდაჭერილია MySQL-ის მიერ სიმებიანი მნიშვნელობებისთვისაც, მაგრამ ცალკეული ბრჭყალები უფრო ფართოდ არის მიღებული სხვა RDBMS-ების მიერ, ამიტომ კარგი იდეაა ორმაგი ბრჭყალების ნაცვლად გამოიყენოთ ერთჯერადი ბრჭყალები.

MySQL ასევე მოელის, რომ DATE და DATETIME ლიტერალური მნიშვნელობები იყოს ერთჯერადი ციტირებით, როგორც სტრიქონები, როგორიცაა "2001-01-01 00:00:00". დამატებითი ინფორმაციისთვის იხილეთ თარიღისა და დროის ლიტერატურის დოკუმენტაცია, განსაკუთრებით დეფისის გამოყენების ალტერნატივები - როგორც სეგმენტის გამყოფი თარიღის სტრიქონებში.

ასე რომ, თქვენი მაგალითის გამოყენებით, მე გავაორმაგებდი PHP სტრიქონს და გამოვიყენებდი ერთ ბრჭყალებს "val1", "val2" მნიშვნელობებისთვის. NULL არის MySQL საკვანძო სიტყვა და არამნიშვნელოვანი და ამიტომ არ გამოიყენება.

არცერთი ამ ცხრილის ან სვეტის იდენტიფიკატორი არ არის დაჯავშნილი სიტყვა ან არ იყენებს სიმბოლოებს, რომლებიც საჭიროებენ ციტირებას, მაგრამ მე ისინი მაინც უკუღმა ციტირებით (დაწვრილებით ამის შესახებ მოგვიანებით...).

RDBMS-თან დაკავშირებული ფუნქციები (როგორიცაა NOW() MySQL-ში) არ უნდა იყოს ციტირებული, თუმცა მათი არგუმენტები ექვემდებარება იგივე წესებს ან ციტირების წესებს, რომლებიც უკვე აღინიშნა.

Backtick(`) ცხრილი და სვეტი ┬──── ┬──┬───────┐ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓↓ ჩასმა `ცხრილში` (`id`, `col1`, `col2`, `თარიღი`, `განახლებულია`) ღირებულებები (NULL, "val1", "val2", "2001-01-01", NOW())"; ციტირებული საკვანძო სიტყვა ─────┴┴┴┘ │ │ │ │ │ │ │││││ ცალციტირებული (") სტრიქონები ─││ ─ ───┴── ┴────┘ │ │ │││││ ერთ ციტირებული (") თარიღი ───── ─ ───┴── არაციტირებული ფუნქცია ────────────────────────── ─────── ──┴┴┴┴┘

ცვლადი ინტერპოლაცია

ცვლადების ციტირების შაბლონები არ იცვლება, თუმცა თუ თქვენ აპირებთ ცვლადების ინტერპოლაციას პირდაპირ სტრიქონში, ის ორმაგად უნდა იყოს ციტირებული PHP-ში. უბრალოდ დარწმუნდით, რომ სწორად გაქცევთ ცვლადებს SQL-ში გამოსაყენებლად. (რეკომენდებულია გამოიყენოთ API, რომელიც მხარს უჭერს მომზადებულ განცხადებებს, როგორც დაცვა SQL ინექციისგან.)

// იგივეა ზოგიერთი ცვლადის ჩანაცვლებით // აქ, ცვლადის ცხრილის სახელი $table არის ციტირებული უკან და ცვლადები // VALUES სიაში არის ერთ ციტირებული $query = "INSERT INTO `$მაგიდა`(`id`, `col1`, `col2`, `თარიღი`) VALUES (NULL, "$val1", "$val2", "$date")";

მომზადებული განცხადებები

მომზადებულ განცხადებებთან მუშაობისას, გაეცანით დოკუმენტაციას, რათა დაადგინოთ, უნდა იყოს თუ არა განცხადების შემავსებლები. მოიცავს ყველაზე პოპულარულ API-ებს, რომლებიც ხელმისაწვდომია PHP, PDO და MySQLi უნებართვოჩანაცვლების ადგილები, ისევე როგორც სხვა ენებზე მომზადებული ინსტრუქციის API-ები:

// PDO მაგალითი დასახელებული პარამეტრებით, unquoted $query = "INSERT INTO `table` (`id`, `col1`, `col2`, `date`) VALUES (:id, :col1, :col2, :date)" ; // MySQLi მაგალითი ? პარამეტრები, unquoted $query = "INSERT INTO `table` (`id`, `col1`, `col2`, `date`) VALUES (?, ?, ?, ?)";

სიმბოლოები, რომლებიც აბრუნებენ უკან მითითებას იდენტიფიკატორებში:

Მაგალითად:

იგივე შეიძლება გაკეთდეს ცხრილების სახელებისა და ველების სახელებისთვის. ეს ძალიან კარგი ჩვევათუ თქვენ დააკავშირებთ თქვენს მონაცემთა ბაზის ID-ს უკანა ფანჯრებთან.

შეამოწმეთ ეს პასუხი, რომ გაიგოთ მეტი საპირისპირო დასკვნების შესახებ.

ახლა ორმაგი ციტატებისა და ერთჯერადი ციტატების შესახებ (მაიკლმა უკვე ახსენა ეს).

მაგრამ მნიშვნელობის დასადგენად, თქვენ უნდა გამოიყენოთ ერთჯერადი ან ორმაგი ბრჭყალები. ვნახოთ სხვა მაგალითი.

INSERT INTO `tablename` (`id, `title`) VALUES (NULL, title1);

აქ შეგნებულად დამავიწყდა სათაურის 1 ბრჭყალებში გადატანა. სერვერი ახლა მიიღებს title1-ს, როგორც სვეტის სახელს (ანუ იდენტიფიკატორს). ასე რომ, რომ მიუთითოთ, რომ ეს არის მნიშვნელობა, თქვენ უნდა გამოიყენოთ ორმაგი ან ერთჯერადი ბრჭყალები.

INSERT INTO `tablename` (`id, `title`) VALUES (NULL, "title1");

ახლა, PHP-თან ერთად, ორმაგი ბრჭყალები და ერთჯერადი ციტატები აადვილებს შეკითხვის დაწერას. მოდით შევხედოთ შეკითხვის შეცვლილ ვერსიას თქვენს შეკითხვაში.

$query = "ჩასმა `ცხრილში` (`id`, `col1`, `col2`) VALUES (NULL, "$val1", "$val2"");

ახლა, ორმაგი ციტატების გამოყენებით PHP-ში, თქვენ აიძულებთ ცვლადებს $val1 და $val2 გამოიყენონ თავიანთი მნიშვნელობები, რითაც შექმნით მოქმედ მოთხოვნას. მოსწონს

$val1 = "ჩემი ღირებულება 1"; $val2 = "ჩემი ღირებულება 2"; $query = "ჩასმა `ცხრილში` (`id`, `col1`, `col2`) VALUES (NULL, "$val1", "$val2"");

ჩასმა `ცხრილში` (`id`, `col1`, `col2`) მნიშვნელობები (NULL, „ჩემი მნიშვნელობა 1“, „ჩემი მნიშვნელობა 2“)

აქ ბევრი გამოსადეგი პასუხი იყო, რომელიც ძირითადად ორ პუნქტში მთავრდება.

  1. BACKTICKS (`) გამოიყენება იდენტიფიკატორის სახელების გარშემო.
  2. ერთჯერადი ციტატები (") გამოიყენება მნიშვნელობების გარშემო.

და როგორც @MichaelBerkowski თქვა

Backtick უნდა იყოს გამოყენებული ცხრილისა და სვეტის იდენტიფიკატორებისთვის, მაგრამ საჭიროა მხოლოდ მაშინ, როდესაც იდენტიფიკატორი არის MySQL რეზერვირებული საკვანძო სიტყვა ან როდესაც იდენტიფიკატორი შეიცავს სივრცეში სიმბოლოებს ან სიმბოლოებს შეზღუდული ნაკრების მიღმა (იხ. ქვემოთ). ხშირად რეკომენდირებულია, რომ თავიდან აიცილოთ დაჯავშნილი საკვანძო სიტყვები სვეტების ან ცხრილების იდენტიფიკატორად, თუ ეს შესაძლებელია, რათა თავიდან აიცილოთ ციტატების პრობლემა.

არის შემთხვევა, როდესაც იდენტიფიკატორი არ შეიძლება იყოს დაცული საკვანძო სიტყვაან შეიცავს სივრცის სიმბოლოებიან სიმბოლოები შეზღუდული ნაკრების მიღმამაგრამ აუცილებლად მოითხოვენ backlinks მათ გარშემო.

123E10 არის სწორი იდენტიფიკატორის სახელი, მაგრამ ასევე სწორი INTEGER ლიტერალი.

[დაწვრილებითი ინფორმაციის გარეშე როგორ მიიღებდით მსგავს id სახელს] ვთქვათ, მინდა შევქმნა დროებითი ცხრილი სახელად 123456e6.

არ არის ERROR ზურგზე.

DB > შექმნა დროებითი ცხრილი `123456e6` (`id` char (8)); მოთხოვნა კარგია, 0 მწკრივი დაზარალდა (0,03 წმ)

შეცდომა, თუ არ იყენებთ გამოძახებას.

DB > შექმნა დროებითი ცხრილი 123451e6 (`id` char (8)); ERROR 1064 (42000): თქვენ გაქვთ შეცდომა თქვენს SQL სინტაქსში; შეამოწმეთ სახელმძღვანელო, რომელიც შეესაბამება თქვენი MariaDB სერვერის ვერსიას, რომ გამოიყენოთ სწორი სინტაქსი "123451e6 (`id` char (8))" სტრიქონზე 1-ში.

თუმცა, 123451a6 არის კარგი ID სახელი (უკუჩვენებების გარეშე).

DB > შექმნა დროებითი ცხრილი 123451a6 (`id` char (8)); მოთხოვნა კარგია, 0 მწკრივი დაზარალდა (0,03 წმ)

ეს მთლიანად იმიტომ ხდება, რომ 1234156e6 ასევე ექსპონენციალური რიცხვია.

ერთი ბრჭყალები უნდა იყოს გამოყენებული სტრიქონების მნიშვნელობებისთვის, როგორიცაა VALUES() სიაში.

Backtick ჩვეულებრივ გამოიყენება იდენტიფიკატორის აღსანიშნავად და ასევე შეიძლება იყოს უსაფრთხო რეზერვირებული საკვანძო სიტყვების დროდადრო გამოყენების გამო.

PHP-თან და MySQL-თან შერწყმისას, ორმაგი ციტატები და ერთჯერადი ციტატები მნიშვნელოვნად ამარტივებს შეკითხვის დაწერის დროს.

MySQL-ში ციტატების ორი ტიპი არსებობს:

  1. " სტრიქონების ლიტერალების ჩათვლით
  2. ` შეიცავდეს იდენტიფიკატორებს, როგორიცაა ცხრილების და სვეტების სახელები

და შემდეგ არის "ეს განსაკუთრებული შემთხვევაა. მისი გამოყენება შესაძლებელია ერთიზემოაღნიშნული მიზნებიდან ერთ დროს დამოკიდებულია სერვერის sql_mode-ზე:

  1. ნაგულისხმევი"პერსონაჟი" შეიძლება გამოყენებულ იქნას სტრიქონების ლიტერალების დასაბუდებლად "
  2. ANSI_QUOTES რეჟიმში " სიმბოლო შეიძლება გამოყენებულ იქნას იდენტიფიკატორების დასამატებლად, ANSI_QUOTES

შემდეგი მოთხოვნა გამოიმუშავებს სხვადასხვა შედეგებს (ან შეცდომებს) SQL რეჟიმის მიხედვით:

აირჩიეთ "სვეტი" ცხრილიდან WHERE foo = "ზოლი"

ANSI_QUOTES გამორთულია

შეკითხვა შეარჩევს სტრიქონის სიტყვასიტყვით "სვეტი", სადაც სვეტი foo ტოლია სტრიქონის "ზოლი"

ჩართულია ANSI_QUOTES

შეკითხვა შეარჩევს სვეტის სვეტს, სადაც სვეტი foo უდრის სვეტს

როდის გამოვიყენოთ

  • გირჩევთ, მოერიდოთ "-ს გამოყენებას, რათა თქვენი კოდი არ იყოს დამოკიდებული SQL რეჟიმებზე
  • ყოველთვის ჩართეთ იდენტიფიკატორები, რადგან ეს კარგი პრაქტიკაა (საკმაოდ რამდენიმე კითხვა SO-ზე განიხილავს ამას)

აშკარა განსხვავებაა " " და " " გამოყენებას შორის .

როდესაც " " გამოიყენება მთელს ტერიტორიაზე, არ არსებობს "ტრანსფორმაცია ან თარგმანი". იბეჭდება როგორც არის.

" "-ით, რასაც გარს აკრავს, "ითარგმნება ან გარდაიქმნება" მის მნიშვნელობად.

რას ვგულისხმობ თარგმანში/კონვერტაციაში არის ეს: ყველაფერი, რაც შეიცავს ერთ ბრჭყალებში, არ "ითარგმნება" მათ მნიშვნელობებზე. ისინი მიიღება, რადგან ისინი ციტატების შიგნით არიან. მაგალითი: a=23, შემდეგ "$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, \n, \r, \ , " , " და \x1a.

ეს ფუნქცია ყოველთვის (რამდენიმე გამონაკლისების გარდა) უნდა იყოს გამოყენებული მონაცემების უსაფრთხოების მიზნით MySQL-ში მოთხოვნის გაგზავნამდე.

Სიფრთხილით

უსაფრთხოება: ნაგულისხმევი სიმბოლოების ნაკრები

სიმბოლოების ნაკრები უნდა იყოს მითითებული ან სერვერის დონეზე, ან API ფუნქციით mysql_set_charset()რომ გავლენა მოახდინოს mysql_real_escape_string() . დამატებითი ინფორმაციისთვის იხილეთ ცნებების განყოფილება პერსონაჟების ნაკრების შესახებ.

Პარამეტრები

unescaped_string

სტრიქონი, რომელიც უნდა გაექცეს.

ბმული_იდენტიფიკატორი

MySQL კავშირი. თუ ბმულის იდენტიფიკატორი არ არის მითითებული, ბოლო ბმული გაიხსნა mysql_connect ()ვარაუდობენ. თუ ასეთი ბმული ვერ მოიძებნა, ის შეეცდება შექმნას თითქოს mysql_connect ()დაურეკეს ყოველგვარი არგუმენტის გარეშე. თუ კავშირი არ არის ნაპოვნი ან დამყარებული, ან E_გაფრთხილებაწარმოიქმნება დონის შეცდომა.

დაბრუნების ღირებულებები

აბრუნებს გამოტოვებულ სტრიქონს, ან ცრუშეცდომაზე.

შეცდომები/გამონაკლისები

ამ ფუნქციის შესრულება MySQL კავშირის გარეშე ასევე გამოსცემს E_გაფრთხილებადონის PHP შეცდომები. შეასრულეთ ეს ფუნქცია მხოლოდ მოქმედი MySQL კავშირით.

მაგალითები

მაგალითი #1 მარტივი mysql_real_escape_string() მაგალითი

//დაკავშირება
$link = mysql_connect("mysql_host" , "mysql_user" , "mysql_password" )
ან die(mysql_error());

//კითხვა
$query = sprintf ( "SELECT * FROM users WHERE user="%s" AND password="%s"",
mysql_real_escape_string ($user),
mysql_real_escape_string($პაროლი));
?>

მაგალითი #2 mysql_real_escape_string() მოითხოვს კავშირის მაგალითს

ეს მაგალითი გვიჩვენებს, თუ რა მოხდება, თუ MySQL კავშირი არ არის ამ ფუნქციის გამოძახებისას.

ზემოთ მოყვანილი მაგალითი გამოვა მსგავსი რამ:

გაფრთხილება: mysql_real_escape_string(): არ არსებობს ასეთი ფაილი ან დირექტორია /this/test/script.php მე-5 ხაზზე გაფრთხილება: mysql_real_escape_string(): სერვერის ბმული ვერ შეიქმნა /this/test/script.php 5 ხაზზე. bool(false) string(41) "SELECT * FROM actors WHERE last_name = """

მაგალითი #3 მაგალითი SQL Injection Attack

// ჩვენ არ შევამოწმეთ $_POST["პაროლი"], ეს შეიძლება იყოს ის, რაც მომხმარებელს სურდა! მაგალითად:
$_POST [ "username" ] = "aidan" ;
$_POST [ "პაროლი" ] = "" ან ""="" ;

// შეკითხვის მონაცემთა ბაზა, რათა შეამოწმოთ არის თუ არა შესაბამისი მომხმარებლები
$query = ( $_POST [ "username" ]) "AND password=" ($_POST ["პაროლი" ]) "" ;
mysql_query ($query);

// ეს ნიშნავს, რომ MySQL-ში გაგზავნილი შეკითხვა იქნება:
echo $query ;
?>

MySQL-ში გაგზავნილი შეკითხვა:

ეს საშუალებას მისცემს ნებისმიერს შევიდეს სისტემაში სწორი პაროლის გარეშე.

შენიშვნები

გამოყენებამდე საჭიროა MySQL კავშირი mysql_real_escape_string() წინააღმდეგ შემთხვევაში დონის შეცდომა E_გაფრთხილებაწარმოიქმნება და ცრუუბრუნდება. თუ link_identifier არ არის განსაზღვრული, გამოიყენება ბოლო MySQL კავშირი.

შენიშვნა: mysql_real_escape_string() არ გაქცევა % და _ . ეს არის ველური ბარათები MySQL-ში, თუ ერთად არის LIKE, გრანტი, ან გაუქმება.

8 წლის წინ

მხოლოდ პატარა ფუნქცია, რომელიც მიბაძავს ორიგინალურ mysql_real_escape_string-ს, მაგრამ რომელსაც არ სჭირდება აქტიური mysql კავშირი. შეიძლება განხორციელდეს როგორც სტატიკური ფუნქცია მონაცემთა ბაზის კლასში. იმედია ვინმეს დაეხმარება.

ფუნქცია mysql_escape_mimic ($inp) (
if(is_array ($inp))
დაბრუნება array_map (__METHOD__ , $inp );

თუ(! ცარიელი ($inp ) && არის_სტრიქონი ($inp )) (
return str_replace (array("\\" , "\0" , "\n" , "\r" , """ , """ , "\x1a" ), array("\\\\" , "\ \0" , "\\n" , "\\r", "\\"", "\\"", "\\Z" ), $inp );
}

დაბრუნება $inp ;
}
?>

13 წლის წინ

გაითვალისწინეთ, რომ mysql_real_escape_string არ ამაგრებს უკანა ხაზებს \x00, \n, \r და \x1a, როგორც ეს ნახსენებია დოკუმენტაციაში, მაგრამ რეალურად ანაცვლებს სიმბოლოს MySQL მისაღები წარმომადგენლობით შეკითხვებისთვის (მაგ. \n შეიცვლება "\"-ით. n" ლიტერალური). (\, ", და " გამოტოვებულია დოკუმენტურად) ეს არ ცვლის, როგორ უნდა გამოიყენოთ ეს ფუნქცია, მაგრამ ვფიქრობ, კარგია იცოდეთ.

6 წლის წინ

გაქცევის დისკუსია არ არის დასრულებული ისე, რომ ყველას არ უთხრათ, რომ თქვენ, ძირითადად, არასოდეს უნდა გამოიყენოთ გარე შეყვანა ინტერპრეტაციული კოდის შესაქმნელად. ეს ეხება SQL განცხადებებს, ან ნებისმიერ რამეს, რომელსაც დაარქმევთ რაიმე სახის "eval" ფუნქციას.

ასე რომ, ამ საშინლად გატეხილი ფუნქციის გამოყენების ნაცვლად, გამოიყენეთ პარამეტრულად მომზადებული განცხადებები.

გულწრფელად რომ ვთქვათ, მომხმარებლის მიერ მოწოდებული მონაცემების გამოყენება SQL განცხადებების შედგენისთვის უნდა ჩაითვალოს პროფესიულ დაუდევრობად და თქვენ უნდა აგოთ პასუხისმგებლობა თქვენი დამსაქმებლის ან კლიენტის მიერ პარამეტრულად მომზადებული განცხადებების გამოუყენებლობის გამო.

Ეს რას ნიშნავს?

ეს ნიშნავს, რომ ნაცვლად SQL განცხადების აგების შემდეგ:

"INSERT INTO X (A) VALUES(".$_POST["a"].)"

თქვენ უნდა გამოიყენოთ mysqli's prede() ფუნქცია () ასეთი განცხადების შესასრულებლად:

"ჩასმა X (A) მნიშვნელობებში(?)"

შენიშვნა: ეს არ ნიშნავს, რომ თქვენ არასოდეს არ უნდა გენერირებათ დინამიური SQL განცხადებები. ეს ნიშნავს, რომ თქვენ არასოდეს არ უნდა გამოიყენოთ მომხმარებლის მიერ მოწოდებული მონაცემები ამ განცხადებების გენერირებისთვის. მომხმარებლის მიერ მოწოდებული ნებისმიერი მონაცემი უნდა გადაეცეს როგორც პარამეტრებს განცხადებაში მისი მიღების შემდეგ. მომზადდა.

ასე რომ, მაგალითად, თუ თქვენ ქმნით პატარა ჩარჩოს და გსურთ ჩასვათ ცხრილში მოთხოვნის URI-ზე დაფუძნებული, თქვენს ინტერესებშია არ მიიღოთ $_SERVER["REQUEST_URI"] მნიშვნელობა (ან ნებისმიერი მისი ნაწილი) და პირდაპირ შეუერთეთ თქვენს მოთხოვნას. ამის ნაცვლად, თქვენ უნდა გააანალიზოთ თქვენთვის სასურველი $_SERVER["REQUEST_URI"] მნიშვნელობის ნაწილი და მიაწოდოთ ეს რაიმე სახის ფუნქციის ან ასოციაციური მასივის მეშვეობით არამომხმარებელზე. მოწოდებული მნიშვნელობა. თუ რუქა არ იძლევა მნიშვნელობას, თქვენ იცით, რომ რაღაც არასწორია მომხმარებლის მიერ მოწოდებულ მონაცემებში.

ამის შეუსრულებლობა გახდა SQL-ის ინექციის მრავალი პრობლემის მიზეზი Ruby On Rails ჩარჩოში, მიუხედავად იმისა, რომ ის იყენებს პარამეტრულ მომზადებულ განცხადებებს. ასე გატეხეს GitHub ერთ მომენტში. ასე რომ, არც ერთი ენა არ არის დაცული ამ პრობლემისგან. ამიტომ ეს არის ზოგადი საუკეთესო პრაქტიკა და არა რაღაც სპეციფიკური PHP-სთვის და რატომ უნდა მიიღოთ ის ნამდვილად.

ასევე, თქვენ მაინც უნდა გააკეთოთ მომხმარებელთა მიერ მოწოდებული მონაცემების გარკვეული სახის დამოწმება, თუნდაც პარამეტრულად მომზადებული განცხადებების გამოყენებისას. ეს იმიტომ ხდება, რომ მომხმარებლის მიერ მოწოდებული მონაცემები ხშირად გახდება ზოგიერთი გენერირებული HTML-ის ნაწილი და გსურთ დარწმუნდეთ, რომ მომხმარებლის მიერ მოწოდებული მონაცემები არ გამოიწვევს უსაფრთხოების პრობლემებს ბრაუზერში.

9 წლის წინ

არის საინტერესო უცნაურობა მაგალითში #2 SQL ინექციის შესახებ: AND იკავებს პრიორიტეტს OR-ზე, ასე რომ, შეყვანილი მოთხოვნა რეალურად შესრულდება როგორც WHERE (user = "aidan" AND პაროლი = "") OR ""="", ასე რომ, ამის ნაცვლად. თვითნებური მომხმარებლის სახელის შესაბამისი მონაცემთა ბაზის ჩანაწერის დაბრუნებისას (ამ შემთხვევაში "aidan"), ის რეალურად დააბრუნებს მონაცემთა ბაზის ყველა ჩანაწერს. განსაკუთრებული თანმიმდევრობით. ასე რომ, თავდამსხმელს შეუძლია შესვლა, როგორც ნებისმიერი ანგარიში, მაგრამ არა აუცილებლად ნებისმიერი ანგარიშით. აკონტროლეთ რომელი ანგარიშია.

რა თქმა უნდა, თავდასხმის პოტენციურს შეუძლია უბრალოდ შეცვალოს მათი პარამეტრები, რათა მიზანმიმართული იყოს კონკრეტული მომხმარებლების ინტერესი:

//Მაგალითად. თავდამსხმელის ღირებულებები
$_POST [ "username" ] = "" ;
$_POST ["პაროლი"] = "" ან მომხმარებელი = "ადმინისტრატორი" და "" = "";

// არასწორად ფორმირებული შეკითხვა
$query = "SELECT * FROM users WHERE user="$_POST [ მომხმარებლის სახელი ] " და პაროლი = " $_POST [ პაროლი ] " " ;

echo $query ;

// MySQL-ზე გაგზავნილი შეკითხვა წაიკითხავს:
// SELECT * FROM users WHERE user="" AND password="" OR user="administrator" AND ""="";
// რაც საშუალებას მისცემს ნებისმიერს, მოიპოვოს წვდომა ანგარიშზე სახელად "ადმინისტრატორი"

?>

1 წლის წინ

@feedr
მისი შენიშვნა შემდეგნაირად ჩამოვაყალიბე:
$string = "asda\0sd\x1aas\\\\\\\\dasd\"asdasd\na\"\"sdasdad";
$array1 = მასივი("\\\\\\\\", "\0", "\n", "\r", """, """, "\x1a");
$ array2 = მასივი ("\\\\\\\\\\\\\\\\\", "\\\0", "\\\n", "\\\r", "\\\ " ", "\\\"", "\\\Z");
echo ($string);
ექო (PHP_EOL);
for($i=0; $i თუ ($i==0)
$p = "/(?სხვა
$p = "/(?ექო ($i);
ექო ($p);
ექო ($მასივი2[$i]);
$string = preg_replace($p, $array2[$i], $string);
echo ("\t");
echo ($string);
ექო (PHP_EOL);
}
ექო (PHP_EOL);
echo ($string);

2 წლის წინ

სემის ციტირება Numb Safari-ზე

[ "გაქცევის განხილვა არ არის დასრულებული ისე, რომ ყველას არ უთხრათ, რომ თქვენ, ძირითადად, არასდროს არ უნდა გამოიყენოთ გარე შეყვანა ინტერპრეტირებული კოდის შესაქმნელად. ეს ეხება SQL განცხადებებს, ან ნებისმიერ რამეს, რომელსაც დაარქმევთ რაიმე სახის "eval" ფუნქციას.

ასე რომ, ამ საშინლად გატეხილი ფუნქციის გამოყენების ნაცვლად, გამოიყენეთ პარამეტრულად მომზადებული განცხადებები.

გულწრფელად რომ ვთქვათ, მომხმარებლის მიერ მოწოდებული მონაცემების გამოყენება SQL განცხადებების შედგენისთვის უნდა ჩაითვალოს პროფესიონალურ დაუდევრობად და თქვენ უნდა აგოთ პასუხისმგებლობა თქვენი დამსაქმებლის ან კლიენტის მიერ პარამეტრულად მომზადებული განცხადებების გამოუყენებლობის გამო." ]

სემი მართალია.........

თუმცა არ მიმაჩნია მიზანშეწონილად შეწყვიტოს ყოველგვარი გაწმენდა და უბრალოდ დავალება გადავიდეს პარამეტრულად მომზადებულ განცხადებებზე.

კონკრეტულ სიტუაციაში მომუშავე კონკრეტული დეველოპერი ყოველთვის გაიგებს მეტი ვალიდური შეყვანის შესახებ (ამ კონტექსტისთვის სპეციფიკური).

თუ თქვენ სთხოვთ მომხმარებელს გადასცეს მნიშვნელობა, რომელიც უკვე მიეცით მას და იცით, რომ ყველა ასეთი მნიშვნელობა იწყება AB****** და სტრიქონი უნდა იყოს 7 ან 11 სიგრძის, მაგრამ არასდროს სხვა სიგრძის, მაშინ თქვენ გაქვთ კარგი წინასწარი გამწმენდის საფუძველი - სტრიქონის სხვადასხვა დასაშვები სიგრძე შეიძლება მიუთითებდეს მემკვიდრეობით მონაცემებზე.

მე არასოდეს მსურს უბრალოდ გადავიტანო ის ნაგავი, რომელიც შესაძლოა ბოროტმა მომხმარებელმა გადასცეს ფორმის საშუალებით პარამეტრულ მომზადებულ განცხადებებს, მე ყოველთვის მინდა გავაკეთო ჩემი საკუთარი საღი აზრის შემოწმებები პირველ რიგში და ზოგიერთ შემთხვევაში ეს შეიძლება შეცდეს სიფრთხილით და უბრალოდ აირჩიეთ მონაცემთა ბაზის მოქმედების მთლიანად შეწყვეტა.

ამგვარად, ჩემი DB არ იკეტება უსაფრთხო განცხადებებით - ის უბრალოდ არ იკეტება, რაც უკეთესია.

უსაფრთხოება ფენებში - გაწმენდა და ვალიდაცია მაინც უნდა იყოს გათვალისწინებული ყველა სიტუაციაში მომზადებული განცხადებების გამოყენებამდე.

გარდა ამისა, რამდენადაც მე შემიძლია წავიკითხო ოფიციალურ დოკუმენტში
==============================================

"გაქცევა და SQL ინექცია

შეკრული ცვლადები იგზავნება სერვერზე მოთხოვნისაგან განცალკევებით და, შესაბამისად, ვერ შეუშლის ხელს მას. სერვერი იყენებს ამ მნიშვნელობებს უშუალოდ შესრულების ადგილზე, განცხადების შაბლონის გაანალიზების შემდეგ. შეკრულ პარამეტრებს არ სჭირდება გაქცევა, რადგან ისინი არასოდეს ჩანაცვლდება უშუალოდ მოთხოვნის სტრიქონში"

ეს მიგვანიშნებს, რომ საშიშროების თავიდან აცილება ხდება შინაგანში ალტერნატიული მოპყრობით და არა გაუქმებით.

ეს ნიშნავს, რომ დიდმა პროექტმა არასრული კონვერტაციით მომზადებულ განცხადებებზე, მემკვიდრეობითი კოდით ორგანიზაციის სხვადასხვა ნაწილში ან სერვერებზე, რომლებიც ესაუბრებიან ერთმანეთს, ამან შეიძლება გადასცეს ცუდი ამბავი იმუნური მდებარეობიდან ან სიტუაციიდან ისეთზე, რომელიც არ არის იმუნური.

სანამ გაწმენდა კომპეტენტურად შესრულდება დამატებითი რისკების გაჩენის გარეშე, მაშინ მე პირადად მე დავიცავდი სანიტარიის გარკვეულ ფენებს და შემდეგ გამოვიძახებ მომზადებულ განცხადებებს.


პირველ რიგში, ცოტა იმაზე, თუ რატომ არის საჭირო ზოგადად ეს დახრილები.
თუ რაიმე მონაცემს შევცვლით შეკითხვაში, მაშინ იმისათვის, რომ ეს მონაცემები განვასხვავოთ SQL ბრძანებებისგან, ისინი უნდა განთავსდეს ბრჭყალებში.
მაგალითად, თუ წერთ
აირჩიეთ * ცხრილიდან WHERE სახელი = ბილ
შემდეგ მონაცემთა ბაზა გადაწყვეტს, რომ Bill არის სხვა ველის სახელი, ვერ იპოვის და დაუშვებს შეცდომას. ამიტომ, ჩანაცვლებული მონაცემები (ამ შემთხვევაში, სახელი Bill) უნდა იყოს ჩასმული ბრჭყალებში - შემდეგ მონაცემთა ბაზა ჩათვლის მას სტრიქონად, რომლის მნიშვნელობა უნდა მიენიჭოს სახელის ველს:
აირჩიეთ * ცხრილიდან WHERE name = "Bill"
თუმცა, ციტატები შეიძლება ასევე გამოჩნდეს თავად მონაცემებში. Მაგალითად,
აირჩიეთ * ცხრილიდან WHERE name = "D"Artagnan"
აქ მონაცემთა ბაზა გადაწყვეტს, რომ "D" არის მონაცემები, ხოლო Artagnan არის ბრძანება, რომელიც მან არ იცის და ასევე დაუშვებს შეცდომას. აქედან გამომდინარე, აუცილებელია ყველა მონაცემის მიკვლევა, რათა აუხსნას მონაცემთა ბაზას, რომ მათში ნაპოვნი ციტატები (და სხვა სპეციალური სიმბოლოები) ეხება მონაცემებს.
შედეგად, ჩვენ მივიღებთ სწორ მოთხოვნას, რომელიც არ გამოიწვევს შეცდომებს:
აირჩიეთ * ცხრილიდან WHERE name = "D\"Artagnan"

ამრიგად, ჩვენ გავარკვიეთ, რომ სტრიქონის მონაცემების მოთხოვნაში ჩანაცვლებისას უნდა დაიცვან ორი წესი:
- ყველა ჩასმული სტრიქონის მონაცემი უნდა იყოს ჩასმული ბრჭყალებში (ერთჯერადი ან ორმაგი, მაგრამ ერთჯერადი უფრო მოსახერხებელია და უფრო ხშირად გამოიყენება).
- სპეციალური სიმბოლოების გაქცევა უნდა მოხდეს დახრილობით.

საგანგებოდ უნდა აღინიშნოს: დამატებული შტრიხები არ შედის მონაცემთა ბაზაში. ისინი მხოლოდ მოთხოვნაშია საჭირო. ძირზე დარტყმისას, დახრილები იშლება. შესაბამისად, გავრცელებული შეცდომაა მონაცემთა ბაზიდან ამოღებისას stripslashes გამოყენება.

ყოველივე ზემოთქმული ეხება სტრიქონების მონაცემებსა და თარიღებს. რიცხვები შეიძლება ჩასმული იყოს უკიდეგანოდ ან შემოიფარგლოს ბრჭყალებით. თუ ამას გააკეთებ მაშინ აუცილებლად!აიძულეთ მონაცემები სასურველ ტიპზე, სანამ არ ჩაწერთ მას შეკითხვაში, მაგალითად:
$id = intval ($id);
თუმცა, სიმარტივისთვის (და საიმედოობისთვის), შეგიძლიათ იმუშაოთ რიცხვებთან, ისევე როგორც სტრიქონებთან (რადგან mysql მაინც აკონვერტებს მათ სასურველ ტიპზე). შესაბამისად, ჩვენ დავაკვირდებით მოთხოვნაში ჩადებულ ნებისმიერ მონაცემს და ჩავსვამთ მას ბრჭყალებში.

ასევე, არსებობს კიდევ ერთი წესი - სურვილისამებრ, მაგრამ ის უნდა დაიცვას შეცდომების თავიდან ასაცილებლად:
ველების და ცხრილების სახელები უნდა იყოს ჩასმული ცალ ბრჭყალებში - "`" (ამ სიმბოლოს მქონე კლავიატურა მდებარეობს სტანდარტულ კლავიატურაზე "1" კლავიშის მარცხნივ). ბოლოს და ბოლოს, ველის სახელი შეიძლება ემთხვეოდეს mysql-ს. საკვანძო სიტყვები, მაგრამ თუ გამოვიყენებთ უკანა ციტატას, მაშინ MySQL მიხვდება, რომ ყველაფერი სწორია:
SELECT * FROM `table` WHERE `date` = "2006-04-04"
თქვენ უნდა განასხვავოთ ეს ბრჭყალები და არ აურიოთ ერთი მეორეში. ასევე უნდა გახსოვდეთ, რომ უკანა ნაწილს არ აცილებს ხაზები.

ასე რომ, ჩვენ ვისწავლეთ, თუ როგორ სწორად ჩავანაცვლოთ მონაცემები მოთხოვნაში.
მაგრამ! დინამიური შეკითხვის კონსტრუქცია არ შემოიფარგლება მონაცემთა ჩანაცვლებით. ხშირად ჩვენ გვიწევს SQL ბრძანებების და ველების სახელების ჩანაცვლება მოთხოვნაში. და აქ გადავდივართ უსაფრთხოების თემაზე:

SQL Injection არის ჰაკერული თავდასხმის მეთოდი, როდესაც სკრიპტზე გადაცემული მონაცემები მოდიფიცირებულია ისე, რომ ამ სკრიპტში გენერირებული მოთხოვნა იწყებს სრულიად განსხვავებულის შესრულებას, რისთვისაც იყო განკუთვნილი.
ასეთი თავდასხმებისგან დაცვის წესები შეიძლება დაიყოს ორ პუნქტად:
1. მონაცემებთან მუშაობა.
2. მუშაობა შეკითხვის კონტროლებთან.

პირველი პუნქტი დეტალურად განვიხილეთ ზემოთ. შეიძლება ითქვას, რომ ეს, ფაქტობრივად, დაცვა არ არის. მოთხოვნაზე მონაცემების დამატების წესებთან შესაბამისობა ნაკარნახევია, პირველ რიგში, SQL SYNTAX-ის მოთხოვნებით. და როგორც გვერდითი ეფექტი, ჩვენ ასევე გვაქვს დაცვა ჰაკერებისგან.

მეორე პუნქტი ბევრად უფრო რთულია, რადგან არ არსებობს ერთი უნივერსალური წესი, რაც შეეხება მონაცემებს - უკუსვლა არ დაიცავს ველის სახელს ჰაკერის მიერ შეცვლილისაგან. შეუძლებელია ციტატების გამოყენება ცხრილების სახელების, SQL განცხადებების, LIMIT ბრძანების პარამეტრების და სხვა განცხადებების დასაცავად.
ამიტომ, საკონტროლო ელემენტების მოთხოვნაში ჩანაცვლების ძირითადი წესია:
თუ თქვენ გჭირდებათ დინამიურად ჩასვათ SQL განცხადებები ან ველების, მონაცემთა ბაზების, ცხრილების სახელები მოთხოვნაში, მაშინ არავითარ შემთხვევაში არ უნდა ჩადოთ ისინი პირდაპირ მოთხოვნაში.
ასეთი დამატებების ყველა ვარიანტი უნდა იყოს ჩაწერილი ADVANCE თქვენს სკრიპტში და არჩეული იყოს მომხმარებლის მიერ შეყვანილი მომხმარებლის მიხედვით.
მაგალითად, თუ თქვენ გჭირდებათ ოპერატორის მიერ შეკვეთის ველის სახელის გადაცემა, მაშინ არავითარ შემთხვევაში არ უნდა შეცვალოთ იგი პირდაპირ. ჯერ უნდა შევამოწმოთ. მაგალითად, შექმენით მოქმედი მნიშვნელობების მასივი და შეცვალეთ იგი მოთხოვნაში მხოლოდ იმ შემთხვევაში, თუ გადაცემული პარამეტრი არის ამ მასივში:
$orders =array("სახელი" , "ფასი" , "რაოდენობა" );
$key = მასივის_ძიება ($_GET["დახარისხება"], $orders));
$orderby = $orders [ $key ];
$query = "არჩევა * FROM `table` ORDER BY$orderby " ;

მომხმარებლის მიერ შეყვანილი სიტყვის წინასწარ აღწერილი ვარიანტების მასივში ვეძებთ და თუ ვიპოვით, ვირჩევთ მასივის შესაბამის ელემენტს. თუ შესატყვისი ვერ მოიძებნა, მასივის პირველი ელემენტი შეირჩევა.
ამრიგად, ის, რაც ჩანაცვლებულია მოთხოვნაში, არის არა ის, რაც შეიყვანა მომხმარებელმა, არამედ ის, რაც ეწერა ჩვენს სკრიპტში.
იგივე უნდა გაკეთდეს ყველა სხვა შემთხვევაში.
მაგალითად, თუ WHERE პუნქტი დინამიურად გენერირებულია:
if (! ცარიელი ($_GET [ "ფასი" ])) $where .= "price="" . mysql_real_escape_string ($_GET ["ფასი"]). """ ;
$query = "SELECT * FROM `table` WHERE $where " ;

ჩემთვის ძნელი წარმოსადგენია შემთხვევა, როდესაც ცხრილის სახელი შეიძლება შევიდეს მოთხოვნაში დინამიურად, მაგრამ თუ ეს მოხდება, მაშინ სახელი ასევე უნდა ჩასვა მხოლოდ სკრიპტში წინასწარ განსაზღვრული ნაკრებიდან.
LIMIT ოპერატორის პარამეტრები იძულებული უნდა იყოს მთელი რიცხვის ტიპზე არითმეტიკული ოპერაციების ან intval() ფუნქციის გამოყენებით.
არ იფიქროთ, რომ აქ ჩამოთვლილი მაგალითები ამოწურავს დინამიური შეკითხვის კონსტრუქციის ყველა ვარიანტს. თქვენ უბრალოდ უნდა გაიგოთ პრინციპი და გამოიყენოთ იგი ყველა ასეთ შემთხვევაში.

ჩემი მუშაობის ბუნებიდან გამომდინარე, მე უნდა ჩავატარო ვებ აპლიკაციების წყაროს კოდის უსაფრთხოების აუდიტი.
ბევრი ვებ აპლიკაცია და ბევრი კოდი...

საიდუმლო არ არის, რომ SQL ინექციის ხარვეზები ყველაზე გავრცელებულია სერვერის მხარეს ვებ აპლიკაციის დაუცველობათაგან. არის პლატფორმები და ჩარჩოები, სადაც მსგავსი რამ თითქმის მთლიანად გამორიცხულია, მაგალითად ORM და ა.შ. მაგრამ სტატისტიკა დაჟინებით გვამცნობს ვებ აპლიკაციების აბსოლუტურ უპირატესობაზე მარტივი თანმიმდევრული SQL მოთხოვნებით ინტერნეტში. გარდა ამისა, არის შემთხვევები, როდესაც ORM არის ზოგადად გამოიყენება, მაგალითად, არ შეიძლება, როდესაც არა მხოლოდ გამონათქვამების პარამეტრები, არამედ თავად შეკითხვის ლოგიკა ოპერატორის დონეზე უნდა იყოს დამოკიდებული მომხმარებლის მონაცემებზე.

მაშ ასე, დავიწყოთ.

უსარგებლო პერსონაჟის გაქცევა
ნაპოვნია PHP ვებ აპლიკაციების 83%-ში, რომლებიც დაუცველია SQL ინექციების მიმართ
გაქცევის ფუნქციის გამოყენება ისეთი სიმბოლოებისთვის, როგორიცაა
mysql_escape_string
mysql_real_escape_string
დამატებები
ბრჭყალების გარეშე. ყველაზე ხშირად ის ვლინდება რიცხვითი პარამეტრებით (ყველა სახის *_id).
მაგალითი
$sql = " აირჩიეთ მომხმარებელი მომხმარებლის სიიდან WHERE userid=".mysql_real_escape_string($_GET["uid"]);

როგორც ჩანს, ეს არის უსაფრთხო კოდი, მაგრამ მხოლოდ ზედაპირზე. SQL ინექციების ყველაზე გავრცელებული ნიმუში PHP-ში ჩემს პრაქტიკაში შემოიჭრა აქ. ამ დაუცველობაზე თავდასხმისთვის, თავდამსხმელმა უბრალოდ უნდა მოერიდოს " " \x00 \r \n \x1a სიმბოლოების გამოყენებას თავდასხმის ვექტორში.
Მაგალითად:
/index.php?uid=-777 UNION SELECT პაროლი მომხმარებლის სიიდან

მოძებნე კოდში
ენის სემანტიკით გართულებულია. მარტივი საძიებლად შეგიძლიათ გამოიყენოთ egrep:
egrep -Rin "(არჩევა|განახლება|ჩასმა|წაშლა|ჩანაცვლება).*(from|set|into).*(mysql_escape_string|mysql_real_escape_string|addslashes)" . | grep -v "[\""]["\"]"

საძიებო გამოხატვის ლოგიკა ასეთია: იპოვნეთ ყველა სტრიქონი, რომლებშიც არ არის ციტირების სიმბოლოების თანმიმდევრობა ("", "", "", "") ფილტრაციის ფუნქციების მარცხნივ. მეთოდი, რა თქმა უნდა, შორს არის 100%-დან, მაგრამ სემანტიკური ანალიზის ჩასატარებლად შეუძლებელია რეგულარული გამოხატვის მოთხოვნა.
ინფორმაციის ჩვენების გასაადვილებლად, შეგიძლიათ კონსოლში მონიშნოთ ფუნქცია ფერად:
egrep -Rin "(არჩევა|განახლება|ჩასმა|წაშლა|ჩანაცვლება).*(from|set|into).*(mysql_escape_string|mysql_real_escape_string|addslashes)" . | grep -v "[\""]["\"]" | egrep --color "(mysql_escape_string|mysql_real_escape_string|addslashes)"

ამ სიმბოლოს დაუცველობისგან დასაცავად, უმჯობესია გამოიყენოთ ტიპის კასტინგი.
ეს ყოველთვის უფრო სწრაფად მუშაობს და უფრო საიმედოა, ვიდრე ყველა სახის ფილტრაცია და სკრინინგი.
ზემოთ მოყვანილი მაგალითისთვის, პატჩი შეიძლება იყოს ასეთი:
$sql = " აირჩიეთ მომხმარებელი მომხმარებლის სიიდან WHERE userid=".intval($_GET["uid"]);

ამით მთავრდება მოკლე ესსე. მე მოვუწოდებ ყველა ვებ დეველოპერს, შეეცადონ შეამოწმონ თავიანთი წყაროები ასეთი დიზაინისთვის. კიდევ უკეთესი, გააფართოვოთ მოცემული საძიებო სკრიპტი ხალხისთვის.

ასე რომ, ძირითადად, ღრმად ჩავუღრმავდი MySQL-ისა და PHP-ის სფეროებს... კონკრეტულად უსაფრთხოების ზომები, რომლებიც უნდა მივიღო მონაცემთა ბაზასთან და ფორმულის შეყვანის დროს. აქამდე მივხვდი, რომ შემდეგი რეკომენდირებულია:

  1. მომზადებული განცხადებები
  2. გამოყენებით _real_escape_string()
  3. არ იყენებთ ჯადოსნურ ციტატებს, რადგან ის აბნევს მონაცემთა ბაზებს და მთავრდება ისეთ რაღაცეებს, როგორიცაა "შენ არ დაუძახე...".

ეს ყველაფერი მშვენიერია და მე ამას ვაკვირდები. თუმცა, მაინტერესებდა, უნდა გავექცე ისეთ სიმბოლოებს, როგორიცაა დოლარის ნიშანი [$], პროცენტის ნიშანი [%] და შესაძლოა სხვა. შესაძლოა შეკითხვამ დოლარის ნიშანი PHP ცვლადის სახით განმარტა? რაც შეეხება LIKE სინტაქსს, რომელიც მე გამიგია, იყენებს % სიმბოლოს ან თუნდაც ველურ ბარათს? მომზადებული განცხადებები ტექნიკურად უნდა ზრუნავდეს ამ ყველაფერზე, მაგრამ მე უბრალოდ მინდოდა ვყოფილიყავი უსაფრთხო მხარეზე და დავრწმუნებულიყავი, რომ ყველაფერი სწორად დავფარე. იმ შემთხვევებში, როდესაც მავიწყდება მომზადებული განცხადებების გამოყენება ან უბრალოდ უგულებელყოფს მათ, ვიმედოვნებდი, რომ დაცვის ეს მეორე ხაზი მეუბნებოდა, რომ თავბრუსხვევისგან თავის დაღწევა შემეძლო.

აი რას ვიყენებ ამჟამად გასაქცევად:

ფუნქცია escape($connection, $data)($new_data = trim($data); $new_data = i_real_escape_string($connection, $new_data); $new_data = addcslashes ($new_data, "%_$"); $new_data = htmlspecialchars ($new_data, ENT_NOQUOTES); დააბრუნეთ $new_data;)

მაშ ეს სწორია? რამეს საშინლად არასწორად ვაკეთებ? გთხოვთ გაითვალისწინოთ, რომ მონაცემთა ბაზის მონაცემების დაბრუნებისას მომიწევს $,% და _ სიმბოლოების წინ უკანა ხაზების ამოღება.

რამეს საშინლად არასწორად ვაკეთებ?

პირველ რიგში თქვენი კვლევის შესახებ.

მომზადებული განცხადებები - ერთადერთიმშვენიერი რამ იპოვე.

მიუხედავად იმისა, რომ mysqli_real_escape_string-ის გამოყენება (თუ ვივარაუდებთ, რომ თქვენ იყენებთ მომზადებულ განცხადებებს) იქნება უსარგებლო და მავნე(შექმნით შედეგს, რომელიც თქვენ თავად აღნიშნეთ: "შენ დარეკე არ არის...").

და ჯადოსნური ციტატები დიდი ხანია ამოღებულია ენიდან - ამდენად, ნამდვილად არ ღირს.

ასე რომ, თქვენი თავდაპირველი ნაგებობების უმეტესობაც კი აშკარად არასწორია.

ახლა შენს კითხვაზე.

შესაძლოა შეკითხვამ დოლარის ნიშანი PHP ცვლადის სახით განმარტა?

რაც შეეხება LIKE სინტაქსს, რომელიც მე გამიგია, იყენებს % სიმბოლოს ან თუნდაც ველურ ბარათს?

დიახ, სწორად გსმენიათ. LIKE ოპერატორის ზუსტი მიზანია განახორციელოს ნიმუშის ძებნა. ამ სიმბოლოების LIKE-ში გამორთვა ოდნავი აზრი არ ექნება.

ყოველთვის, როცა აპირებთ LIKE ოპერატორის გამოყენებას, უნდა გადაწყვიტოთ რომელი კონკრეტული სიმბოლო გამოიყენოთ და რომელი აკრძალოთ. თქვენ არ შეგიძლიათ გამოიყენოთ ერთჯერადი გადაწყვეტა. რომ აღარაფერი ვთქვათ, რომ ყველა სხვა mysql ინტერაქციაში % ნიშანს განსაკუთრებული მნიშვნელობა არ აქვს.

მომზადებულმა განცხადებებმა ტექნიკურად უნდა იზრუნოს ამ ყველაფერზე

მომზადებულ განცხადებებს არაფერი აქვს საერთო $ ან % ნიშანთან. მომზადებული განცხადებები ეხება SQL ინექციას, მაგრამ ვერც ერთი სიმბოლო არ შეიძლება გამოიწვიოს („ინექციას“ ვერ უწოდებთ სწორად გამოყენებულ LIKE ოპერატორს, არა?).

და ბოლოს, ყველაზე უარესი ნაწილი.

თუ დაგავიწყდათ მომზადებული განცხადებების გამოყენება ან უბრალოდ უგულებელყოფთ მათ შესრულებას,

არაფერი გიშველის.

და ყველაზე ნაკლები დახმარება იქნება თქვენ მიერ შემუშავებული ფუნქციიდან.

შეაჯამეთ.

  1. მოიშორეთ ეს ფუნქცია.
  2. გამოყენება შემავსებლები *თითოეული ინდივიდუალური ცვლადის წარმოსაჩენად მოთხოვნაში.
  3. Escape % და _ სიმბოლოების შეყვანაში მხოლოდ იმ შემთხვევაში, თუ ისინი გამოყენებული იქნება LIKE ოპერატორში და არ გსურთ მათი ინტერპრეტაცია.
  4. გამოსასვლელად გამოიყენეთ htmlspecialchars() და არა mysql შეყვანისთვის.

* წაიკითხეთ მომზადებული განცხადებები, თუ ეს ტერმინი თქვენთვის უცნობია.

თქვენ არ უნდა მოერიდოთ დოლარის ნიშანს. MySQL კონკრეტულად არ უყურებს ამ სიმბოლოს და PHP ცნობს მას მხოლოდ წყაროს კოდით და არა სტრიქონების მნიშვნელობებში (თუ არ დაუძახებთ eval-ს სტრიქონზე, მაგრამ ეს არის ჭიების სულ სხვა ჭია).

თქვენ დაგჭირდებათ მხოლოდ % და _-დან გაქცევა, თუ იყენებდით მომხმარებლის შეყვანას LIKE არგუმენტად და არ გინდოდათ, რომ მომხმარებელს შეეძლოს ველური ბარათების გამოყენება. ეს შეიძლება მოხდეს, თუ თქვენ ამუშავებთ საძიებო ფორმას. თქვენ არ გჭირდებათ მისი გამოყენება მონაცემთა ბაზაში შენახვისას.

მონაცემთა ბაზაში წვდომისას არ გჭირდებათ htmlspecialchars-ის გამოყენება. ეს უნდა იყოს გამოყენებული მხოლოდ მომხმარებლისთვის მონაცემების ჩვენებისას HTML გვერდზე XSS ინექციის თავიდან ასაცილებლად.

იმის მიხედვით, თუ რა მონაცემები და რისთვის გამოიყენება.

თუ აღმოაჩენთ, რომ PHP-ის ნაგულისხმევი განცხადებები ძალიან დიდი და რთულია, გირჩევთ გადახედოთ github-ზე არსებულ ზოგიერთ კლასს, რათა წარმოდგენა მოგცეთ გამარტივებული მოთხოვნების შესახებ.

ამ კლასში მოთხოვნების ჩასმის მაგალითი

$data = მასივი ("login" => "admin", "active" => true, "firstName" => "John", "lastName" => "Doe", "password" => $db->func( "SHA1(?)", მასივი ("საიდუმლო პაროლი+მარილი")), // პაროლი = SHA1("საიდუმლო პაროლი+მარილი") "createdAt" => $db->now(), // createAt = NOW() " ამოიწურება" => $db->ახლა ("+1Y") // ამოიწურება = NOW() + ინტერვალი 1 წელი // მხარდაჭერილი ინტერვალები [წ] წამი, [მ] წუთი, [სთ] საათი, [დ] დღე, [Თვე წელი); $id = $db->insert("მომხმარებლები", $data); if ($id) echo "user შეიქმნა. Id=" . $id; else echo "ჩასმა ვერ მოხერხდა: " . $db->getLastError();