Monday 10 March 2008

Security Testing ตอนที่ 1

Security Testing(ตอนที่ 1)

สวัสดีครับผม Mr. Invert prahs กลับมาเขียน blog แล้วครับหลังจากที่หายหน้าหายตาไปกันตั้งนานเพราะว่าไปลง Project กับคุณ tofu เลยไม่มีเวลาว่างมาเขียน blog (ปล. จริงๆก็อู้ด้วยส่วนหนึ่ง) แต่เชื่อแล้วจริงๆว่าถ้าคิดจะเขียน blog ก็เหมือนมีลูกจริงๆ เพราะว่าต้องค่อยป้อนบทความใหม่ๆเข้ามาเรื่อยๆ เหมือนมีห่วงผูกคอ เอาหละเริ่มออกทะเลไปไกลแล้วมาเข้าเรื่องกันดีกว่า ซึ่งอย่างที่ผมบอกไปว่าได้ไปลง project จริงๆจังๆกับคุณ tofu ซึ่งถือเป็น project แรกของผมกับคุณ tofu ทำให้ผมผู้ซึ่งเป็นเด็กจบใหม่ (จากปีที่แล้ว) ได้เห็นมุมมองเกี่ยวกับด้านการทำ Web Application ที่กว้างขึ้นและได้เรียนรู้หลายๆสิ่งหลายๆอย่างมากมายซึ่งถ้ามีเวลาว่างๆจะมานั่งเขียน blog มาเล่าให้ฟังว่าป็นยังไง ซึ่งเรื่องแรกที่ผมจะนำมาเล่าก็คือ Security Testing ผมเองก็เพิ่งจะรู้ว่าเวลาเขียน Web Application เกี่ยวกับเงินๆทองๆนี่มันยุ่งยากมันจุกจิกอย่างนี้นี่เอง
ในการทดสอบ Application ที่เราพัฒนานั้นนอกจากเราจะต้องทำการทดสอบ bug ของ Application แล้ว ถ้าหาก Application นั้นมีส่วนที่เกี่ยวข้องกับระบบการเงิน เราอาจจะต้องมีการทดสอบด้าน security ด้วยซึ่งการทดสอบ security นี้ไม่ว่าจะเป็น Windows Application (หรือบางคนจะเรียกว่า Desktop Application) หรือ Web Application นั้นจะมีลักษณะการทดสอบที่คล้ายๆกันเพียงการทดสอบ Web Application นั้นอาจจะมีเรื่องที่ยุ่งยากหรือจุกจิกกว่ากันเยอะ ซึ่งการทดสอบหลักๆจะแบ่งออกเป็น 7 หัวข้อหลักๆดังนี้

URL & Parameter Manipulation

เป็นการ check ว่าในการส่ง parameter แบบ get ที่ส่งผ่าน URL หรือส่งผ่าน Hidden field นั้นมีข้อมูลที่สำคัญส่งมากับ URL parameter หรือไม่เพราะว่าอาจจะเป็นจุดบอดที่สามารถให้บรรดาเหล่า Hacker นั้นใช่จุดบอดเหล่านี้สาวเข้าไปถึงข้อมูลสำคัญของเราได้
ซึ่งถ้าหากว่าจำเป็นจริงๆที่จะต้องทำการส่งผ่าน URL parameter หรือ hidden field จริงๆก็ควรที่จะทำการ encrypt ข้อมูลที่ส่งผ่าน URL parameter หรือ hidden field เพื่อเพิ่มความปลอดภัยแต่ว่าถ้าเลี่ยงได้ก็ควรไปใช้ Session ในการเก็บข้อมูลเหล่านี้แทน
ข้อแนะนำเกี่ยวกับการ encrypt data เนื่องจาก algorithm ในการ encrypt data มีมากมายก็จริงแต่ algorithm ส่วนใหญ่มักจะมีคนแก้ได้แล้วเป็นส่วนมากดังนั้นในการหา algorithm encrypt data มาใช้ในงานที่ serious จริงๆ ควรที่จะหา encrypt data ที่มี salted hash techniques โดยสามารถเพิ่มความปลอดภัยของข้อมูลได้มากขึ้นเป็นร้อยเป็นพันเท่าครับ โดยการใส่ keyword เข้าไปผสมลงใน data ก่อนจะผ่านกรรมวิธีการ encrypt data เพื่อให้แก้ไขได้ยากยิ่งขึ้นซึ่งเราเรียก keyword ที่เราไปผสม data นี้ว่า salt (ซึ่งเป็นตัวเดียวกันกับคำว่า เกลือ ครับ ก็เหมือนเวลาที่เรากินอาหารแล้วอยากให้อาหารอร่อยขึ้นเราก็เหยาะเกลือลงไป แต่ในที่นี้เพื่อที่จะทำให้การถอด data ยากขึ้น) โดยถ้าสนใจอยากลองเล่นก็ลองไปดูตัวอย่างและวิธีการในเวบนี้ครับ http://www.securitydocs.com/library/3439 หรือถ้าต้องการดูอย่างมุมมองกว้างๆก็แนะนำเวบนี้เลย http://www.developerfusion.co.uk/show/4679/1/%20
หรือจะเป็นอีกวิธีคือเก็บข้อมูลที่เป็น URL Parameter ทั้งหมดลงไปใน hidden field ทั้งหมดจากนั้นก็ใส่ script ป้องกันการ view source ลงไปในหน้า page นั้น (เช่นที่เราเห็นกันบ่อยคือกันห้าม click ขวา) เพื่อป้องกันการรู้ชื่อ parameter ของ hidden field ในหน้านั้นๆ แต่ขอบอกว่าวิธีนี้ไม่ค่อยจะใช้ได้ผลสักเท่าไร เพราะว่าถ้าหากผู้ใช้ไปปิดความสามารถในการ run javascript ที่ browser แล้วก็ไม่สามารถกันได้อยู่ดี และ script ส่วนใหญ่จะไม่รองรับทุก browser ด้วยครับคือบางครั้งกัน IE กับ firefox ได้แต่อาจจะกัน Opera ไม่ได้ถ้าคนเขียนไม่ได้เขียนรองรับทุก OS

