การฉีด SQL จากการ์ตูน "Bobby Tables" XKCD ทำงานอย่างไร


1093

แค่มองไปที่:

XKCD Strip (ที่มา: https://xkcd.com/327/ )

SQL นี้ทำอะไร:

Robert'); DROP TABLE STUDENTS; --

ฉันรู้ว่าทั้งสอง'และ--สำหรับความคิดเห็น แต่คำไม่DROPได้รับความเห็นเช่นกันเพราะมันเป็นส่วนหนึ่งของบรรทัดเดียวกันหรือไม่


16
หากคุณฟังPodcast Stack Overflow # 31 (27 พฤศจิกายน 2008) พวกเขาจะพูดถึงเรื่องนี้
EBGreen

93
ใน MySQL, 'ไม่ได้สำหรับการแสดงความคิดเห็น แม้ว่าจะเคยมีที่ว่างก่อนหน้าดังนั้นมันจึงสามารถจบสตริงที่นำหน้ามันได้เท่านั้น
การแข่งขัน Lightness ใน Orbit

45
เท่าที่ XKCD ดำเนินไปหากมีคำถามใด ๆ เกี่ยวกับการ์ตูนบางเล่มคุณสามารถไปที่อธิบาย XKCDและรับคำตอบของคุณ มีแม้กระทั่งวิกิ XKCDซึ่งมีประโยชน์มากสำหรับการ์ตูนที่มีเล่ห์เหลี่ยมเช่นXKCD geohashing
Anatoli

13
ฉันเชื่อว่าลิงค์นี้จะต้องถูกบันทึกไว้ที่นี่: bobby-tables.com
Arioch 'The

2
beta.companieshouse.gov.uk/company/10542519เป็นการลงทะเบียนสำหรับที่ปรึกษาชื่อ DROP Table "COMPANIES"; - LTD
Alex Dupuy

คำตอบ:


1116

มันวางโต๊ะนักเรียน

รหัสต้นฉบับในโปรแกรมของโรงเรียนอาจมีลักษณะเหมือน

q = "INSERT INTO Students VALUES ('" + FNMName.Text + "', '" + LName.Text + "')";

นี่เป็นวิธีที่ไร้เดียงสาในการเพิ่มการป้อนข้อความลงในคิวรีและไม่ดีอย่างที่คุณเห็น

หลังจากค่าจากชื่อแรกกล่องข้อความชื่อกลางFNMName.Text (ซึ่งคือRobert'); DROP TABLE STUDENTS; --) และกล่องข้อความชื่อLName.Text (ลองเรียกมันว่าDerper) จะถูกต่อกับส่วนที่เหลือของแบบสอบถามตอนนี้ผลลัพธ์จะเป็นสองแบบสอบถามที่คั่นด้วยตัวยกเลิกคำสั่ง (อัฒภาค) แบบสอบถามที่สองได้รับการฉีดเข้าไปในแรก เมื่อรหัสดำเนินการแบบสอบถามนี้กับฐานข้อมูลจะมีลักษณะเช่นนี้

INSERT INTO Students VALUES ('Robert'); DROP TABLE Students; --', 'Derper')

ซึ่งในภาษาอังกฤษธรรมดาแปลคร่าว ๆ เป็นสองแบบสอบถาม:

เพิ่มระเบียนใหม่ลงในตารางนักเรียนที่มีค่าชื่อเป็น 'โรเบิร์ต'

และ

ลบตารางนักเรียน

ทุกสิ่งที่ผ่านมาแบบสอบถามที่สองถูกทำเครื่องหมายเป็นความคิดเห็น : --', 'Derper')

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

แก้ไขอีกครั้งตามความคิดเห็นอันชาญฉลาดของdan04


3
อืม, ที่มีวงเล็บรอบขัดแย้งค่อนข้างผิดปกติ แต่อย่างน้อยมันก็หลีกเลี่ยงข้อผิดพลาดทางไวยากรณ์ ... :-)
PhiLho

60
@PhiLho: ถ้าข้อความต้นฉบับเป็นINSERTแล้ววงเล็บจะทำให้รู้สึกมากกว่า นอกจากนี้ยังจะอธิบายว่าทำไมการเชื่อมต่อฐานข้อมูลไม่ได้อยู่ในโหมดอ่านอย่างเดียว
dan04

3
ในฐานะที่เป็น @ dan04 INSERTอธิบายวงเล็บทำให้รู้สึกมากขึ้นกับ เมื่อคิดย้อนหลังไปแล้วSELECTจะไม่สามารถทำงานต่อไปได้เนื่องจากส่วนแทรกของตาราง Bobby เล็ก ๆ น้อย ๆ ในตารางน่าจะทิ้งโต๊ะไปแล้ว
ypercubeᵀᴹ

10
ในความเป็นจริงในตัวอย่างนี้การสืบค้นแรก ("เพิ่มบันทึกใหม่ ... ") จะล้มเหลวเนื่องจากStudentsคาดว่าจะมีมากกว่าหนึ่งคอลัมน์ ที่กล่าวว่าการมีคอลัมน์ที่สองนั้นมีประโยชน์ในการแสดงว่าทำไมต้องมีการแสดงความคิดเห็น และเนื่องจากไม่มีใครสามารถเปลี่ยนชื่อของบ๊อบบี้ได้ดังนั้นจึงควรปล่อยให้เป็นไปตามที่ควรจะเป็นมากกว่าเชิงอรรถเล็กน้อย
eggyal

7
นามสกุลของบ๊อบบี้ - หรืออย่างน้อยแม่ของเขาคือโรเบิร์ตต่ออธิบาย XKCD ฉันไม่แน่ใจว่าการแก้ไขที่จะปรับปรุงความชัดเจนของคำตอบแม้ว่า
WBT

611

สมมุติว่ามีการใช้ชื่อในตัวแปร, $Name.

จากนั้นคุณเรียกใช้แบบสอบถามนี้:

INSERT INTO Students VALUES ( '$Name' )

รหัสวางสิ่งที่ผู้ใช้กำหนดเป็นตัวแปรโดยไม่ตั้งใจ

คุณต้องการให้SQLเป็น:

ใส่ลงในค่าของนักเรียน (' Robert Tables`)

แต่ผู้ใช้ที่ฉลาดสามารถจัดหาสิ่งที่พวกเขาต้องการ:

ใส่ลงในค่าของนักเรียน (' Robert'); DROP TABLE Students; --')

สิ่งที่คุณจะได้รับคือ:

INSERT INTO Students VALUES ( 'Robert' );  DROP TABLE STUDENTS; --' )

--แสดงความคิดเห็นเท่านั้นที่เหลือของบรรทัด


87
นี่คือคะแนนที่ดีที่สุดแล้วเพราะมันอธิบายวงเล็บปิด
Tim Büthe

1
โดยวิธีการที่ไม่มีผู้อำนวยการโรงเรียนในการ์ตูนที่จะต้องตระหนักหรือ XSS ตั้งแต่ตารางนักเรียนถูกลบเขาไม่สามารถรู้ว่าใครทำ
xryl669

@ xryl669 บันทึกมีประโยชน์อย่างมากในสถานการณ์เช่นนี้ ... บางครั้งบันทึกการสืบค้นทั้งหมดและบางครั้งข้อมูลบันทึกอื่น ๆ สามารถช่วยคุณอนุมานผู้ร้ายได้
inemanja

165

ดังที่คนอื่น ๆ ได้ชี้ให้เห็นแล้ว');คำแถลงปิดต้นฉบับแล้วคำสั่งที่สองจะตามมา เฟรมเวิร์กส่วนใหญ่รวมถึงภาษาเช่น PHP มีการตั้งค่าความปลอดภัยเริ่มต้นในตอนนี้ซึ่งไม่อนุญาตให้มีหลายคำสั่งในหนึ่งสตริง ตัวอย่างเช่นใน PHP คุณสามารถเรียกใช้หลาย ๆ คำสั่งในหนึ่งสตริง SQL โดยใช้mysqli_multi_queryฟังก์ชั่น

อย่างไรก็ตามคุณสามารถจัดการคำสั่ง SQL ที่มีอยู่ผ่านการฉีด SQL ได้โดยไม่ต้องเพิ่มคำสั่งที่สอง สมมติว่าคุณมีระบบเข้าสู่ระบบซึ่งจะตรวจสอบชื่อผู้ใช้และรหัสผ่านด้วยการเลือกอย่างง่ายนี้:

$query="SELECT * FROM users WHERE username='" . $_REQUEST['user'] . "' and (password='".$_REQUEST['pass']."')";
$result=mysql_query($query);

หากคุณระบุpeterเป็นชื่อผู้ใช้และsecretเป็นรหัสผ่านสตริง SQL ที่ได้จะเป็นดังนี้:

SELECT * FROM users WHERE username='peter' and (password='secret')

ทุกอย่างเรียบร้อยดี. ตอนนี้คิดว่าคุณให้สตริงนี้เป็นรหัสผ่าน:

' OR '1'='1

จากนั้นสตริง SQL ที่ได้จะเป็นดังนี้:

SELECT * FROM users WHERE username='peter' and (password='' OR '1'='1')

ที่จะช่วยให้คุณสามารถเข้าสู่บัญชีใด ๆ โดยไม่ต้องรู้รหัสผ่าน ดังนั้นคุณไม่จำเป็นต้องใช้คำสั่งสองคำสั่งเพื่อใช้การฉีด SQL แม้ว่าคุณจะสามารถทำสิ่งที่ทำลายล้างได้มากขึ้นถ้าคุณสามารถจัดหาคำสั่งได้หลายคำสั่ง


71

ไม่'ไม่ใช่ความคิดเห็นใน SQL แต่เป็นตัวคั่น

แม่คิดว่าโปรแกรมเมอร์ฐานข้อมูลทำการร้องขอเช่น:

INSERT INTO 'students' ('first_name', 'last_name') VALUES ('$firstName', '$lastName');

(ตัวอย่าง) เพื่อเพิ่มนักเรียนใหม่โดยที่$xxxเนื้อหาตัวแปรถูกนำออกจากรูปแบบ HTML โดยตรงโดยไม่ต้องตรวจสอบรูปแบบหรือหลีกเลี่ยงอักขระพิเศษ

ดังนั้นหาก$firstNameมีRobert'); DROP TABLE students; --โปรแกรมฐานข้อมูลจะดำเนินการตามคำขอต่อไปนี้โดยตรงในฐานข้อมูล:

INSERT INTO 'students' ('first_name', 'last_name') VALUES ('Robert'); DROP TABLE students; --', 'XKCD');

กล่าวคือ มันจะยุติการแทรกคำสั่งต้น ๆ เรียกใช้งานโค้ดที่เป็นอันตรายใด ๆ ที่แครกเกอร์ต้องการจากนั้นใส่เครื่องหมายใด ๆ ที่เหลือ

อืมฉันช้าเกินไปฉันเห็น 8 คำตอบก่อนที่ฉันจะอยู่ในแถบสีส้ม ... :-) หัวข้อยอดนิยมดูเหมือนว่า


39

TL; DR

- แอปพลิเคชันยอมรับอินพุตในกรณีนี้ 'Nancy' โดยไม่ต้องพยายามฆ่าเชื้ออินพุตเช่นโดยการหลีกเลี่ยงอักขระพิเศษใน
โรงเรียน=> INSERT INTO VALUES ( 'Nancy' ) ของนักเรียน INSERT 0 1
   
  

- การฉีด SQL เกิดขึ้นเมื่อป้อนเข้าไปในคำสั่งฐานข้อมูลที่ถูกจัดการเพื่อ- ทำให้เซิร์ฟเวอร์ฐานข้อมูลเพื่อดำเนินการ
โรงเรียนSQL โดยพลการ=> INSERT INTO VALUES ( 'Robert' ) นักเรียน DROP ตารางนักเรียน; - '); INSERT 0 1 DROP ตาราง
      
  
 

- บันทึกของนักเรียนหายไปแล้ว - มันอาจจะแย่กว่านี้อีก! 
โรงเรียน=> เลือก* จากนักเรียน; 
ข้อผิดพลาด:   ความสัมพันธ์"นักเรียน" ไม่ได้อยู่   
บรรทัดที่1 : เลือก* จากนักเรียน; ^   
                      

สิ่งนี้จะลดลง (ลบ) ตารางนักเรียน

( ตัวอย่างรหัสทั้งหมดในคำตอบนี้ถูกเรียกใช้บนเซิร์ฟเวอร์ฐานข้อมูล PostgreSQL 9.1.2 )

เพื่อให้ชัดเจนว่ามีอะไรเกิดขึ้นลองทำตารางง่ายๆที่มีเฉพาะฟิลด์ชื่อและเพิ่มแถวเดียว:

โรงเรียน=> สร้างตารางนักเรียน( ชื่อ TEXT PRIMARY KEY ); 
ข้อสังเกต: CREATE TABLE / PRIMARY KEY จะสร้างนัยดัชนี"students_pkey" สำหรับตาราง"นักเรียน" CREATE TABLE 
โรงเรียน=> INSERT INTO นักเรียนVALUES ( 'จอห์น' ); INSERT 0 1             
    
  

สมมติว่าแอปพลิเคชันใช้ SQL ต่อไปนี้เพื่อแทรกข้อมูลลงในตาราง:

INSERT INTO VALUES นักเรียน( 'foobar' );  

แทนที่foobarด้วยชื่อจริงของนักเรียน การดำเนินการแทรกปกติจะมีลักษณะเช่นนี้:

- การป้อนข้อมูล: แนนซี่
โรงเรียน=> INSERT INTO นักเรียนVALUES ( 'แนนซี่' ); INSERT 0 1   
  

เมื่อเราสอบถามตารางเราจะได้สิ่งนี้:

โรงเรียน=> เลือก* จากนักเรียน;   
 ชื่อ
-------
 จอห์น
 แนนซี่
( 2 แถว) 

เกิดอะไรขึ้นเมื่อเราใส่ชื่อ Little Bobby Tables ลงในตาราง

- อินพุต: Robert '); นักเรียน DROP Table - 
โรงเรียน=> INSERT เข้าสู่นักเรียนค่า( 'โรเบิร์ต' ); DROP ตารางนักเรียน; - '); INSERT 0 1 DROP ตาราง      
  
 

การฉีด SQL ที่นี่เป็นผลมาจากชื่อของนักเรียนที่ยกเลิกคำสั่งและรวมถึงDROP TABLEคำสั่งแยกต่างหาก; เครื่องหมายขีดคั่นสองตัวที่ส่วนท้ายของอินพุตมีจุดประสงค์เพื่อใส่รหัสใด ๆ ที่เหลือซึ่งอาจทำให้เกิดข้อผิดพลาด บรรทัดสุดท้ายของการส่งออกยืนยันว่าเซิร์ฟเวอร์ฐานข้อมูลได้ลดลงตาราง

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

ผลลัพธ์?

โรงเรียน=> เลือก* จากนักเรียน; 
ข้อผิดพลาด:   ความสัมพันธ์"นักเรียน" ไม่ได้อยู่   
บรรทัดที่1 : เลือก* จากนักเรียน; ^   
                      

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

ตามที่ระบุไว้ในหนังสือการ์ตูน XKCD วิธีหนึ่งในการป้องกันการโจมตี SQL injection คือการฆ่าเชื้ออินพุตของฐานข้อมูลเช่นโดยการหลีกเลี่ยงอักขระพิเศษเพื่อที่พวกเขาจะไม่สามารถแก้ไขคำสั่ง SQL พื้นฐานและดังนั้นจึงไม่สามารถทำให้เกิดการเรียกใช้งาน หากคุณใช้การสืบค้นแบบกำหนดพารามิเตอร์เช่นโดยใช้SqlParameterใน ADO.NET อย่างน้อยที่สุดการป้อนข้อมูลจะถูกทำให้สะอาดโดยอัตโนมัติเพื่อป้องกันการฉีด SQL

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


30

สมมติว่าคุณเขียนวิธีสร้างนักเรียนอย่างไร้เดียงสาเช่นนี้:

void createStudent(String name) {
    database.execute("INSERT INTO students (name) VALUES ('" + name + "')");
}

และมีคนป้อนชื่อ Robert'); DROP TABLE STUDENTS; --

สิ่งที่เรียกใช้บนฐานข้อมูลคือแบบสอบถามนี้:

INSERT INTO students (name) VALUES ('Robert'); DROP TABLE STUDENTS --')

อัฒภาคสิ้นสุดคำสั่งแทรกและเริ่มต้นอื่น; - แสดงความคิดเห็นส่วนที่เหลือของบรรทัด คำสั่ง DROP TABLE ถูกดำเนินการ ...

นี่คือสาเหตุที่พารามิเตอร์การโยงเป็นสิ่งที่ดี


26

เครื่องหมายคำพูดเดี่ยวคือจุดเริ่มต้นและจุดสิ้นสุดของสตริง อัฒภาคคือจุดสิ้นสุดของคำสั่ง ดังนั้นหากพวกเขาเลือกอย่างนี้:

Select *
From Students
Where (Name = '<NameGetsInsertedHere>')

SQL จะกลายเป็น:

Select *
From Students
Where (Name = 'Robert'); DROP TABLE STUDENTS; --')
--             ^-------------------------------^

ในบางระบบselectจะมีการรันก่อนตามด้วยdropคำสั่ง! ข้อความคือ: ไม่ได้ฝังค่าลงใน SQL ของคุณ ใช้พารามิเตอร์แทน!


18

');ปลายแบบสอบถามก็ไม่ได้เริ่มต้นการแสดงความคิดเห็น จากนั้นวางตารางนักเรียนและแสดงความคิดเห็นส่วนที่เหลือของแบบสอบถามที่ควรจะถูกดำเนินการ


17

ผู้เขียนฐานข้อมูลอาจทำ

sql = "SELECT * FROM STUDENTS WHERE (STUDENT_NAME = '" + student_name + "') AND other stuff";
execute(sql);

ถ้า student_name เป็นชื่อที่ได้รับการเลือกจะใช้ชื่อ "Robert" และจากนั้นให้ดรอปตาราง ส่วน "-" เปลี่ยนส่วนที่เหลือของแบบสอบถามที่กำหนดให้เป็นความคิดเห็น


มันเป็นความคิดแรกของฉัน แต่คุณได้รับข้อผิดพลาดทางไวยากรณ์กับวงเล็บปิดท้ายใช่ไหม?
PhiLho

3
นั่นเป็นเหตุผลที่มี - ในตอนท้ายระบุว่าข้อความที่เหลือเป็นความคิดเห็นและควรละเว้น

17

ในกรณีนี้ 'ไม่ใช่ตัวอักษรแสดงความคิดเห็น มันถูกใช้เพื่อกำหนดขอบเขตตัวอักษรสตริง ศิลปินการ์ตูนเป็นแบงกิ้งในความคิดที่ว่าโรงเรียนที่มีปัญหานั้นมีไดนามิก sql อยู่ที่ไหนซักแห่งที่มีหน้าตาแบบนี้:

$sql = "INSERT INTO `Students` (FirstName, LastName) VALUES ('" . $fname . "', '" . $lname . "')";

ดังนั้นตอนนี้ตัวละคร 'จะสิ้นสุดสตริงตามตัวอักษรก่อนที่โปรแกรมเมอร์จะคาดหวังมัน รวมกับ; ตัวละครที่จะจบคำสั่งผู้โจมตีสามารถเพิ่มสิ่งที่พวกเขาต้องการ sql - ความคิดเห็นในตอนท้ายคือการทำให้แน่ใจว่า sql ใด ๆ ที่เหลืออยู่ในคำสั่งเดิมไม่ได้ป้องกันการรวบรวมแบบสอบถามบนเซิร์ฟเวอร์

FWIW ฉันยังคิดว่าการ์ตูนที่มีปัญหานั้นมีรายละเอียดที่ไม่ถูกต้อง: หากคุณกำลังคิดที่จะล้างข้อมูลในฐานข้อมูลของคุณตามที่การ์ตูนแนะนำคุณยังคงทำผิดอยู่ แต่คุณควรคิดในแง่ของการกักกันอินพุตฐานข้อมูลของคุณและวิธีที่ถูกต้องในการทำเช่นนี้คือผ่านการสืบค้นแบบกำหนดพารามิเตอร์


16

'ตัวละครใน SQL จะใช้สำหรับค่าคงที่สตริง ในกรณีนี้มันถูกใช้สำหรับสิ้นสุดค่าคงที่สตริงไม่ใช่สำหรับความคิดเห็น


7

นี่คือวิธีการทำงาน: สมมติว่าผู้ดูแลระบบกำลังมองหาบันทึกของนักเรียน

Robert'); DROP TABLE STUDENTS; --

เนื่องจากบัญชีผู้ดูแลระบบมีสิทธิ์สูงในการลบตารางออกจากบัญชีนี้จึงเป็นไปได้

รหัสเพื่อดึงชื่อผู้ใช้จากการร้องขอคือ

ตอนนี้แบบสอบถามจะเป็นแบบนี้ (เพื่อค้นหาตารางนักเรียน)

String query="Select * from student where username='"+student_name+"'";

statement.executeQuery(query); //Rest of the code follows

แบบสอบถามผลลัพธ์

Select * from student where username='Robert'); DROP TABLE STUDENTS; --

