ทางเลือกสำหรับ mysql_real_escape_string โดยไม่ต้องเชื่อมต่อกับ DB


91

ฉันต้องการให้ฟังก์ชันทำงานเป็น mysql_real_escape_string โดยไม่ต้องเชื่อมต่อกับฐานข้อมูลในบางครั้งฉันต้องทำการทดสอบแบบแห้งโดยไม่ต้องเชื่อมต่อ DB mysql_escape_string เลิกใช้งานแล้วดังนั้นจึงไม่เป็นที่ต้องการ การค้นพบบางส่วนของฉัน:

http://www.gamedev.net/community/forums/topic.asp?topic_id=448909

http://w3schools.invisionzone.com/index.php?showtopic=20064



1
+1 ฉันกำลังเขียนคลาส MySQL ด้วยตัวเองและใช้ mysql_real_escape_string () เพื่อวัตถุประสงค์ในการผูกพารามิเตอร์ ฉันหลีกเลี่ยงการใช้ mysqli เนื่องจากโฮสติ้งไม่รองรับทั้งหมด ฉันยังหลีกเลี่ยงไลบรารีหลายไฟล์และหลายคลาส สิ่งที่ฉันต้องการมีเพียงคลาสเดียวที่เรียบร้อยและสะอาด ขอขอบคุณ!
เวียด

+1 ให้ด้วยครับ. กรณีการใช้งานของฉันคือ SugarCRM APi ที่ฉันต้องการพุชส่วนของ SQL ไปยังอินสแตนซ์ SugarCRM ระยะไกลผ่าน API น่ารังเกียจแม้ว่านั่นคือสิ่งที่ฉันต้องทำงานด้วย (ไปเคาะหัวนักพัฒนา SugarCRM ด้วยกัน) ฉันต้องการหลีกเลี่ยงสตริงใน SQL ในแอปพลิเคชันที่ใช้ API และแยกจากฐานข้อมูลที่อยู่เบื้องหลังอินสแตนซ์ SugarCRM โดยสิ้นเชิง
Jason

คำตอบ:


76

เป็นไปไม่ได้ที่จะหลบหนีสตริงอย่างปลอดภัยโดยไม่มีการเชื่อมต่อฐานข้อมูล mysql_real_escape_string()และคำสั่งที่เตรียมไว้จำเป็นต้องมีการเชื่อมต่อกับฐานข้อมูลเพื่อให้สามารถหลบหนีสตริงโดยใช้ชุดอักขระที่เหมาะสมมิฉะนั้นการโจมตีด้วยการฉีด SQL ยังคงเป็นไปได้โดยใช้อักขระแบบหลายไบต์

หากคุณกำลังทดสอบเท่านั้นคุณก็สามารถใช้ได้เช่นกันmysql_escape_string()ไม่รับประกัน 100% สำหรับการโจมตีด้วย SQL injection แต่เป็นไปไม่ได้ที่จะสร้างอะไรที่ปลอดภัยกว่านี้หากไม่มีการเชื่อมต่อ DB


1
+1 ขอบคุณสำหรับหมายเหตุ ฉันไม่ค่อยแน่ใจว่าจะทดสอบกับการโจมตีด้วยการฉีด SQL โดยใช้อักขระหลายไบต์ได้อย่างไร
เวียด

2
ฉันได้รับรหัสเก่าให้อัปเดต ใช้mysql_escape_stringโดยไม่ต้องเชื่อมต่อ (ยังคงพยายามหาสาเหตุอยู่) เนื่องจากฟังก์ชันนั้นเลิกใช้งานแล้วฉันแค่สงสัยว่าจะแทนที่ได้อย่างไร ดูเหมือนว่ามีเหตุผลอย่างแน่นอนที่สามารถระบุ "ชุดอักขระที่เหมาะสม" ในฟังก์ชันใดก็ได้แทนที่โดยไม่ต้องเปิดการเชื่อมต่อ
JohnK

