ทำไมกลไกการป้องกันการฉีด SQL ถึงวิวัฒนาการไปในทิศทางของการใช้คิวรีแบบพารามิเตอร์


59

วิธีที่ฉันเห็นการโจมตีด้วยการฉีด SQL สามารถป้องกันได้โดย:

  1. คัดกรองกรองเข้ารหัสการป้อนข้อมูลอย่างระมัดระวัง (ก่อนแทรกลงใน SQL)
  2. การใช้คำสั่งที่เตรียมไว้ / แบบสอบถามแบบใช้พารามิเตอร์

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

ตามที่ฉันเข้าใจถ้าใช้ # 1 อย่างถูกต้องและข้อควรระวังทั้งหมดได้รับการดูแลมันจะมีประสิทธิภาพเท่ากับ # 2

ฆ่าเชื้อโรคกรองและเข้ารหัส

มีความสับสนในส่วนของฉันระหว่างสิ่งที่เป็นฆ่าเชื้อ , การกรองและการเข้ารหัสความหมาย ฉันจะบอกว่าสำหรับวัตถุประสงค์ของฉันทั้งหมดข้างต้นสามารถพิจารณาตัวเลือก 1. ในกรณีนี้ผมเข้าใจว่าการฆ่าเชื้อและการกรองมีศักยภาพในการแก้ไขหรือยกเลิกการป้อนข้อมูลในขณะที่การเข้ารหัสจะเก็บรักษาข้อมูลตามที่เป็นแต่ถอดรหัส อย่างถูกต้องเพื่อหลีกเลี่ยงการโจมตีของการฉีด ฉันเชื่อว่าการหลีกเลี่ยงข้อมูลถือได้ว่าเป็นวิธีการเข้ารหัส

พารามิเตอร์การสืบค้นเทียบกับการเข้ารหัสห้องสมุด

มีคำตอบที่แนวคิดของparameterized queriesและencoding librariesที่ได้รับการปฏิบัติแทนกันได้ แก้ไขฉันถ้าฉันผิด แต่ฉันรู้สึกว่าแตกต่างกัน

ความเข้าใจของฉันคือว่าencoding librariesไม่ว่าพวกเขาจะมีศักยภาพในการปรับเปลี่ยน SQL "โปรแกรม" ได้ดีเพียงใดเพราะพวกเขากำลังทำการเปลี่ยนแปลง SQL เองก่อนที่มันจะถูกส่งไปยัง RDBMS

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

ห้องสมุดการเข้ารหัส

  data -> (encoding library)
                  |
                  v
SQL -> (SQL + encoded data) -> RDBMS (execution plan defined) -> execute statement

แบบสอบถามแบบกำหนดพารามิเตอร์

                                               data
                                                 |
                                                 v
SQL -> RDBMS (query execution plan defined) -> data -> execute statement

ความสำคัญทางประวัติศาสตร์

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


1
ความคิดเห็นไม่ได้มีไว้สำหรับการอภิปรายเพิ่มเติม การสนทนานี้ได้รับการย้ายไปแชท
maple_shaft

23
งบเตรียมไม่ได้เป็นผลมาจากวิวัฒนาการจากการโจมตีฉีด SQL พวกเขาอยู่ที่นั่นตั้งแต่เริ่มต้น คำถามของคุณอิงจากคุณสมบัติที่เป็นเท็จ
user207421

4
หากคุณคิดว่าคุณฉลาดกว่าคนเลวไปที่ # 1
paparazzo

1
"ทำไม PQ ยังคงเป็นวิธีการเลือก" เพราะเป็นวิธีที่ง่ายที่สุดและแข็งแกร่งที่สุด บวกกับข้อได้เปรียบด้านประสิทธิภาพดังกล่าวกับ PQ ไม่มีข้อเสียจริงๆ
พอลเดรเปอร์

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

คำตอบ:


147

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

ใช่แล้วสิ่งนั้นจะหยุดการโจมตีด้วยการฉีด SQL แต่มันก็มีค่าใช้จ่ายที่สูงกว่า


60
@dennis - อะไรคือคำพูดในตัวแปร SQL ของคุณ? "? '?"? U + 2018? \ u2018 มีเทคนิคในการแยกนิพจน์หรือไม่แบบสอบถามย่อยของคุณสามารถอัปเดตได้หรือไม่มีหลายสิ่งที่ต้องพิจารณา
Telastyn

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

12
ข้อได้เปรียบอีกประการของคำสั่งที่เตรียมไว้คือประสิทธิภาพที่เพิ่มขึ้นที่คุณได้รับเมื่อคุณต้องเรียกใช้คิวรีเดิมอีกครั้งโดยมีค่าต่างกัน นอกจากนี้งบที่เตรียมไว้สามารถทราบได้ว่ามูลค่ามีความหมายว่าเป็น trully หรือไม่เช่นnullสตริงหรือตัวเลขและดำเนินการตามนั้น นี่เป็นสิ่งที่ดีมากสำหรับการรักษาความปลอดภัย และแม้ว่าคุณจะเรียกใช้เคียวรีหนึ่งครั้งเอ็นจิน DB จะปรับให้เหมาะสมสำหรับคุณแล้ว ยังดีกว่าถ้าเก็บไว้!
Ismael Miguel

