อะไรคือความเสี่ยง / ความเสี่ยงด้านความปลอดภัยของโปรแกรมเมอร์ C ทุกคนที่ต้องระวัง? [ปิด]


13

มีความเสี่ยงด้านความปลอดภัยมากมายจากการสัมผัสอย่างใกล้ชิดกับฮาร์ดแวร์ซึ่งต่างจากการใช้ API ที่ผ่านการทดสอบและผ่านการพิสูจน์แล้วจากภาษาโปรแกรมระดับสูง มันง่ายกว่ามากที่จะทำให้บัฟเฟอร์ล้นใน C กว่าในภาษาเช่น Java

อะไรคือความเสี่ยงหรือช่องโหว่ (เช่น buffer overflow) ที่โปรแกรมเมอร์ C ทุกคนควรระวัง (ช่องโหว่ IE ที่เกี่ยวข้องกับโปรแกรมเมอร์ C) ปัญหาเหล่านี้นำไปสู่ปัญหาอะไร จะหลีกเลี่ยงพวกเขาได้อย่างไรและอะไรคือข้อผิดพลาดทั่วไปที่ทำให้สิ่งเหล่านี้เกิดขึ้นในโปรแกรม?


เกี่ยวกับรายการนี้: owasp.org/index.php/Category:OWASP_Top_Ten_Project ต้องการ อะไรมากกว่านี้?
S.Lott

2
@ S.Lott: ดูเหมือนว่าจะเป็นเรื่องความปลอดภัยในการพัฒนาเว็บเป็นอย่างมาก ดูเหมือนว่าจะมีทรัพยากรเพิ่มเติมโดยทั่วไปมากกว่าสิ่งที่ฉันขอจริง ๆ ดูเหมือนว่า
Anto

@ ถึง: โปรดอัปเดตคำถามเพื่อแยกความแตกต่างระหว่างทรัพยากรทั้งหมดเกี่ยวกับความปลอดภัยและความปลอดภัยที่คุณถาม
S.Lott

@ S.Lott: ฉันไม่แน่ใจว่าคุณหมายถึงอะไร ฉันขอความปลอดภัยซึ่งมีความสำคัญกับโปรแกรมเมอร์ C ส่วนใหญ่นั่นคือสิ่งต่าง ๆ เช่นบัฟเฟอร์ล้นและสิ่งอื่น ๆ ที่เป็นไปได้ใน C.
Anto

@ ถึง: "ดูเหมือนว่าจะมีแหล่งข้อมูลเพิ่มเติมเกี่ยวกับ [ความปลอดภัยบนเว็บ?] โดยทั่วไปมากกว่าที่ฉันขอจริง ๆ " ดูเหมือนจะบอกว่าคุณถามเกี่ยวกับความปลอดภัยที่ไม่ใช่ความปลอดภัยของเว็บ จริงหรือไม่? ถ้าเป็นเช่นนั้นโปรดอัปเดตคำถามเพื่ออธิบายสิ่งที่คุณกำลังมองหา เท็จ? จากนั้นคุณจะถูกถามเกี่ยวกับความปลอดภัยของเว็บซึ่งในกรณีนี้ทำไมไม่ได้เป็นรายการ OWASP ที่กล่าวถึงในคำถามของคุณหรือไม่
S.Lott

คำตอบ:


13

บัฟเฟอร์มากเกินไปนั้นใหญ่เกินไป ไม่มีสิ่งใดใน C ที่ตรวจสอบช่วงโดยค่าเริ่มต้นดังนั้นจึงเป็นเรื่องง่ายมากที่จะเขียนทับบัฟเฟอร์ มีฟังก์ชั่นไลบรารีมาตรฐานgets()ที่ไม่สามารถหยุดการโอเวอร์โฟลว์บัฟเฟอร์และไม่ควรใช้

มีเทคนิคระดับการนำไปปฏิบัติบางอย่างเพื่อขัดขวางการใช้ประโยชน์เช่น scrambling heap blocks แต่จะไม่หยุดบัฟเฟอร์ล้นในบัฟเฟอร์ในเครื่องซึ่งมักจะทำสิ่งที่น่าสนใจเช่นเปลี่ยนที่อยู่ที่ฟังก์ชันจะกลับไป

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

ปัญหาที่เกี่ยวข้องคือปัญหาของการเขียนลงในบัฟเฟอร์เล็กเกินไปโดยตัวละครตัวหนึ่งลืมว่าสตริง C ที่มีความยาว n ตัวต้องใช้ตัวอักษร n + 1 ในหน่วยความจำเนื่องจากตัว'\0'ยุติ หากผู้โจมตีสามารถจัดการเก็บสตริงโดยไม่ต้องใช้เทอร์มินัลฟังก์ชัน C ใด ๆ ที่คาดว่าสตริงจะดำเนินการต่อไปจนกว่าจะถึงศูนย์ไบต์ซึ่งอาจส่งผลให้คัดลอกหรือส่งออกข้อมูลมากกว่าที่ต้องการ (หรือกดปุ่มหน่วยความจำ ) การแก้ปัญหาอีกครั้งคือการรับรู้การดูแลและการตรวจสอบรหัส

มีความเสี่ยงอีกอย่างกับprintf()ครอบครัว หากคุณเคยเขียนchar * str; ... printf(str);คุณกำลังตั้งค่าตัวเองสำหรับปัญหาหากstrมี '%' เมื่อพิมพ์ %nสั่งรูปแบบช่วยให้printf()การเขียนในหน่วยความจำ การแก้ปัญหาคือหรือprintf("%s", str); puts(str);(นอกจากนี้ให้ใช้ C99 snprintf()แทนsprintf())

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

intอย่าลืมว่าค่าคงที่ตัวละครในซีเป็นจริง เขียนสิ่งที่ต้องการchar c; while((c = getchar()) != EOF) ...ได้อย่างง่ายดายสามารถล้มเหลวเนื่องจากจะไม่สามารถแทนได้ในEOFchar

มีข้อผิดพลาดลักษณะ C มากกว่าที่ฉันคิดได้ แต่สิ่งเหล่านี้อาจทำให้เกิดปัญหาด้านความปลอดภัย


ไม่จำเป็นต้องใช้printf("%s", str)สตริงเปล่าเมื่อputs(str)จะทำงานเดียวกัน
Blrfl

@Blrfl แต่putsผนวกอักขระขึ้นบรรทัดใหม่ขณะที่printfไม่
rightfold

สามารถทำได้fputs(str, stdout)ซึ่งไม่ได้
Blrfl

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

@DavidThornley: C11 & C ++ 14 มาตรฐานลบได้รับ () ฟังก์ชั่นจากห้องสมุดมาตรฐานเนื่องจากความเป็นอันตราย
Destructor

5

บางส่วนของความเสี่ยง C-เฉพาะรวมถึง: บัฟเฟอร์ล้น , การจัดรูปแบบการโจมตีสตริงและล้นจำนวนเต็ม


1
ไม่มีอะไรเฉพาะ C เกี่ยวกับบัฟเฟอร์โอเวอร์โฟลว์ - ภาษาใด ๆ ที่มีพอยน์เตอร์สามารถมีได้ โอเวอร์โฟลจำนวนเต็มมีผลกับทุกภาษาและสามารถเกิดขึ้นได้ง่ายในโค้ดที่มีการจัดการด้วย
Steve

1
@ Steve มันไม่ได้เป็นตัวชี้ที่ทำให้เกิดปัญหา แต่วิธีการที่ภาษาไม่บังคับใช้ขอบเขตของอาร์เรย์
Doug T.

2
@ คำถามที่ไม่ได้ถามเกี่ยวกับสิ่งที่เกี่ยวข้องกับ C เท่านั้น แต่สิ่งที่โปรแกรมเมอร์ C ควรระวัง
AttackHobo

1
@Steve: C มีความไวต่อการผิดปกติในการบัฟเฟอร์ล้นส่วนหนึ่งเป็นเพราะขาดการสนับสนุนการตรวจสอบช่วงและจำนวนฟังก์ชั่นห้องสมุดที่จะล้นบัฟเฟอร์สำหรับคุณอย่างมีความสุข
David Thornley

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

4

นี่คือความเสี่ยงที่พลาดง่ายซึ่งอาจทำให้เกิดปัญหาซึ่งต้องใช้เวลาหลายชั่วโมงในการแก้ไข

พิจารณารหัสต่อไปนี้ซึ่งจะรวบรวมโดยไม่มีปัญหา

if(lpstr_current_state = CONST_EMERGENCY_STATE_HOLY_CRAP)
{
    do_warn_joint_chiefs_of_staff_of_nuclear_attack();
}

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

if(CONST_EMERGENCY_STATE_HOLY_CRAP = lpstr_current_state)
{
    do_warn_joint_chiefs_of_staff_of_nuclear_attack();
}

จากนั้นคุณสามารถพูดกับตัวเองว่า "อึศักดิ์สิทธิ์ที่อาจไม่ดี" ในขณะที่แก้ไขรหัสเพื่ออ่าน ...

if(CONST_EMERGENCY_STATE_HOLY_CRAP == lpstr_current_state)
{
    do_warn_joint_chiefs_of_staff_of_nuclear_attack();
}

7
นั่นเป็นเรื่องง่ายสำหรับคอมไพเลอร์ที่จะจับและตั้งค่าสถานะเป็นคำเตือนซึ่งแตกต่างจากปัญหาอื่น ๆ น่าเสียดายที่คอมไพเลอร์ไม่ใช่ทุกตัวที่ทำให้ง่ายต่อการทำ
David Thornley

2
ที่สามารถเกิดขึ้นในภาษาอื่น ๆ กว่า C, ภาษาใด ๆ ที่ใช้และ= ==
FrustratedWithFormsDesigner

3
นี่ไม่ใช่จุดอ่อนด้านความปลอดภัยนี่เป็นจุดบกพร่อง
Chris Pitman

1
สิ่งเหล่านี้เรียกว่าเงื่อนไขโยดา

2
@Kristofer Hoch: หากเราจะเรียกความเสี่ยงจากข้อผิดพลาด C และพิจารณาที่นี่เราจะต้องมีฟอรัมที่ใหญ่กว่านี้
David Thornley

0

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

ดังนั้นเมื่อคุณคิดว่า "ไม่มีใครในใจที่ถูกต้องของพวกเขาจะ ... " คุณต้องคิดทันที "ยกเว้นคนที่ต้องการแฮ็คเข้าสู่คอมพิวเตอร์ของคนอื่นจะทำอย่างนั้น"

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


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