3
เป็นไปไม่ได้? mysql_real_escape_string ได้อะไรจากการเชื่อมต่อฐานข้อมูลที่ไม่ใช่ข้อมูลการกำหนดค่าที่สามารถส่งผ่านด้วยมือไปยังฟังก์ชันที่เทียบเท่าได้ แก้ไข: อ่านด้านล่างมันเรียกใช้ฟังก์ชันไลบรารีภายใน MySQL ดังนั้นจึงมีการประมวลผลบางอย่างที่เกิดขึ้นนอก PHP มันอาจจะยังพกพาได้ แต่การทำให้ทันสมัยอยู่เสมอจะเป็นโปรเจ็กต์ในตัวเอง
Jason

2
จะเกิดอะไรขึ้นหากทราบชุดอักขระ DB ล่วงหน้า
jchook

7
ใช่ถ้าคุณรู้ชุดอักขระอะไรที่ป้องกันการหลบหนีโดยไม่มีการเชื่อมต่อ?
โยฮัน

67

ตามหน้าการอ้างอิงฟังก์ชันmysql_real_escape_string : "mysql_real_escape_string () เรียกฟังก์ชันไลบรารีของ MySQL mysql_real_escape_string ซึ่งจะหลีกเลี่ยงอักขระต่อไปนี้: \ x00, \ n, \ r, \, '," และ \ x1a "

ด้วยเหตุนี้ฟังก์ชันที่ระบุในลิงก์ที่สองที่คุณโพสต์ควรทำในสิ่งที่คุณต้องการ:

function mres($value)
{
    $search = array("\\",  "\x00", "\n",  "\r",  "'",  '"', "\x1a");
    $replace = array("\\\\","\\0","\\n", "\\r", "\'", '\"', "\\Z");

    return str_replace($search, $replace, $value);
}

6
ขอบคุณ. ฉันขอแนะนำอย่างอื่น: function escape ($ aQuery) {return strtr ($ aQuery, array ("\ x00" => '\ x00', "\ n" => '\ n', "\ r" => '\ r', '\\' => '\\\\', "'" => "\'", '"' => '\"', "\ x1a" => '\ x1a')) ; }
เวียด

1
ทำไม \ x1a ถูกแทนที่ด้วย \\\ x1a แทนที่จะเป็น \\ x1a? นี่คือการพิมพ์ผิด?
Michael Z

16
-1 สิ่งนี้อันตรายมาก หากการเชื่อมต่อฐานข้อมูลใช้ชุดอักขระแบบหลายไบต์การแทนที่ด้วยวิธีง่ายๆเช่นนี้อาจทำให้ข้อมูลเสียหายได้ (รวมถึงอักขระที่ใช้ Escape / quoting) ซึ่งผู้โจมตีประสงค์ร้ายอาจใช้ประโยชน์โดยเจตนาเพื่อฉีด SQL โดยพลการ
eggyal

หากคุณใส่ชุดอักขระผิดอาจเป็นอันตรายได้ สำหรับชุดอักขระแบบหลายไบต์หาก mysql กำลังใช้ใครบางคนสามารถใส่ไบต์เพื่อยกเลิก \\ ชุดอักขระหลายไบต์มักจะใช้อะไรก็ได้เป็นไบต์ที่สองรวมถึง \\ สำหรับ mysql จะไม่เห็นว่าเป็นแบบสแตนด์อโลน \\ แต่เป็นส่วนหนึ่งของอักขระแบบหลายไบต์ ฉันไม่รู้ว่าเกิดอะไรขึ้นกับ UTF8 ฉันหวังว่าจะมี [0xB0, '\\'] ที่เมื่อกดปุ่มไบต์ที่ไม่ถูกต้อง \\ ซึ่งจะหยุดและเริ่มต้นใหม่ด้วยไบต์นั้นแทนที่จะกลืนลงไป
jgmjgm

1
ถ้าฉันรู้ว่า charset เป็น utf8 จะปลอดภัยไหมที่จะใช้mb_strpos()(และmb_substr()สร้างพฤติกรรมที่คล้ายกับsubstr_replace()) เพื่อทำสิ่งนี้
SOFe