8
@Dennis Mr. Henry Null ขอขอบคุณที่ทำสิ่งนี้ให้ถูกวิธี
Mathieu Guindon

14
@Dennis ชื่อแรกไม่เกี่ยวข้อง ปัญหาเกิดขึ้นกับนามสกุล ดูStack Overflow , Programmers.SE , Fox Sports , Wired , BBCและอะไรก็ได้ที่คุณสามารถค้นหาได้ในการค้นหาโดย Google ;-)
Mathieu Guindon

80

เนื่องจากตัวเลือก 1 ไม่ใช่วิธีแก้ปัญหา การคัดกรองและการกรองหมายถึงการปฏิเสธหรือลบอินพุตที่ไม่ถูกต้อง แต่การป้อนข้อมูลใด ๆ อาจถูกต้อง ตัวอย่าง apostrophe เป็นอักขระที่ถูกต้องในชื่อ "O'Malley" มันจะต้องมีการเข้ารหัสอย่างถูกต้องก่อนที่จะใช้ใน SQL ซึ่งเป็นสิ่งที่งบเตรียมไว้


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


2
นั่นคือ (และนั่นคือส่วนที่ขาดหายไปในอีกสองคำตอบดังนั้น +1) เมื่อพิจารณาว่าคำถามถูกสร้างขึ้นมาอย่างไรมันไม่ได้เกี่ยวกับการฆ่าเชื้ออินพุตของผู้ใช้ แต่และฉันพูดถึงคำถาม:“ การกรองอินพุต (ก่อนแทรก)” หากคำถามตอนนี้เกี่ยวกับการทำให้บริสุทธิ์ข้อมูลที่ป้อนเข้ามาทำไมคุณต้องทำด้วยตัวเองแทนที่จะปล่อยให้ห้องสมุดทำมัน (ในขณะเดียวกันการสูญเสียโอกาสที่จะมีแผนการดำเนินการที่แคชไว้)
Arseni Mourzenko

8
@Dennis: การฆ่าเชื้อหรือการกรองหมายถึงการลบข้อมูล การเข้ารหัสหมายถึงการเปลี่ยนการนำเสนอข้อมูลโดยไม่ทำให้ข้อมูลสูญหาย
JacquesB

9
@Dennis: การกรองหมายถึงการยอมรับหรือปฏิเสธการป้อนข้อมูลของผู้ใช้ ตัวอย่างเช่น“ Jeff” จะถูกกรองเป็นอินพุตของฟิลด์“ อายุของผู้ใช้” เนื่องจากค่านั้นไม่ถูกต้อง ถ้าแทนการกรองการป้อนข้อมูลที่คุณจะเริ่มเปลี่ยนมันด้วยเช่นแทนที่ตัวอักษรคำพูดเดียวแล้วคุณจะทำว่าเป็นสิ่งเดียวกับห้องสมุดฐานข้อมูลที่พวกเขาใช้คำสั่ง parametrized; ในกรณีนี้คำถามของคุณคือ“ ทำไมฉันจะใช้บางสิ่งที่มีอยู่และเขียนโดยผู้เชี่ยวชาญในสาขาเมื่อฉันสามารถบูรณาการล้อในทุกโครงการได้หรือไม่”
Arseni Mourzenko

3
@Dennis: O\'Malleyใช้เครื่องหมายทับเพื่อหลีกเลี่ยงการอ้างอิงสำหรับการแทรกที่เหมาะสม (อย่างน้อยในบางฐานข้อมูล) ใน MS SQL O''Malleyหรือการเข้าถึงก็สามารถที่จะหนีไปกับคำพูดเพิ่มเติม ไม่พกพาได้มากถ้าคุณต้องทำด้วยตัวเอง
AbraCadaver

5
ฉันไม่สามารถบอกคุณได้ว่าหลายครั้งที่ชื่อของฉันถูกปฏิเสธโดยระบบ บางครั้งฉันก็เห็นข้อผิดพลาดที่เกิดจากการฉีด SQL เพียงแค่ใช้ชื่อของฉัน Heck ฉันถูกขอให้เปลี่ยนชื่อผู้ใช้ของฉันเพราะจริง ๆ แล้วฉันได้ทำลายบางสิ่งบางอย่างในแบ็กเอนด์
Alexander O'Mara

60

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

List<Integer> list = /* a list of 1, 2, 3 */
String strList = list.toString();   /* to get "[1, 2, 3]" */
strList = /* manipulate strList to become "[1, 2, 5, 3]" */
list = parseList(strList);

หากมีคนแนะนำให้ทำเช่นนั้นคุณควรตอบอย่างถูกต้องว่าเป็นเรื่องไร้สาระและควรทำสิ่งต่อไปนี้