สรุป ถ้าจะกันปัญหาทางด้าน URL & Parameter Manipulation มีสองวิธีที่แก้ได้แน่นอนคือ เก็บข้อมูลที่เป็นความลับใส่ session หรืออีกวิธีก็ทำการ encrypt data เพื่อป้องกันไม่ให้แก้ข้อมูลออกได้ง่ายๆ

SQL Injection

เป็นการใส่คำสั่ง sql เพื่อรันให้ทำงาน โดยกรอกเข้าไปในช่องของ text box เพื่อทำอะไรบางอย่าง เช่น สามารถ login เข้าไป, หรือ รันคำสั่งเพื่อ drop table เป็นต้น ปัญหาแบบนี้จะเจอบ่อยครับในกรณีที่ programmer เขียน SQL ที่ใช้ใน program แบบไม่ได้ดักจับ escape characters บางตัว เช่น double quote (“), single quote (‘) เป็นต้น ซึ่งการที่เราไม่ได้ดักจับหรือจัดการ escape characters นั้นอาจจะทำให้เกิดผลดังตัวอย่างด้านล่างดังนี้

String sql = “select * from user where password = ‘” + password + ”’ ”;

ซึ่ง variable ที่ชื่อว่า password นั้นเป็นตัวรับค่าข้อมูลมาจาก user สมมติว่า user คนนั้นกรอกค่าลงไปดังนี้

Pwd12345’ or ‘1’=’1

ซึ่งหากลองแทน variable password ลงใน variable sql ดูผลที่ได้ก็จะเป็นดังนี้

select * from user where password = ‘Pwd12345’ or ‘1’=’1’

ซึ่งถึงแม้ว่า password จะผิดแต่ว่า user ก็สามารถ login เข้าไปเพราะว่า or ‘1’=’1’ มันเป็นจริงเสมอนอกจาก SQL Injection จะเกิดขึ้นกับคำสั่ง SQL แล้วบางครั้งการเรียกใช้ store procedure ก็เกิด SQL Injection เหมือนกันถ้าหากว่าไม่ได้ระมัดระวังเรื่อง escape characters

วิธีป้องกัน ในบาง DB นั้นมี security ที่รองรับการป้องกัน SQL Injection อยู่แล้วเช่น MySQL ที่เพิ่งเริ่มมีใน version 5.0 โดยต้องใช้ method ชื่อ real_escape_chars() เพื่อช่วยในการจัดการเกี่ยวกับ escape characters หรือในบางภาษาก็มีการจัดการ escape characters ใน SQL ให้เรา เช่น ภาษา Java ซึ่งในภาษา Java นั้นก็จะมี Prepare Statement ที่ช่วยจัดการในเรื่องของการทำ Query แต่สำหรับภาษาไหนหรือ DB ตัวไหนที่ไม่ได้รองรับการป้องกัน SQL Injection ก็ควรที่จะต้องเขียน program ในส่วนที่จัดการ escape characters กันเอาเองซึ่งผมก็มีตัวอย่าง code ของ Java มาให้ดู

http://pastebin.com/f30a7a3be