28

ตรงข้ามกับคำตอบอื่น ๆ ของฉันฟังก์ชันต่อไปนี้อาจปลอดภัยแม้ว่าจะมีอักขระแบบหลายไบต์ก็ตาม

// replace any non-ascii character with its hex code.
function escape($value) {
    $return = '';
    for($i = 0; $i < strlen($value); ++$i) {
        $char = $value[$i];
        $ord = ord($char);
        if($char !== "'" && $char !== "\"" && $char !== '\\' && $ord >= 32 && $ord <= 126)
            $return .= $char;
        else
            $return .= '\\x' . dechex($ord);
    }
    return $return;
}

ฉันหวังว่าจะมีคนที่มีความรู้มากกว่าตัวฉันสามารถบอกฉันได้ว่าทำไมโค้ดด้านบนถึงใช้ไม่ได้


+1 ขอบคุณสำหรับความพยายามพิเศษ ฉันจะไปหาข้อมูลเพิ่มเติมเกี่ยวกับการแทรก SQL แบบหลายไบต์
เวียด

ฉันเดาว่ามันควรจะเป็น $ return = '\ x' เดเชกซ์ ($ ord); แทน
เวียด

1
ตามกฎทั่วไปฉันชอบใช้ '\\' แม้ในสตริงที่มีเครื่องหมายอัญประกาศเดี่ยวเพียงเพราะ '\' ตัวเดียวอาจส่งผลต่ออักขระตัวถัดไปหากคุณไม่ระวัง ฉันอาจจะเป็น OCD อีกครั้ง
php มากเกินไป

1
ฟังก์ชันนี้ไม่เป็นไปตามกฎการหลีกเลี่ยง mysql และจะทำให้สูญเสียความสมบูรณ์ของข้อมูล "MySQL รู้จักลำดับการหลีกเลี่ยงที่แสดงในตารางที่ 9.1" ลำดับการหลบหนีของอักขระพิเศษ "สำหรับลำดับการหลบหนีอื่น ๆ ทั้งหมดเครื่องหมายแบ็กสแลชจะถูกละเว้นนั่นคืออักขระที่ใช้ Escape จะถูกตีความเหมือนกับว่าไม่มีการหลีกเลี่ยงตัวอย่างเช่น“ \ x” มีค่าแค่“ x” " - dev.mysql.com/doc/refman/5.6/en/…
velcrow

2
\ xAA มีความหมายมากกว่าข้อความ "xAA" ในตัวอักษรสตริง MySQL จริงหรือไม่? เอกสารประกอบดูเหมือนจะบอกว่า \ x ไม่มีความหมายพิเศษดังนั้น \ จะถูกละเว้น dev.mysql.com/doc/refman/5.0/en/string-literals.html
Jason

6

จากการวิจัยเพิ่มเติมฉันพบว่า:

http://dev.mysql.com/doc/refman/5.1/th/news-5-1-11.html

แก้ไขความปลอดภัย:

พบช่องโหว่ด้านความปลอดภัยการฉีด SQL ในการประมวลผลการเข้ารหัสแบบหลายไบต์ จุดบกพร่องอยู่ในเซิร์ฟเวอร์การแยกวิเคราะห์สตริงที่ไม่ถูกต้องที่ใช้ Escape ด้วยฟังก์ชัน mysql_real_escape_string () C API

ช่องโหว่นี้ถูกค้นพบและรายงานโดย Josh Berkus และ Tom Lane ซึ่งเป็นส่วนหนึ่งของความร่วมมือด้านความปลอดภัยระหว่างโครงการของกลุ่ม OSDB สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการแทรก SQL โปรดดูข้อความต่อไปนี้