List<Integer> list = /* ... */;
list.add(5, position=2);

ที่โต้ตอบกับโครงสร้างข้อมูลในระดับแนวคิด มันไม่ได้แนะนำการพึ่งพาใด ๆ กับโครงสร้างที่อาจพิมพ์หรือแยก นั่นคือการตัดสินใจแบบฉากฉาก

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

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

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

มีการเปรียบเทียบที่ดีระหว่างมาโคร C-style ที่ใช้การแทนที่ข้อความอย่างง่ายและมาโคร Lisp ที่สร้างโค้ดโดยอำเภอใจ ด้วยมาโคร C-style คุณสามารถแทนที่ข้อความในซอร์สโค้ดและนั่นหมายความว่าคุณมีความสามารถในการแนะนำข้อผิดพลาดทางไวยากรณ์หรือพฤติกรรมที่ทำให้เข้าใจผิด ด้วย Lisp macros คุณกำลังสร้างโค้ดในรูปแบบที่คอมไพเลอร์ประมวลผล (นั่นคือคุณกำลังส่งคืนโครงสร้างข้อมูลจริงที่คอมไพเลอร์ประมวลผลไม่ใช่ข้อความที่ผู้อ่านต้องประมวลผลก่อนที่คอมไพเลอร์จะไปถึงมัน) . ด้วยแมโคร Lisp คุณไม่สามารถสร้างบางสิ่งที่อาจเป็นข้อผิดพลาดในการแยกวิเคราะห์ เช่นคุณไม่สามารถสร้าง(ขอ ((AB บริการ)

แม้ว่าจะมีมาโคร Lisp คุณก็ยังสามารถสร้างโค้ดที่ไม่ดีได้เนื่องจากคุณไม่จำเป็นต้องรับรู้ถึงโครงสร้างที่ควรจะมี เช่นใน Lisp, (let ((ab)) a)หมายถึง "สร้างการเชื่อมคำศัพท์ใหม่ของตัวแปร a ไปยังค่าของตัวแปร b แล้วส่งกลับค่าของ" และ(let (ab) a)หมายถึง "สร้างการเชื่อมคำศัพท์ใหม่ของตัวแปร a และ b และกำหนดค่าเริ่มต้นให้เป็นศูนย์และจากนั้นส่งคืนค่าของ a" สิ่งเหล่านี้ถูกต้องทั้งทางวากยสัมพันธ์ แต่มันหมายถึงสิ่งต่าง ๆ เพื่อหลีกเลี่ยงปัญหานี้คุณสามารถใช้ฟังก์ชั่นที่มีความหมายมากยิ่งขึ้น

Variable a = new Variable("a");
Variable b = new Variable("b");
Let let = new Let();
let.getBindings().add(new LetBinding(a,b));
let.setBody(a);
return let;

ด้วยบางสิ่งเช่นนั้นมันเป็นไปไม่ได้ที่จะคืนสิ่งที่ไม่ถูกต้องทาง syntactically และมันยากมากที่จะคืนสิ่งที่ไม่ได้ตั้งใจตามที่คุณต้องการ


คำอธิบายที่ดี!
Mike Partridge

2
คุณสูญเสียฉันไปที่ "การเปรียบเทียบที่ดี" แต่ฉัน upvoted ตามคำอธิบายก่อนหน้า :)
Wildcard

1
ตัวอย่างที่ยอดเยี่ยม! - และคุณสามารถเพิ่ม: บางครั้งมันเป็นไปไม่ได้หรือเป็นไปได้ที่จะสร้างสตริงที่แยกวิเคราะห์ได้ขึ้นอยู่กับประเภทข้อมูล - จะทำอย่างไรหากหนึ่งในพารามิเตอร์ของฉันคือฟิลด์ข้อความอิสระที่มีเนื้อเรื่องเรื่องราว (~ 10.000 ตัวอักษร) หรือสิ่งที่ถ้าพารามิเตอร์หนึ่งเป็นJPG ภาพ ? - วิธีเดียวเท่านั้นที่จะเป็นแบบสอบถามแบบกำหนดค่าได้
Falco

จริงๆแล้วไม่มี - มันเป็นคำอธิบายที่ไม่ดีนักเกี่ยวกับสาเหตุที่ข้อความที่เตรียมไว้วิวัฒนาการมาเพื่อป้องกันการฉีด sql โดยเฉพาะอย่างยิ่งได้รับตัวอย่างรหัสอยู่ในจาวาซึ่งไม่ได้อยู่รอบ ๆ เมื่อแบบสอบถามแปรปรวนที่ developped น่าจะอยู่ในกรอบเวลาที่ C / C ++ ที่ถือว่ารัฐของศิลปะ ฐานข้อมูล SQL เริ่มใช้ในปีแรก ๆ ของช่วงเวลา 1970-1980 วิธีก่อนภาษาระดับสูงกว่าซึ่งเป็นที่นิยม Heck ฉันจะบอกว่าหลายคนมาทำให้การทำงานกับฐานข้อมูลง่ายขึ้น (PowerBuilder ใคร?)
TomTom

@TomTom จริง ๆ แล้วฉันเห็นด้วยกับเนื้อหาส่วนใหญ่ของคุณ ฉันได้สัมผัสโดยเฉพาะอย่างยิ่งในด้านความปลอดภัยที่นี่ บนดังนั้นฉันตอบ SPARQL จำนวนมาก (ภาษาคิวรี RDF ที่มีความคล้ายคลึงกับ SQL) และผู้คนจำนวนมากพบปัญหาเนื่องจากพวกเขาเชื่อมสตริงเข้าด้วยกันแทนที่จะใช้คิวรี่แบบพารามิเตอร์ แม้ว่าจะไม่มีการโจมตีด้วยการฉีดแบบสอบถามที่มีพารามิเตอร์ช่วยหลีกเลี่ยงข้อผิดพลาด / ข้อขัดข้องและข้อบกพร่อง / ข้อขัดข้องอาจเป็นปัญหาด้านความปลอดภัยเช่นกันแม้ว่าจะไม่ใช่การโจมตีแบบฉีดก็ตาม ดังนั้นฉันจะบอกว่าน้อยลง: แบบสอบถามแบบมีพารามิเตอร์เป็นสิ่งที่ดีแม้ว่าการฉีด SQL จะไม่เป็นปัญหาและมันก็ดี ...
Joshua Taylor

21

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


10
การฉีด SQL เป็นปัญหาตั้งแต่ SQL ถูกคิดค้นครั้งแรก มันไม่ได้กลายเป็นปัญหาในภายหลัง
Servy

9
@Servy ในทางทฤษฎีใช่ จริง ๆ แล้วมันกลายเป็นเรื่องจริงเมื่อกลไกการป้อนข้อมูลของเราออนไลน์แล้วนำเสนอพื้นผิวการโจมตีครั้งใหญ่สำหรับทุกคนที่จะตี
Jan Doggen

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

5
@ ความรู้ของฉันไดนามิก SQL เป็นคุณสมบัติที่ค่อนข้างล่าช้า การใช้งานเริ่มต้นของ SQL ส่วนใหญ่จะถูกคอมไพล์ / ประมวลผลล่วงหน้าด้วยพารามิเตอร์สำหรับค่า (ทั้งในและนอก) ดังนั้นพารามิเตอร์ในการสืบค้นอาจทำให้การฉีด SQL ในซอฟต์แวร์มีมาก่อน (อาจไม่ใช่ในแบบสอบถาม ad-hoc / CLI)
Mark Rotteveel

6
พวกเขาอาจทราบล่วงหน้าเกี่ยวกับการฉีด SQL
user253751

20

เพียงกล่าวว่าพวกเขาไม่ได้ คำสั่งของคุณ:

ทำไมกลไกการป้องกันการฉีด SQL ถึงวิวัฒนาการไปในทิศทางของการใช้พารามิเตอร์การสืบค้น

มีข้อบกพร่องพื้นฐาน Parameterized query มีอยู่นานกว่า SQL Injection อย่างน้อยก็เป็นที่รู้จักอย่างกว้างขวาง โดยทั่วไปพวกเขาจะถูกพัฒนาเป็นวิธีการหลีกเลี่ยงความเข้มข้นของสตริงในแอปพลิเคชัน "แบบฟอร์มสำหรับการค้นหา" ตามปกติ LOB (สายงานธุรกิจ) มี หลายคน - หลายปีต่อมามีคนพบปัญหาด้านความปลอดภัยด้วยการจัดการสตริงดังกล่าว

ฉันจำได้ว่าทำ SQL เมื่อ 25 ปีที่แล้ว (เมื่ออินเทอร์เน็ตไม่ได้ใช้กันอย่างแพร่หลาย - มันเพิ่งจะเริ่มต้น) และฉันจำได้ว่าทำ SQL กับ IBM DB5 IIRC เวอร์ชัน 5 - และนั่นก็มีการสืบค้นพารามิเตอร์แล้ว


ขอบคุณ ทำไมจึงจำเป็นต้องหลีกเลี่ยงการต่อสตริงเข้าด้วยกัน? ดูเหมือนว่าฉันจะเป็นคุณลักษณะที่มีประโยชน์ มีคนมีปัญหากับมันหรือไม่?
เดนนิส

3
สองอันที่จริง ข้อแรกมันไม่ได้สำคัญเสมอไปทั้งหมด - ทำไมต้องจัดการกับการจัดสรรหน่วยความจำ ฯลฯ เมื่อไม่ต้องการ แต่ประการที่สองในสมัยโบราณด้านแคชฐานข้อมูล sql ไม่ตรงกับที่รวบรวม SQL ที่ดีมีราคาแพง ผลข้างเคียงของการใช้คำสั่งที่เตรียมไว้หนึ่ง sql (ซึ่งเป็นที่มาของพารามิเตอร์) แผน exeuction สามารถนำกลับมาใช้ใหม่ได้ SQL Server แนะนำการปรับพารามิเตอร์อัตโนมัติ (เพื่อนำแผนแบบสอบถามมาใช้ใหม่แม้ไม่มีพารามิเตอร์ - จะถูกหักและโดยนัย) ฉันคิดว่าทั้ง 2000 หรือ 2007 - ที่ใดที่หนึ่งในระหว่างนั้น IIRC
TomTom

2
การมีคิวรี่แบบพารามิเตอร์ไม่ได้ช่วยกำจัดความสามารถในการเชื่อมสตริง คุณสามารถทำการต่อสตริงเพื่อสร้างเคียวรีที่กำหนดพารามิเตอร์ เพียงเพราะคุณสมบัติมีประโยชน์ไม่ได้หมายความว่าจะเป็นตัวเลือกที่ดีสำหรับปัญหาที่กำหนด
JimmyJames

ใช่ แต่อย่างที่ฉันบอก - ตามเวลาที่พวกเขาคิดค้น SQL แบบไดนามิกมาพร้อมกับประสิทธิภาพที่ค่อนข้างดี;) แม้กระทั่งทุกวันนี้คนบอกคุณว่าแผนการสืบค้น SQL แบบไดนามิกใน SQL Server ไม่ได้ถูกนำมาใช้ซ้ำ (ซึ่งผิดตั้งแต่ hm - as ฉันพูดบางจุดระหว่างปี 2000 ถึงปี 2007 - ยาวมากเลย) ในช่วงเวลานั้นคุณต้องการคำสั่งที่เตรียมไว้จริงๆถ้าคุณเรียกใช้ sql หลายครั้ง;)
TomTom

ความจริงแล้วการแคชแผนสำหรับ SQL แบบไดนามิกนั้นได้เพิ่มไปยัง SQL Server 7.0 แล้วในปี 1998 - sqlmag.com/database-performance-tuning/ …
Mike Dimmick

13

นอกเหนือจากคำตอบที่ดีอื่น ๆ ทั้งหมด:

สาเหตุที่ # 2 ดีกว่าคือเพราะมันแยกข้อมูลของคุณจากโค้ดของคุณ ใน # 1 ข้อมูลของคุณเป็นส่วนหนึ่งของรหัสของคุณและเป็นสิ่งที่มาจากสิ่งเลวร้าย ด้วย # 1 คุณจะได้รับคิวรีของคุณและจำเป็นต้องทำตามขั้นตอนเพิ่มเติมเพื่อให้แน่ใจว่าคิวรีของคุณเข้าใจข้อมูลของคุณเป็นข้อมูลในขณะที่ใน # 2 คุณจะได้รับโค้ดของคุณและโค้ดของมันและข้อมูลของคุณคือข้อมูล


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

11

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

จากมุมมองฐานข้อมูล SQL select * from employees where last_name = 'Smith'และselect * from employees where last_name = 'Fisher'แตกต่างกันอย่างชัดเจนดังนั้นจึงต้องแยกวิเคราะห์รวบรวมและเพิ่มประสิทธิภาพแยกต่างหาก พวกเขายังจะครอบครองช่องแยกต่างหากในพื้นที่หน่วยความจำที่ทุ่มเทให้กับการจัดเก็บงบที่รวบรวม ในระบบที่มีการโหลดจำนวนมากซึ่งมีเคียวรีที่คล้ายกันจำนวนมากซึ่งมีการคำนวณพารามิเตอร์ที่แตกต่างกันและโอเวอร์เฮดของหน่วยความจำอาจมีค่ามาก

