นี่คือปลั๊กอินของ Phan เพื่อลองและตรวจจับปัญหาด้านความปลอดภัย (เช่น XSS) มันติดตามได้ตลอดเวลาที่ผู้ใช้สามารถแก้ไขตัวแปรและตรวจสอบเพื่อดูว่าตัวแปรดังกล่าวจะถูกหลบหนีก่อนที่จะถูกส่งออกเป็น HTML หรือใช้เป็นแบบสอบถาม SQL ฯลฯ
รองรับโครงการ PHP ทั่วไปและยังมีโหมดเฉพาะสำหรับรหัส MediaWiki (วิเคราะห์ hooks, htmlforms และวิธีการฐานข้อมูล)
มีการสาธิตเว็บ
$ composer require --dev mediawiki/phan-taint-check-plugin
ปลั๊กอินสามารถใช้ในโหมด "คู่มือ" และ "สแตนด์อโลน" ทั้งสอง อดีตเป็นตัวเลือกที่ดีที่สุดหากโครงการของคุณทำงานอยู่แล้วและแทบจะไม่จำเป็นต้องมีการกำหนดค่า หลังควรใช้เฉพาะในกรณีที่คุณไม่ต้องการเพิ่ม Phan ลงในโครงการของคุณและไม่ได้รับการสนับสนุนสำหรับรหัสที่เกี่ยวข้องกับ MediaWiki สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการใช้ปลั๊กอินนี้ของ Wikimedia โปรดดู https://www.mediawiki.org/wiki/phan-taint-check-plugin
คุณเพียงแค่ต้องเพิ่มการตรวจสอบ taint-check ในส่วน plugins ของการกำหนดค่า Phan ของคุณ สมมติว่า taint-check อยู่ในตำแหน่งผู้ขายมาตรฐานเช่น $seccheckPath = 'vendor/mediawiki/phan-taint-check-plugin/'; ไฟล์ที่จะรวมคือ "$seccheckPath/GenericSecurityCheckPlugin.php" สำหรับโครงการทั่วไปและ "$seccheckPath/MediaWikiSecurityCheckPlugin.php" สำหรับโครงการ MediaWiki
นอกจากนี้ตรวจสอบให้แน่ใจว่าโหมดด่วนถูกปิดใช้งานหรือปลั๊กอินจะไม่ทำงาน:
' quick_mode ' => false คุณควรเพิ่ม SecurityCheck-LikelyFalsePositive และ SecurityCheck-PHPSerializeInjection เพื่อ suppress_issue_types (หลังมีอัตราการบวกเท็จสูง)
จากนั้นเรียกใช้ Phan ตามปกติ:
$ vendor/bin/phan -d . --long-progress-bar
การดำเนินการ phan ด้วย --analyze-twice จะจับปัญหาความปลอดภัยเพิ่มเติมที่อาจไม่มีใครสังเกตเห็นในขั้นตอนการวิเคราะห์ปกติ ข้อ จำกัด ที่ทราบของเรื่องนี้คือปัญหาเดียวกันอาจถูกรายงานมากกว่าหนึ่งครั้งด้วยสายที่เกิดขึ้นแตกต่างกัน
คุณสามารถเรียกใช้การตรวจสอบ taint-check ผ่าน:
$ ./vendor/bin/seccheck
คุณอาจต้องการเพิ่มนามแฝงสคริปต์นักแต่งเพลงสำหรับสิ่งนั้น:
"scripts" : {
"seccheck" : " seccheck "
}โปรดทราบว่าข้อดีที่ผิดพลาดถูกปิดใช้งานโดยค่าเริ่มต้น
ปลั๊กอินจะส่งออกประเภทปัญหาต่าง ๆ ขึ้นอยู่กับสิ่งที่ตรวจพบ ประเภทปัญหาที่ส่งออกคือ:
SecurityCheck-XSSSecurityCheck-SQLInjectionSecurityCheck-ShellInjectionSecurityCheck-PHPSerializeInjection - สำหรับเมื่อมีคนทำ unserialize( $_GET['d'] ); ประเภทปัญหานี้ดูเหมือนจะมีอัตราบวกเท็จสูงในปัจจุบันSecurityCheck-CUSTOM1 - เพื่อให้ผู้คนมีประเภท Taint ที่กำหนดเองSecurityCheck-CUSTOM2 - DittoSecurityCheck-DoubleEscaped - ตรวจพบว่า HTML กำลังหลบหนีสองครั้งSecurityCheck-RCE - การดำเนินการรหัสระยะไกลเช่น eval( $_GET['foo'] )SecurityCheck-PathTraversal - เส้นทางข้ามเส้นทางเช่น require $_GET['foo']SecurityCheck-ReDoS - การปฏิเสธการแสดงออกปกติของบริการ (redos), เช่น preg_match( $_GET['foo'], 'foo')SecurityCheck-LikelyFalsePositive - ปัญหาที่อาจเกิดขึ้น แต่อาจไม่ใช่ ส่วนใหญ่เกิดขึ้นเมื่อปลั๊กอินสับสน ฟิลด์ความรุนแรงมักถูกทำเครื่องหมายว่าเป็น Issue::SEVERITY_NORMAL (5) ข้อดีที่ผิดพลาดได้รับ Issue::SEVERITY_LOW (0) ปัญหาที่อาจส่งผลให้เกิดการประนีประนอมกับเซิร์ฟเวอร์ (ตรงข้ามกับการประนีประนอมของผู้ใช้ปลายทาง) เช่นเชลล์หรือการฉีด SQL ถูกทำเครื่องหมายว่าเป็น Issue::SEVERITY_CRITICAL (10) โดยปกติแล้ว SerializationInject จะ "สำคัญ" แต่ปัจจุบันแสดงว่าเป็นความรุนแรงของปกติเนื่องจากการตรวจสอบดูเหมือนว่าจะมีอัตราบวกเท็จสูงในขณะนี้
คุณสามารถใช้ตัวเลือกบรรทัดคำสั่ง -y ของ phan เพื่อกรองโดยความรุนแรง
หากคุณต้องการปราบปรามค่าบวกที่ผิดพลาดคุณสามารถใส่ @suppress NAME-OF-WARNING ใน docblock สำหรับฟังก์ชั่น/วิธี หรือคุณสามารถใช้การปราบปรามประเภทอื่น ๆ เช่น @phan-suppress-next-line ดู readme ของ Phan สำหรับรายการที่สมบูรณ์ ส่วน @param-taint และ @return-taint (ดูส่วน "การปรับแต่ง") ก็มีประโยชน์มากในการจัดการกับข้อดีที่ผิดพลาด
โปรดทราบว่าปลั๊กอินจะรายงานช่องโหว่ XSS ที่เป็นไปได้ในบริบท CLI เพื่อหลีกเลี่ยงพวกเขาคุณสามารถปราบปรามไฟล์ SecurityCheck-XSS ด้วย @phan-file-suppress ในสคริปต์ CLI หรือสำหรับแอปพลิเคชันทั้งหมด (โดยใช้ตัวเลือกการกำหนดค่า suppress_issue_types ) หากแอปพลิเคชันประกอบด้วยสคริปต์ CLI เท่านั้น อีกทางเลือกหนึ่งหากการส่งออกทั้งหมดเกิดขึ้นจากฟังก์ชั่นภายในคุณสามารถใช้ @param-taint ได้ดังนี้:
/**
* @param-taint $stuffToPrint none
*/
public function printMyStuff ( string $ stuffToPrint ) {
echo $ stuffToPrint ;
}เมื่อแก้ไขปัญหาด้านความปลอดภัยคุณสามารถใช้:
'@phan-debug-var-taintedness $varname';
สิ่งนี้จะปล่อยปัญหา SecurityCheckDebugTaintedness ที่มีความสะอาดของ $varname ที่บรรทัดที่พบคำอธิบายประกอบ โปรดทราบว่าคุณต้องแทรกคำอธิบายประกอบในตัวอักษรสตริง ความคิดเห็นจะไม่ทำงาน ดูคำอธิบายประกอบของ @phan-debug-var Phan
@return-taint html$options ) และที่หก ( $join_cond ) ของ IDatabase::select() หากให้โดยตรงเป็นตัวอักษรอาร์เรย์หรือกลับมาเป็นตัวอักษรอาร์เรย์โดยตรงจากวิธี getQueryInfo() ปลั๊กอินรองรับการปรับแต่งโดยการแบ่งคลาส SecurityCheckPlugin สำหรับตัวอย่างที่ซับซ้อนของการทำเช่นนั้นให้ดูที่ MediaWikisecurityCheckPlugin
บางครั้งคุณมีวิธีการใน codebase ของคุณที่เปลี่ยน taint ของตัวแปร ตัวอย่างเช่นฟังก์ชั่นการหลบหนี HTML ที่กำหนดเองควรล้างบิต HTML Taint Bit ในทำนองเดียวกันบางครั้ง phan-taint-check อาจสับสนและคุณต้องการแทนที่ taint ที่คำนวณสำหรับฟังก์ชั่นเฉพาะ
คุณสามารถทำได้โดยการเพิ่มคำสั่ง TAINT ในความคิดเห็น DOCBLOCK ตัวอย่างเช่น:
/**
* My function description
*
* @param string $html the text to be escaped
* @param-taint $html escapes_html
*/
function escapeHtml ( $ html ) {
}วิธีการยังสืบทอดคำสั่งเหล่านี้จากคำจำกัดความนามธรรมในอินเทอร์เฟซของบรรพบุรุษ แต่ไม่ได้มาจากการใช้งานที่เป็นรูปธรรมในชั้นเรียนบรรพบุรุษ
คำสั่ง Taint จะถูกนำหน้าด้วย @param-taint $parametername หรือ @return-taint หากมีคำสั่งหลายคำสั่งพวกเขาสามารถคั่นด้วยเครื่องหมายจุลภาค @param-taint ใช้สำหรับการทำเครื่องหมายว่าการส่ง taint นั้นส่งจากพารามิเตอร์ไปยังค่าวิธีการส่งคืนวิธีการหรือเมื่อใช้กับคำสั่ง exec_ เพื่อทำเครื่องหมายสถานที่ที่พารามิเตอร์ถูกส่งออก/ดำเนินการ @return-taint ใช้เพื่อปรับค่าใช้จ่ายของผลตอบแทนโดยไม่คำนึงถึงพารามิเตอร์อินพุต
ประเภทของคำสั่งรวมถึง:
exec_$TYPE - หากพารามิเตอร์ถูกทำเครื่องหมายเป็น exec_$TYPE จากนั้นการให้อาหารพารามิเตอร์นั้นค่าที่มี $TYPE tyt จะส่งผลให้เกิดการเตือน โดยทั่วไปคุณจะใช้สิ่งนี้เมื่อฟังก์ชั่นที่ส่งออกหรือดำเนินการพารามิเตอร์ของมันescapes_$TYPE - ใช้สำหรับพารามิเตอร์ที่ฟังก์ชั่นหลบหนีจากนั้นส่งคืนพารามิเตอร์ ดังนั้น escapes_sql จะล้าง SQL TAINT BITonlysafefor_$TYPE - สำหรับใช้ใน @return-taint ทำเครื่องหมายประเภทการส่งคืนที่ปลอดภัยสำหรับ $TYPE เฉพาะ แต่ไม่ปลอดภัยสำหรับประเภทอื่น ๆ$TYPE - ถ้าเพียงประเภทที่ระบุไว้ในพารามิเตอร์มันจะเป็น bitwised และด้วย taint ของตัวแปรอินพุต โดยปกติคุณจะไม่ต้องการทำสิ่งนี้ แต่อาจมีประโยชน์เมื่อ $TYPE none ที่จะระบุว่าพารามิเตอร์ไม่ได้ใช้เพื่อสร้างค่าส่งคืน ใน @return สิ่งนี้สามารถใช้ในการแจกแจงซึ่งค่าสถานะผลตอบแทนที่น่าเบื่อซึ่งมักจะมีประโยชน์เฉพาะเมื่อระบุว่ามี tainted ที่จะบอกว่ามีธงทั้งหมดarray_ok - ธงวัตถุประสงค์พิเศษที่จะบอกว่าละเว้นอาร์กิวเมนต์ที่ไม่บริสุทธิ์หากพวกเขาอยู่ในอาร์เรย์allow_override ธงวัตถุประสงค์พิเศษเพื่อระบุว่าคำอธิบายประกอบที่มีค่าใช้จ่ายควรถูกแทนที่ด้วยการตรวจสอบแบบ phan-taint-check หากสามารถตรวจจับ Taint ที่เฉพาะเจาะจงได้ ค่าสำหรับ $TYPE สามารถเป็นหนึ่งใน htmlnoent , html , sql , shell , serialize , custom1 , custom2 , code , path , regex , sql_numkey , escaped , none , tainted ส่วนใหญ่เหล่านี้เป็นหมวดหมู่ที่น่าเบื่อยกเว้น:
htmlnoent - เช่น html แต่ปิดการตรวจจับการหลบหนีสองครั้งที่ใช้กับ html เมื่อระบุ escapes_html Escaped จะถูกเพิ่มเข้ามาใน @return โดยอัตโนมัติและ exec_escaped จะถูกเพิ่มลงใน @param ในทำนองเดียวกัน onlysafefor_html เทียบเท่ากับ onlysafefor_htmlnoent,escapednone - หมายความว่าไม่มีความ Tainttainted - หมายถึงหมวดหมู่ที่ Taint ทั้งหมดยกเว้นหมวดหมู่พิเศษ (เทียบเท่ากับ SecurityCheckPlugin::YES_TAINT )escaped - ใช้เพื่อหมายถึงค่าถูกหลบหนีไปแล้ว (เพื่อติดตามการหลบหนีสองครั้ง)sql_numkey - มีวัตถุประสงค์พิเศษสำหรับ MediaWiki มันไม่สนใจ taint ในอาร์เรย์หากพวกเขามีไว้สำหรับคีย์เชื่อมโยง ค่าเริ่มต้นสำหรับ @param-taint จะ tainted หากเป็นสตริง (หรือประเภทอันตรายอื่น ๆ ) และ none ถ้ามันเป็นจำนวนเต็ม ค่าเริ่มต้นสำหรับ @return-taint คือ allow_override (ซึ่งเทียบเท่ากับ none เว้นแต่ว่ามีสิ่งที่ดีกว่าที่จะได้รับการตรวจสอบอัตโนมัติ)
แทนที่จะใช้วิธีการใส่คำอธิบายประกอบใน codebase ของคุณคุณยังสามารถปรับแต่ง phan-taint-check ให้มีความรู้ในตัวของวิธีการ taints นอกจากนี้คุณสามารถขยายปลั๊กอินเพื่อให้มีพฤติกรรมโดยพลการ
ในการทำเช่นนี้คุณจะแทนที่วิธี getCustomFuncTaints() วิธีนี้ส่งคืนอาร์เรย์แบบเชื่อมโยงของชื่อวิธีการที่มีคุณสมบัติครบถ้วนไปยังอาร์เรย์ที่อธิบายถึงวิธีการ taint ของค่าส่งคืนของฟังก์ชันในแง่ของอาร์กิวเมนต์ของมัน คีย์ตัวเลขสอดคล้องกับจำนวนอาร์กิวเมนต์และคีย์ 'โดยรวม' จะเพิ่ม Taint ที่ไม่ได้อยู่ในอาร์กิวเมนต์ใด ๆ โดยพื้นฐานแล้วสำหรับแต่ละอาร์กิวเมนต์ปลั๊กอินจะใช้ข้อ จำกัด ของอาร์กิวเมนต์ bitwise และเป็นรายการของมันในอาร์เรย์จากนั้น bitwise หรือเป็นคีย์โดยรวม หากคีย์ใด ๆ ในอาร์เรย์มีธงเอ็กเอ็กจะมีการยกปัญหาทันทีหาก taint ที่สอดคล้องกันถูกป้อนฟังก์ชั่น (ตัวอย่างเช่นฟังก์ชันเอาต์พุต) ธง EXEC ไม่ทำงานในคีย์ 'โดยรวม'
ตัวอย่างเช่น htmlspecialchars ซึ่งลบ HTML Taint หนีการโต้แย้งและส่งคืนค่าที่หลบหนีจะมีลักษณะ:
' htmlspecialchars ' => [
( self :: YES_TAINT & ~ self :: HTML_TAINT ) | self :: ESCAPED_EXEC_TAINT ,
' overall ' => self :: ESCAPED ,
];ตัวแปรสภาพแวดล้อมต่อไปนี้มีผลต่อปลั๊กอิน โดยปกติคุณจะไม่ต้องปรับสิ่งเหล่านี้
SECURITY_CHECK_EXT_PATH - เส้นทางสู่ไดเรกทอรีที่มี extension.json / skin.json เมื่ออยู่ในโหมด Mediawiki หากไม่ได้ตั้งค่าจะถือว่าไดเรกทอรีรากของโครงการSECCHECK_DEBUG - ไฟล์เพื่อส่งออกข้อมูลการดีบักพิเศษ (ถ้าทำงานจาก shell /dev/stderr สะดวก) ใบอนุญาตสาธารณะ GNU ทั่วไปเวอร์ชัน 2 หรือใหม่กว่า