ในบทความก่อนหน้านี้ เราได้พูดคุยเกี่ยวกับแก่นแท้ของช่องโหว่การโจมตี SQL ที่เกิดจากการเขียนโค้ดที่ไม่เหมาะสมโดยโปรแกรมเมอร์ ตอนนี้เราจะพูดถึงวิธีการเขียนโค้ดอย่างถูกต้องเพื่อไม่ให้ถูกโจมตีจากการฉีด SQL ก่อนที่จะพูดถึงเรื่องนี้ เรามาลองดูโค้ดกันก่อน:
คัดลอกรหัสรหัสดังต่อไปนี้:
สลัว sql_injdata,SQL_inj,SQL_Get,SQL_Data,Sql_Post
SQL_injdata = '|และ|exec|insert|select|delete|update|count|*|%|chr|mid|master|truncate|char|declare
SQL_inj = แยก(SQL_Injdata,|)
ถ้า Request.QueryString<> จากนั้น
สำหรับแต่ละ SQL_Get ใน Request.QueryString
สำหรับ SQL_Data=0 ถึง Ubound(SQL_inj)
ถ้า instr(Request.QueryString(SQL_Get),Sql_Inj(Sql_DATA))>0 จากนั้น
Response.Write <Script Language=javascript>alert('SQL anti-injection system prompts, please do not try to inject again!'); history.back(-1)</Script>
การตอบกลับสิ้นสุด
สิ้นสุดถ้า
ต่อไป
ต่อไป
สิ้นสุดถ้า
ถ้า Request.Form<> จากนั้น
สำหรับแต่ละ Sql_Post ใน Request.Form
สำหรับ SQL_Data=0 ถึง Ubound(SQL_inj)
ถ้า instr(Request.Form(Sql_Post),Sql_Inj(Sql_DATA))>0 จากนั้น
Response.Write <Script Language=javascript>alert('SQL anti-injection system prompts, please do not try to inject again!'); history.back(-1)</Script>
การตอบกลับสิ้นสุด
สิ้นสุดถ้า
ต่อไป
ต่อไป
สิ้นสุดถ้า
นี่คือส่วนหนึ่งของโค้ดต่อต้านการฉีด ASP ที่ได้รับความนิยมอย่างกว้างขวางบนอินเทอร์เน็ต แนวคิดคือเพื่อตรวจสอบข้อมูลที่ส่งโดยวิธี Post และวิธี Get และเพื่อป้องกันการฉีด SQL โดยการกรองอักขระที่ละเอียดอ่อนเช่น Insert, Update และ ฯลฯ ตามทฤษฎีแล้ว ถ้าเรากรองอักขระได้เพียงพอ เราก็รับประกันได้ว่าเราจะไม่ถูกโจมตีโดยการแทรก SQL แต่โปรดใช้ความระมัดระวัง อ่านโค้ดนี้และใส่ใจกับวิธีการตัดสิน มันถูกตัดสินผ่านฟังก์ชัน instr กล่าวคือ ถ้าฉันต้องการกรองอักขระ และ ไม่ใช่แค่คำ และที่ถูกกรองเท่านั้น แต่ยังรวมถึงคำทั้งหมดด้วย ที่มี และ. ทุกคำที่มีการผสมอักขระต่อไปนี้ถูกกรองออก เช่น เกาะ แผ่นดินใหญ่ มือ... หากกรองอักขระเหล่านี้ออก จะมีใครยังยินดีใช้คำเหล่านั้นหรือไม่? ดังนั้นวิธีการกรองอักขระที่ละเอียดอ่อนนี้ไม่มีความหมายเลย สิ่งที่ทำให้ฉันประหลาดใจก็คือขยะชิ้นนี้ถูกโพสต์บนอินเทอร์เน็ตแบบคลาสสิกจริงๆ
บางคนกล่าวว่าการโจมตีแบบแทรก SQL เกิดจากการประกบสตริงการสืบค้น SQL ดังนั้นการใช้ขั้นตอนการจัดเก็บโดยไม่ต้องประกบสตริงการสืบค้น SQL จึงสามารถป้องกันคุณจากการโจมตีแบบแทรก SQL ได้ ไม่จำเป็นเลย เราจะมาดูตัวอย่างการโจมตีแบบ Stored Procedure Injection กัน
รหัสของกระบวนงานที่เก็บไว้ dt_GetNews เป็นดังนี้:
สร้างขั้นตอน dt_GetNews
@newstypeint
เช่น
เลือก * จาก news โดยที่ newstype=@newstype
ไป
รหัสโทร:
-
การเชื่อมต่อแบบสลัว
ตั้งค่า adoconnection=server.createobject (adodb.connection)
'........รหัสที่เกี่ยวข้องสำหรับการสร้างการเชื่อมต่อฐานข้อมูลจะถูกละไว้ที่นี่
adoconnection.execute exec dt_GetNews + คำขอ (ประเภทข่าว)
adoconnection.ปิด
-
หากค่าของ request(newstype) เท่ากับ 1 ผลลัพธ์ของการดำเนินการคือการส่งคืนเรคคอร์ดทั้งหมดโดยที่ฟิลด์ newstype ในตารางข่าวเป็น 1 อย่างไรก็ตาม หากค่าของ request(newstype) คือ 1 ผลลัพธ์ที่ส่งคืนคือตารางข่าวถูกลบ
จากตัวอย่างนี้จะเห็นได้ว่าแม้การใช้ขั้นตอนการจัดเก็บจะยังคงถูกโจมตี นอกจากนี้ ให้เลือก * จากข่าวสารโดยที่ newstype=@newstype ไม่ได้ประกบกัน ดังนั้นจึงไม่มีการเชื่อมต่อที่หลีกเลี่ยงไม่ได้ระหว่างสตริงการสืบค้น SQL แบบประกบและการโจมตีแบบแทรก SQL ขั้นตอนการจัดเก็บอาจไม่สามารถป้องกันการโจมตีจากการฉีดยาได้
ดังนั้นคุณจะเขียนมันอย่างไรโดยไม่ถูกโจมตีจากการฉีด SQL ด้านล่างนี้ฉันจะแนะนำวิธีการขั้นสูงสุด พูดตรงๆ มันง่ายและดั้งเดิมมาก ซึ่งก็คือการตรวจสอบประเภทข้อมูลและการแทนที่เครื่องหมายคำพูดเดี่ยว ไม่ว่าจะเป็น Oracle, Sql Server, mySql, Access หรือฐานข้อมูลเชิงสัมพันธ์อื่นๆ ประเภทฟิลด์สามารถแบ่งคร่าวๆ ได้เป็นสองประเภท: ประเภทตัวเลข (เช่น int, float ฯลฯ) และประเภทอักขระ (เช่น char, varchar เป็นต้น ) คำสั่ง SQL ที่เกี่ยวข้องจะแตกต่างกันเล็กน้อยขึ้นอยู่กับประเภทของฟิลด์ เช่น:
ฟิลด์ประเภทข่าวใน Select * from news โดยที่ newstype=1 ต้องเป็นฟิลด์ตัวเลข
เลือก * จาก news โดยที่ newstype='social news' ฟิลด์ newstype จะต้องเป็นฟิลด์อักขระ
สำหรับช่องตัวเลข สิ่งที่เราต้องทำคือตรวจสอบประเภทข้อมูลของพารามิเตอร์ ตัวอย่างเช่น เมื่อเราสร้างคำสั่งแบบสอบถามโดยใช้ select * from news โดยที่ newstype=+v_newstype เราต้องตรวจสอบประเภทข้อมูลของตัวแปร v_newstype อย่างน้อยต้องเป็นตัวเลขซึ่งอาจเป็นจำนวนเต็มหรือจำนวนจุดลอยตัวก็ได้ หากมีการตรวจสอบ ให้เลือก * จาก news โดยที่ newstype=+v_newstype จะไม่สร้างสิ่งที่คล้ายกับการเลือก * จาก news โดยที่ newstype=1 ;หยด งบเช่นข่าวตาราง สาเหตุที่ ASP เสี่ยงต่อการถูกโจมตีมากกว่า ASP.Net, JSP ฯลฯ เป็นเพราะตัวแปรใน ASP ไม่จำเป็นต้องประกาศและประเภทของตัวแปรไม่ชัดเจน
สำหรับช่องอักขระ สิ่งที่เราต้องทำคือประมวลผลเครื่องหมายคำพูดเดี่ยว (') วิธีการประมวลผลคือการแทนที่เครื่องหมายคำพูดเดี่ยวด้วยเครื่องหมายคำพูดเดี่ยว 2 อัน ('') เมื่อใช้ newstype='+v_newstype+' เพื่อสร้างคำสั่งแบบสอบถาม เครื่องหมายคำพูดเดี่ยวใน v_newstype จะต้องถูกแทนที่ด้วยเครื่องหมายคำพูดเดี่ยว 2 อัน เนื่องจากใน SQL ส่วนที่ปิดล้อมด้วยเครื่องหมายคำพูดเดี่ยว 2 อันแสดงถึงสตริง และ A single สองอันติดต่อกัน เครื่องหมายคำพูดแสดงถึงอักขระเครื่องหมายคำพูดเดี่ยว หลังจากการประมวลผล เราจะดูวิธีการก่อสร้างของ select * from news โดยที่ newstype='+v_newstype+' เมื่อค่าของ v_newstype คือ:
ข่าวโซเชียล';ข่าวโต๊ะวาง--
หลังจากแทนที่เครื่องหมายคำพูดเดียวเป็นสองเครื่องหมายคำพูดเดี่ยว ค่าของ v_newstype จะกลายเป็น:
ข่าวโซเชียล'';ข่าวโต๊ะวาง--
คำสั่ง SQL ที่สร้างขึ้นจะกลายเป็น:
เลือก * จากข่าวโดยที่ newstype='social news'';drop table news—'
ผลลัพธ์ของแบบสอบถามคือการส่งคืนระเบียนที่มีค่าของฟิลด์ประเภทข่าวในตารางข่าวคือ ข่าวโซเชียล '; ข่าวตารางหล่น-- โดยไม่ทำให้ตารางข่าวถูกลบเหมือนเมื่อก่อน
นอกจากนี้ ไม่ใช่แค่คำสั่ง Select ที่ต้องประมวลผล เช่น Insert, Update, Delete, Exec ฯลฯ คุณสามารถดูวิธีการฉีดต่อไปนี้:
ในโครงสร้างแทรกเข้าไปในค่า news(title) ('+v_title+')
เมื่อ v_title=123';วางข่าวตาราง--';
เมื่ออัพเดตชุดข่าว /> เมื่อ v_title=123'-- หรือ v_id=1;drop table news-- จึงไม่ใช่ปัญหาเฉพาะกับคำสั่ง Select เท่านั้น แต่ข้อความอื่นๆ อาจมีปัญหา อย่าเพิ่งเน้น Select
กล่าวโดยสรุป หลังจากตรวจสอบประเภทข้อมูลและประมวลผลอักขระเครื่องหมายคำพูดเดี่ยวแล้ว แม้ว่าจะมีความสามารถทั้งหมดก็ตาม ก็ไม่สามารถหลุดออกจากฝ่ามือของตถาคตของเราได้