จากนั้นการใช้การค้นหาแบบพารามิเตอร์มักจะให้ประโยชน์ด้านประสิทธิภาพที่สำคัญ


ฉันคิดว่านั่นเป็นทฤษฎี (ตามงบที่เตรียมไว้สำหรับการสืบค้นแบบกำหนดพารามิเตอร์) ในทางปฏิบัติฉันสงสัยว่านี่เป็นเรื่องจริงที่บ่อยครั้งเนื่องจากการใช้งานส่วนใหญ่จะเตรียม - รัน - รันในการโทรครั้งเดียวดังนั้นให้ใช้คำสั่งที่เตรียมไว้ที่แตกต่างกันสำหรับการสืบค้นแบบกำหนดพารามิเตอร์แต่ละรายการ ระดับprepareมักจะค่อนข้างแตกต่างจากระดับ SQL จริงprepare)
jcaron

แบบสอบถามต่อไปนอกจากนี้ยังมีแตกต่างกันไป parser SQL: และSELECT * FROM employees WHERE last_name IN (?, ?) SELECT * FROM employees WHERE last_name IN (?, ?, ?, ?, ?, ?)
Damian Yerrick

ใช่พวกเขามี. ซึ่งเป็นสาเหตุที่ MS เพิ่มแผนคิวรีแคชในปี 1998 ไปยัง SQL Server 7 เช่นเดียวกับใน: ข้อมูลของคุณเป็นรุ่นเก่า
TomTom