ที่ผมให้ตัวอย่างมาให้ที่เป็นในกรณีของ Java นั้นไม่ได้หมายความว่าให้ใช้ตัวนี้แทน prepare statement นะครับยกตัวอย่างเพื่อเป็นแนวทางการเขียนเพื่อนำไปดัก Escape Characters ในภาษาอื่นครับ แต่ว่าการดัก Escape Characters นั้นส่วนใหญ่จะดักกันตรงที่เครื่องหมาย double quote (“), single quote (‘) และ semicolon (;) มากกว่าครับส่วนที่เหลือถ้าอยากจะดักเพิ่มก็แล้วแต่ความเหมาะสมครับ เช่น ใน MS SQL นั้นมี “--” แทน comment ซึ่งเราควรที่จะดักเพิ่ม เป็นต้น ซึ่งนอกจากวิธีที่ผมได้กล่าวมาแล้วนั้นยังมี trick เล็กๆน้อยๆอีกครับ คือการกำหนดสิทธิ user ให้มี role ตามที่ได้ใช้จริงๆเท่านั้นเพื่อป้องกันว่า เช่น บางครั้งการเขียน program เราอาจจะฝั่ง business process ใน store procedure ของฝั่ง DB ก็ได้ ซึ่งบางทีใน store procedure นั้นอาจจะมี business process ที่ต้องไปรัน command ของ OS ได้ ดังนั้น store procedure นั้นควรที่จะมอบสิทธิให้กับ user ที่ใช้จริงๆเท่านั้น เพราะว่าในตอนทดลองเราอาจจะขี้เกียจมานั่งกำหนดสิทธิให้สิทธิทุกอย่างหมดเลย ดังนั้นก่อนนำเข้าสู้ระบบนำไปใช้จริงก็อย่าลืมกำหนดสิทธิใหม่ด้วยครับ
ปล. Code ด้านบนนั้นที่จริงใช้ Regular Expression น่าจะดีกว่าครับในการตรวจจับแต่ว่าผมไม่เคยลองเล่น Regular Expression ของ Java ซักทีเคยเล่นแต่ javascript ครับใครที่เคยเล่นแล้วช่วยแนะนำผ่าน comment ได้ครับ

Cross-site scripting (XSS)

เป็นใส่ script บางอย่างเข้าไปในเว็บ เช่น อาจจะใส่ javascript เข้าไปในช่อง text box ดังนี้ <script>alert(“Hello World -Popup”)</script> เพื่อสร้าง popup window แต่ว่าบางครั้ง hacker อาจจะนำ script บางอย่างเข้าไปเพื่อหวังผลบางอย่าง เช่น ดึงข้อมูล cookie ออกมาจาก client site โดยใช้ javascript, vbscript หรือภาษา script อื่นๆ

วิธีแก้ไข ใช้วิธีการ Convert HTML Tags ซึ่งผู้ที่กรอกเข้ามาถ้าหากมีส่วนหนึ่งส่วนใดให้แปลงตามรูปแบบในตารางด้านล่างนี้ก่อนค่อยนำเข้า database



ซึ่งวิธีนี้ข้อเสียเราต้องมานั่งเขียน program เพื่อแปลง code เองซึ่งค่อยข้างจะยุ่งยากนิดนึงแต่ก็อาจมีทางเลือกอีกในการกัน XSS คือใช้ Lightweight Markup Language หลายคนคงงงอาจจะยังไม่รู้แต่ถ้าผมบอกว่าตัวอย่างของ Lightweight Markup Language (LML) ที่เราได้เห็นนั้นก็คือ BB code นั้นเองซึ่งของ Java นี้ที่ผมลองหาดูก็ไปเจอตัวนี้เข้า PLink Textile ครับ น่าสนใจดีลองไปดูตัวอย่างตาม url นี้ครับ http://hobix.com/textile/ แต่วิธีนี้ค่อนข้างที่จะยุ่งยากครับเหมาะสำหรับช่องที่มีการกรอกข้อมูลยาวๆอย่างเช่นกระทู้ใน webboard ครับ แต่วิธีแก้ง่ายๆที่แนะนำคือ ให้ใช้ JSTL แทน JSP scriptlets เข้ามาช่วยในการแสดงผลลงในหน้า web คือใช้ <c:out> แทน <%= %> ครับเพราะว่าจะกันไว้ให้อยู่แล้วครับ Code Convert HTML Tags (ไว้เป็นแนวทางสำหรับภาษาอื่นครับแต่ว่ามันเป็น source ของ java นะครับ ที่ผมลองเขียนเอง) เข้าไปโหลดได้ที่นี่ครับ

http://pastebin.com/f7249386c

จากตัวอย่าง Code ด้านบนนั้นที่จริงใน Apache นั้นมี Opensource ที่รองรับ Convert HTML Tags อยู่ครับชื่อว่า class StringEscapeUtils อยู่ใน package Apache Commons ครับ http://commons.apache.org/lang/api/org/apache/commons/lang/StringEscapeUtils.html

ซึ่งจะทำให้เราไม่ต้องมาเขียน code ให้เหนื่อย (อันที่จริงผมลองค้นหาใน apache commons แล้วนะแต่ว่าตอนแรกไม่เจอเลยต้องมานั่งเขียนเองเพิ่งมาเจอที่หลัง) โดยใช้ method escapeHtml() มันก็จะจัดการให้เราโดยที่เราไม่ต้องไปเขียน code เองแล้วก็อย่างที่บอกไปด้านบนครับมันมี method escapeSql() ที่ไว้ใช้แก้ SQL Injection ด้วย เหอะๆๆ เพิ่งไปเจอครับตอนแรกที่ผมลองค้นดูนึกว่ามันแยกเป็น class แต่ว่าที่จริงมันเอาไปรวมอยู่ใน class เดียวกันแล้วแบ่งแยกเป็น method ครับ

No comments: