เพิ่มความปลอดภัยให้การ upload ภาพ

หลังจากที่ผมได้รับงานแก้ไขเพิ่มเติมความปลอดภัย จากงานที่คนอื่นเคยทำมา ทำให้ผมเห็นได้ว่า บางคนให้ความสำคัญกับความปลอดภัยของเว็บน้อยมากจริงๆ
ไม่ว่าจะ sql injection, xss, cross site request forgery ที่เรารู้กันอยู่แล้ว ผมจึงหาความรู้เกี่ยวกับความปลอดภัยเพิ่มเติม จึงได้รู้ว่าการอัปโหลดภาพแบบที่เช็คสกุลภาพกันนั้น มันไม่ปลอดภัยพอจริงๆด้วย

เรามาดูกระบวนการกันหน่อย
เริ่มที่ user อัปโหลด -> มาที่เว็บ เราเขียนสคริปต์เช็ค type -> เป็น jpg,jpeg,gif,png ก็ทำการ move_uploaded_file

แต่ ถ้าไฟล์ภาพนั้น ข้างในเป็นสคริปต์ php ล่ะ? แน่นอนครับว่ามันอาจจะ execute ได้หรือไม่ได้นั้น แต่ถ้าเรากรองให้ถี่ถ้วนว่ามันเป็นไฟล์ภาพจริงๆนั้น จะไม่ดีกว่าหรือครับ?
ด้วยเหตุนี้เราจึงต้องเปลี่ยนกระบวนการกันนิดหน่อยจากข้างบน เป็น
user อัปโหลด -> มาที่เว็บ เราเช็ค mime type ว่าเป็นไฟล์ภาพจริงๆ -> move_uploaded_file

เพิ่มอีกแค่นิดเดียวแต่ปลอดภัยกว่ากันมาก จริงไหมครับ?
มาดูโค้ดกันดีกว่า


$img = getimagesize($_FILES['file']['tmp_name']);
list($width, $height, $image_type, $wh_att) = getimagesize($_FILES['file']['tmp_name']);
// เช็คไฟล์ภาพ#####
if ( ($image_type == '1' || $image_type == '2' || $image_type == '3') && ($img['mime'] == "image/gif" || $img['mime'] == "image/jpeg" || $img['mime'] == "image/png") ) {
    // ok
    $uploadok = true;
} else {
    $uploadok = false;
}
// เช็คไฟล์ภาพ#####

if ( $uploadok === true ) {
    // เช็คแล้วผ่านก็ย้ายไฟล์เลย
    move_uploaded_file($_FILES['file']['tmp_name'], dirname(__FILE__)."/".$_FILES['file']['name']);
} else {
    // เช็คแล้วไม่ผ่าน ลบ tmp file ทิ้งเพื่อความปลอดภัย
    @unlink($_FILES['file']['tmp_name']);// ใส่ @ เข้าไปเพราะไม่รู้ว่าจะลบ tmp file ได้หรือไม่ (บาง server กำหนดไม่เหมือนกัน)
}

อธิบายการเช็คไฟล์ภาพ
getimagesize คือการเช็คค่าต่างๆของไฟล์ภาพ จากตัวไฟล์จริงๆ
แต่เราจะต้องเช็คในขณะที่มันยังอยู่ใน temp folder โดยยังไม่ใช้ move_uploaded_file() เพื่อความปลอดภัย

$image_type ที่กำหนดใน list() นั้น จะได้ค่าออกมาเป็นตัวเลข โดย 1 จะเป็น gif 2 jpeg 3 เป็น png ตามลำดับ
ขอให้ดูอ้างอิงได้จาก http://www.php.net/manual/en/function.image-type-to-mime-type.php
ส่วน $img['mime'] ที่ได้จาก getimagesize() นั้นจะได้ค่า mime ออกมาเป็นตัวอักษรตรงๆเลย อ้างอิงตามลิ้งค์ด้านบนเช่นกัน

เมื่อเช็คแล้วว่าเป็นไฟล์ภาพ ก็ทำการเรียก move_uploaded_file ต่อไป

ใส่ความเห็น

อีเมลของคุณจะไม่แสดงให้คนอื่นเห็น ช่องข้อมูลจำเป็นถูกทำเครื่องหมาย *

คุณอาจใช้แท็กHTMLและแอททริบิวต์เหล่านี้: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>