1
@TomTom - การแคชแผนแบบสอบถามไม่เหมือนกับการกำหนดพารามิเตอร์อัตโนมัติซึ่งคุณดูเหมือนจะบอกใบ้ เช่นเดียวกับในอ่านก่อนที่คุณโพสต์
mustaccio

@mustaccio จริงๆแล้วอย่างน้อย MS ก็แนะนำทั้งสองอย่างในเวลาเดียวกัน
TomTom

5

รอ แต่ทำไม

ตัวเลือกที่ 1 หมายถึงคุณต้องเขียนรูทีนการฆ่าเชื้อสำหรับอินพุตทุกประเภทในขณะที่ตัวเลือกที่ 2 นั้นมีข้อผิดพลาดน้อยและรหัสน้อยสำหรับคุณที่จะเขียน / ทดสอบ / ดูแลรักษา

เกือบจะแน่นอน"การดูแลคำเตือนทั้งหมด"อาจซับซ้อนกว่าที่คุณคิดและภาษาของคุณ (เช่น Java PreparedStatement) มีความซับซ้อนมากกว่าที่คุณคิด

คำสั่งที่เตรียมไว้หรือเคียวรี parametrized จะถูกคอมไพล์ล่วงหน้าในเซิร์ฟเวอร์ฐานข้อมูลดังนั้นเมื่อตั้งค่าพารามิเตอร์จะไม่มีการต่อ SQL เข้าด้วยกันเนื่องจากแบบสอบถามไม่ได้เป็นสตริง SQL อีกต่อไป ข้อได้เปรียบ aditional คือ RDBMS แคชแบบสอบถามและการโทรที่ตามมาจะถือว่าเป็น SQL เดียวกันแม้ว่าค่าพารามิเตอร์จะแตกต่างกันในขณะที่มีการเชื่อมต่อ SQL ทุกครั้งที่มีการเรียกใช้แบบสอบถามด้วยค่าที่แตกต่างกันแบบสอบถามที่แตกต่างกันและ RDBMS สร้างแผนการดำเนินการอีกครั้ง ฯลฯ


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

1
ทำไม? หากพารามิเตอร์ไม่ถูกวิเคราะห์คำหรือตีความว่าไม่มีเหตุผลที่จะหลบหนีบางสิ่งบางอย่าง
talex

11
ฉันคิดว่าคุณมีภาพที่ไม่ถูกต้องเกี่ยวกับการทำงานของพารามิเตอร์การสืบค้น มันไม่ได้เป็นเพียงแค่กรณีของพารามิเตอร์ที่ถูกทดแทนในภายหลังพวกเขาจะไม่ถูกทดแทนมา DBMS เปลี่ยนแบบสอบถามเป็น "แผน" ชุดของขั้นตอนที่จะดำเนินการเพื่อให้ได้ผลลัพธ์ของคุณ ในเคียวรีที่กำหนดพารามิเตอร์แผนนั้นจะเหมือนฟังก์ชัน: มันมีตัวแปรจำนวนหนึ่งที่จำเป็นต้องให้เมื่อดำเนินการ เมื่อถึงเวลาที่ตัวแปรถูกจัดเตรียมไว้สตริง SQL จะถูกลืมอย่างสมบูรณ์และแผนจะถูกดำเนินการด้วยค่าที่กำหนด
IMSoP

2
@IMSoP นั่นเป็นความเข้าใจผิดของฉัน ถึงแม้ว่าผมจะคิดว่ามันเป็นหนึ่งที่พบบ่อยที่สุดเท่าที่คุณสามารถดูได้ในทั้งสองได้รับการโหวตมากที่สุดคำตอบสำหรับคำถามนี้ใน SO stackoverflow.com/questions/3271249/... ฉันอ่านเกี่ยวกับเรื่องนี้และคุณพูดถูก ฉันแก้ไขคำตอบ
Tulains Córdova

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

1

ลองจินตนาการว่าวิธีการ "ฆ่าเชื้อโรคกรองและเข้ารหัส" ในอุดมคติจะเป็นอย่างไร

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

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

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

ดังนั้นสิ่งต่าง ๆ อาจจะง่ายขึ้นถ้าฐานข้อมูลจัดการการทดแทนให้คุณเช่นกัน - มันรู้อยู่แล้วว่าแบบสอบถามชนิดใดที่คาดหวังและวิธีการเข้ารหัสข้อมูลอย่างปลอดภัยและวิธีการเปลี่ยนเป็นแบบสอบถามของคุณอย่างปลอดภัยดังนั้นคุณจึงไม่ต้องกังวล ในรหัสของคุณ

ณ จุดนี้เราเพิ่งสร้างการสืบค้นแบบกำหนดพารามิเตอร์