เนื่องจากอินพุตของผู้ใช้ไม่ถูกทำให้สะอาดเคียวรีข้างต้นจึงถูกจัดการเป็น 2 ส่วน

Select * from student where username='Robert'); 

DROP TABLE STUDENTS; --

เครื่องหมายขีดกลางคู่ (-) จะแสดงความคิดเห็นส่วนที่เหลือของแบบสอบถาม

นี่เป็นอันตรายเนื่องจากสามารถลบล้างการพิสูจน์ตัวตนด้วยรหัสผ่านถ้ามี

คนแรกจะทำการค้นหาตามปกติ

อันที่สองจะวางตารางนักเรียนถ้าบัญชีมีสิทธิ์เพียงพอ (โดยทั่วไปบัญชีผู้ดูแลระบบโรงเรียนจะเรียกใช้แบบสอบถามดังกล่าวและจะมีสิทธิ์พูดคุยเกี่ยวกับข้างต้น)


SELECT* FROM sutdents ...- คุณลืม "s" นี่คือสิ่งที่คุณวาง DROP TABLE STUDENTS;
DevWL

4

คุณไม่จำเป็นต้องป้อนข้อมูลในแบบฟอร์มเพื่อทำการฉีด SQL

ไม่มีใครชี้เรื่องนี้มาก่อนดังนั้นฉันอาจเตือนคุณบางคน