อภิปรายผล. พบช่องโหว่ด้านความปลอดภัยการแทรก SQL ในการประมวลผลการเข้ารหัสแบบหลายไบต์ ช่องโหว่การรักษาความปลอดภัยการแทรก SQL อาจรวมถึงสถานการณ์ที่เมื่อผู้ใช้ให้ข้อมูลเพื่อแทรกลงในฐานข้อมูลผู้ใช้อาจฉีดคำสั่ง SQL ลงในข้อมูลที่เซิร์ฟเวอร์จะดำเนินการ สำหรับช่องโหว่นี้เมื่อมีการใช้การหลีกเลี่ยงการตั้งค่าอักขระโดยไม่รู้ตัว (ตัวอย่างเช่น addlashes () ใน PHP) จึงเป็นไปได้ที่จะข้ามการหลีกเลี่ยงในชุดอักขระแบบหลายไบต์ (เช่น SJIS, BIG5 และ GBK) ด้วยเหตุนี้ฟังก์ชันเช่น addlashes () จึงไม่สามารถป้องกันการโจมตีด้วย SQL-injection เป็นไปไม่ได้ที่จะแก้ไขปัญหานี้ในฝั่งเซิร์ฟเวอร์ ทางออกที่ดีที่สุดคือให้แอปพลิเคชันใช้การหลีกเลี่ยงการตั้งค่าอักขระที่เสนอโดยฟังก์ชันเช่น mysql_real_escape_string ()

อย่างไรก็ตามตรวจพบข้อบกพร่องในวิธีที่เซิร์ฟเวอร์ MySQL แยกวิเคราะห์ผลลัพธ์ของ mysql_real_escape_string () ด้วยเหตุนี้แม้ว่าจะมีการใช้ฟังก์ชันการตั้งค่าอักขระ mysql_real_escape_string () การแทรก SQL ก็เป็นไปได้ ข้อบกพร่องนี้ได้รับการแก้ไขแล้ว

วิธีแก้ปัญหา หากคุณไม่สามารถอัปเกรด MySQL เป็นเวอร์ชันที่มีการแก้ไขข้อบกพร่องในการแยกวิเคราะห์ mysql_real_escape_string () แต่เรียกใช้ MySQL 5.0.1 ขึ้นไปคุณสามารถใช้โหมด NO_BACKSLASH_ESCAPES SQL เป็นวิธีแก้ปัญหาได้ (โหมดนี้ถูกนำมาใช้ใน MySQL 5.0.1) NO_BACKSLASH_ESCAPES เปิดใช้งานโหมดความเข้ากันได้มาตรฐานของ SQL โดยที่แบ็กสแลชไม่ถือเป็นอักขระพิเศษ ผลลัพธ์ก็คือการสืบค้นจะล้มเหลว

ในการตั้งค่าโหมดนี้สำหรับการเชื่อมต่อปัจจุบันให้ป้อนคำสั่ง SQL ต่อไปนี้:

SET sql_mode='NO_BACKSLASH_ESCAPES';

คุณยังสามารถตั้งค่าโหมดทั่วโลกสำหรับไคลเอนต์ทั้งหมด:

SET GLOBAL sql_mode='NO_BACKSLASH_ESCAPES';

โหมด SQL นี้ยังสามารถเปิดใช้งานโดยอัตโนมัติเมื่อเซิร์ฟเวอร์เริ่มทำงานโดยใช้ตัวเลือกบรรทัดคำสั่ง --sql-mode = NO_BACKSLASH_ESCAPES หรือโดยการตั้งค่า sql-mode = NO_BACKSLASH_ESCAPES ในไฟล์ตัวเลือกเซิร์ฟเวอร์ (ตัวอย่างเช่น my.cnf หรือ my.ini ขึ้นอยู่กับระบบของคุณ) (ข้อบกพร่อง # 8378, CVE-2006-2753)

ดูข้อบกพร่อง # 8303 ด้วย


1
สิ่งนี้ได้รับการแก้ไขเมื่อนานมาแล้ว
สามัญสำนึกของคุณ

2
ระวังNO_BACKSLASH_ESCAPES ช่องโหว่อื่น ๆด้วย
eggyal

2
แก้ไขใน 5.1.11 - ลิงก์เสียนี่คือที่เก็บถาวร: web.archive.org/web/20120501203047/http://dev.mysql.com:80/doc/…
Bastion
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.