และเมื่อมีการสอบถามพารามิเตอร์มันจะเปิดโอกาสใหม่เช่นการเพิ่มประสิทธิภาพและการตรวจสอบที่ง่ายขึ้น

การเข้ารหัสยากที่จะทำถูกต้องและการเข้ารหัสเสร็จถูกแยกไม่ออกจากพารามิเตอร์

หากคุณชอบสตริงแก้ไขเป็นวิธีการค้นหาอาคารมีสองภาษา (Scala และ ES2015 มาใจ) ที่มีการแก้ไขสตริง pluggable จึงมี เป็น ห้องสมุดที่ช่วยให้คุณเขียนแบบสอบถาม parameterised ที่มีลักษณะเหมือนสตริงแก้ไข แต่ ปลอดภัยจากการฉีด SQL - ดังนั้นในไวยากรณ์ ES2015:

import {sql} from 'cool-sql-library'

let result = sql`select *
    from users
    where user_id = ${user_id}
      and password_hash = ${password_hash}`.execute()

console.log(result)

1
"การเข้ารหัสทำได้ยาก" - ฮ่าฮ่าฮ่า มันไม่ใช่. วันหรือสองวันมันเป็นเอกสารทั้งหมด ฉันเขียนโปรแกรมเข้ารหัสเมื่อหลายปีที่ผ่านมาสำหรับ ORM (เนื่องจากเซิร์ฟเวอร์ sql มีข้อ จำกัด เกี่ยวกับพารามิเตอร์และดังนั้นจึงเป็นปัญหาในการแทรกแถว 5,000-10000 ในคำสั่งเดียว (ย้อนกลับ 15 ปีที่แล้ว) ฉันจำไม่ได้ว่าเป็นปัญหาใหญ่
TomTom

1
บางที SQL Server นั้นเพียงพอปกติแล้วว่ามันไม่ใช่ปัญหา แต่ฉันพบปัญหาในฐานข้อมูลอื่น - กรณีมุมที่มีการเข้ารหัสอักขระที่ไม่ตรงกันตัวเลือกการกำหนดค่าที่ไม่ชัดเจนตัวเลือกการกำหนดค่าที่ไม่ชัดเจน ทุกอย่างสามารถแก้ไขได้ แต่ต้องมีความเข้าใจอย่างย่อเกี่ยวกับนิสัยใจคอของ DB (ฉันกำลังมองคุณ, MySQL และ Oracle)
James_pic

3
@TomTom การเข้ารหัสยากจริง ๆ ที่จะทำให้ถูกต้องเมื่อคุณคำนึงถึงเวลา คุณจะทำอย่างไรเมื่อผู้ขาย DB ของคุณตัดสินใจที่จะสร้างรูปแบบความคิดเห็นใหม่ในรุ่นถัดไปหรือเมื่อ Bareword กลายเป็นคำหลักใหม่ในการอัพเกรด ในทางทฤษฎีคุณสามารถเข้ารหัสได้ดีสำหรับ RDBMS ของคุณเพียงครั้งเดียวและผิดในการแก้ไขครั้งต่อไป อย่าแม้แต่เริ่มต้นกับสิ่งที่เกิดขึ้นเมื่อคุณสลับผู้ขายไปยังผู้ที่มีความคิดเห็นแบบ
Eric

@ เอริคที่น่ากลัวตรงไปตรงมา (ฉันใช้ Postgres หากมีหูดที่แปลกประหลาดเช่นนี้ที่ฉันยังไม่เคยพบมาก่อน)
Wildcard

0

ในตัวเลือก 1 คุณกำลังทำงานกับชุดอินพุต size = infinity ที่คุณพยายามแมปกับขนาดเอาต์พุตที่มีขนาดใหญ่มาก ในตัวเลือก 2 คุณได้ จำกัด อินพุตของคุณกับสิ่งที่คุณเลือก ในคำอื่น ๆ :

  1. คัดกรองและกรอง [ infinity ] อย่างระมัดระวังสำหรับ [การค้นหา SQL ปลอดภัยทั้งหมด ]
  2. การใช้ [ สถานการณ์ล่วงหน้าที่ จำกัด อยู่ในขอบเขตของคุณ ]

ตามคำตอบอื่น ๆ ดูเหมือนว่าจะมีประโยชน์ด้านประสิทธิภาพบางประการจากการ จำกัด ขอบเขตของคุณให้อยู่ห่างจากระยะอนันต์และไปสู่สิ่งที่จัดการได้


0

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

ช่องโหว่ในการฉีด SQL นั้น isomorphic ต่อ buffer overflow ในภาษาเช่น C. History แสดงให้เห็นว่า buffer overflows นั้นยากต่อการป้องกันอย่างมาก - แม้แต่รหัสที่สำคัญยิ่งที่ต้องตรวจสอบแบบเปิดมักมีช่องโหว่ดังกล่าวอยู่บ่อยครั้ง

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

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

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


ทั้งหมดนี้เป็นสิ่งที่ดีและสวยงาม แต่ไม่ได้ตอบคำถามตามชื่อเรื่องเลย
TomTom

1
@TomTom: คุณหมายถึงอะไร คำถามนั้นเกี่ยวกับสาเหตุที่แบบสอบถามแบบกำหนดพารามิเตอร์เป็นกลไกที่ต้องการในการป้องกันการฉีด SQL คำตอบของฉันอธิบายว่าทำไมเคียวรีแบบพารามิเตอร์จึงปลอดภัยและมีประสิทธิภาพมากกว่าการฆ่าเชื้ออินพุตของผู้ใช้
Daniel Pryden

ฉันขอโทษ แต่คำถามของฉันอ่านว่า "ทำไมกลไกการป้องกันการฉีด SQL ถึงวิวัฒนาการไปในทิศทางของการใช้ Parameterized Queries" พวกเขาไม่ได้. มันไม่เกี่ยวกับตอนนี้มันเป็นเรื่องของประวัติศาสตร์
TomTom

0

ฉัน Alredy เขียนเกี่ยวกับเรื่องนี้ที่นี่: https://stackoverflow.com/questions/6786034/can-parameterized-statement-stop-all-sql-inject/33033576#33033576

แต่เพื่อให้ง่าย:

วิธีการทำงานของการสืบค้นแบบกำหนดพารามิเตอร์คือ sqlQuery ถูกส่งไปเป็นแบบสอบถามและฐานข้อมูลรู้ว่าสิ่งที่แบบสอบถามนี้จะทำและจากนั้นจะแทรกชื่อผู้ใช้และรหัสผ่านเป็นค่า ซึ่งหมายความว่าพวกเขาไม่สามารถมีผลต่อแบบสอบถามได้เนื่องจากฐานข้อมูลทราบแล้วว่าแบบสอบถามจะทำอะไร ดังนั้นในกรณีนี้มันจะค้นหาชื่อผู้ใช้ของ "ไม่มีใครหรือ 1 = 1 '-" และรหัสผ่านเปล่าซึ่งควรเป็นเท็จ

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


0

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

ที่กล่าวว่ามันไม่ยากมากที่จะเขียนฟังก์ชั่น C ที่ใช้สตริง C เป็นอาร์กิวเมนต์ของมันและผลิตสตริงที่แตกต่างกันซึ่งมีลักษณะเหมือนตัวอักษรสตริงในรหัสต้นฉบับ C ที่แสดงถึงสตริงเดียวกัน ตัวอย่างเช่นฟังก์ชันนั้นจะแปล abc เป็น "abc" และ "abc" เป็น "\" abc \ "" และ "\" abc \ "" เป็น "\" \\ "abc \\" \ "" (ถ้ามันดูผิดสำหรับคุณนั่นคือ html มันถูกต้องเมื่อฉันพิมพ์ลงไป แต่ไม่ใช่เมื่อมันปรากฏขึ้น) และเมื่อเขียนฟังก์ชัน C แล้วก็ไม่ยากเลยที่จะสร้างซอร์สโค้ด C ที่ ข้อความจากช่องป้อนข้อมูลที่จัดทำโดยผู้ใช้จะกลายเป็นตัวอักษรสตริง C นั่นไม่ใช่เรื่องยากที่จะทำให้ปลอดภัย ทำไมนักพัฒนา SQL จะไม่ใช้วิธีการนั้นเป็นวิธีหลีกเลี่ยง SQL injections อยู่นอกเหนือฉัน

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

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

ดังนั้นจากจุดของนักพัฒนาที่ใช้ภาษาที่รวบรวมการฆ่าเชื้อเป็นสิ่งที่จะไม่เกิดขึ้นกับฉัน ความจำเป็นในการฆ่าเชื้อโรคนั้นเป็นบ้า การค้นหาแบบกำหนดพารามิเตอร์เป็นวิธีแก้ปัญหาที่ชัดเจน

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


-2

ปัญหาหลักคือแฮ็กเกอร์พบวิธีที่จะล้อมรอบสุขอนามัยในขณะที่การค้นหาแบบ parametrized เป็นกระบวนการที่มีอยู่ซึ่งทำงานได้อย่างสมบูรณ์แบบพร้อมกับสิทธิประโยชน์เพิ่มเติมของประสิทธิภาพและหน่วยความจำ

บางคนทำให้ปัญหาง่ายขึ้นเพราะ "มันเป็นเพียงคำพูดเดียวและเครื่องหมายคำพูดคู่" แต่แฮ็กเกอร์ค้นพบวิธีที่ชาญฉลาดในการหลีกเลี่ยงการตรวจจับเช่นใช้การเข้ารหัสที่แตกต่างกันหรือการใช้ฟังก์ชั่นฐานข้อมูล

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

ในทางกลับกันเพียงแค่ใช้แบบสอบถามที่ต่อกันเป็นเรื่องของการเรียนรู้ที่จะใช้และทำความคุ้นเคยกับมัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.