ส่วนใหญ่เราจะพยายามแก้ไขรูปแบบการป้อนข้อมูล แต่นี่ไม่ใช่สถานที่เดียวที่คุณสามารถโจมตีด้วยการฉีด SQL คุณสามารถทำการโจมตีได้ง่ายด้วย URL ที่ส่งข้อมูลผ่านการร้องขอ GET ลองพิจารณาตัวอย่างที่ร่วงหล่น:

<a href="/show?id=1">show something</a>

URL ของคุณจะดู http://yoursite.com/show?id=1

ตอนนี้บางคนสามารถลองสิ่งนี้

http://yoursite.com/show?id=1;TRUNCATE table_name

ลองแทนที่ table_name ด้วยชื่อตารางจริง หากเขาได้ชื่อตารางของคุณถูกต้องพวกเขาจะทำให้โต๊ะว่าง! (มันเป็นเรื่องง่ายมากที่จะ brut บังคับ URL นี้ด้วยสคริปต์ง่าย ๆ )

ข้อความค้นหาของคุณจะมีลักษณะเช่นนี้ ...

"SELECT * FROM page WHERE id = 4;TRUNCATE page"

ตัวอย่างโค้ด PHP ที่มีช่องโหว่โดยใช้ PDO:

<?php
...
$id = $_GET['id'];

$pdo = new PDO($database_dsn, $database_user, $database_pass);
$query = "SELECT * FROM page WHERE id = {$id}";
$stmt = $pdo->query($query);
$data = $stmt->fetch(); 
/************* You have lost your data!!! :( *************/
...

โซลูชัน - ใช้วิธีการเตรียม PDO () & bindParam ():

<?php
...
$id = $_GET['id'];

$query = 'SELECT * FROM page WHERE id = :idVal';
$stmt = $pdo->prepare($query);
$stmt->bindParam('idVal', $id, PDO::PARAM_INT);
$stmt->execute();
$data = $stmt->fetch();
/************* Your data is safe! :) *************/
...
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.