เพิ่มความปลอดภัยให้กับ PHP ของคุณ (ตอนที่ 2 : ความปลอดภัยที่มักถูกมองข้าม)
ในบทนี้ เราจะมาพูดถึงเรื่องง่ายๆ ที่เราสามารถเพิ่มความแน่นหนาให้กับเว็บของเรา ซึ่งไม่มีอะไรซับซ้อนมากครับ แต่ผู้คนมักมองข้ามกันไป
Register Globals
ปัญหานี้เป็นปัญหาที่พบได้มากเลยทีเดียวครับ และก็ไม่เห็นว่าจะมีใครสนใจมันเลย นับตั้งแต่ PHP เวอร์ชั่น 4.2.0 หรืออะไรประมาณนี้เนี่ยแหละ ค่า register_globals ใน php.ini ก็ถูกตั้งไว้ที่ Off โดยปกติ ซึ่งก็สร้างปัญหาพอสมควรกับผู้เขียนโค๊ดทั่วไป ที่มักจะเรียกใช้ข้อมูลจากผู้ใช้แบบง่ายๆ ประมาณว่าการใช้ $foo ในการเรียกข้อมูลมาจาก form หรือ url ที่เป็น ?foo=bar นะครับ เพราะเรากำลังส่งข้อมูลจากภายนอกเข้ามารวมกับสคริปต์ของเรา ทางแก้ไขก็คือการตั้ง register_globals เป็น Off แล้วเรียกใช้ข้อมูลจากภายนอก ดังนี้
- เวลารับข้อมูลมาจาก ฟอร์ม ในหน้าก่อนๆ ให้ใช้ $_POST['foo']
- เวลารับข้อมูลมาจาก URL เช่น http://localhost/test.php?foo=bar ก็ให้ใช้ $_GET['foo']
- เวลารับข้อมูลจาก Session ให้ใช้ $_SESSION['foo']
เพียงเท่านี้ คุณก็จะได้สคริปต์ที่มีความปลอดภัยมากขึ้น โดยการแยกข้อมูลจากผู้ใช้ออกจากข้อมูลของระบบ และเป็นการป้องกันความสับสนทางหนึ่งด้วย เพราะผู้ที่พัฒนาโค๊ดจะรู้ได้อย่างชัดเจนว่าข้อมูลที่ได้มานั้นมาจากไหน
การกลั่นกรองข้อมูล
สามสิ่งที่ควรคำนึง...
- ทำความแน่นอนว่า การกลั่นกรองข้อมูลเป็นสิ่งที่ถูกหลีกเลี่ยงไม่ได้
- ทำความแน่นอนว่า ข้อมูลที่ไม่ถูกต้อง จะไม่มีทางเล็ดลอดเข้าไปในระบบได้
- ตรวจสอบแหล่งที่มาของข้อมูล
วิธีที่ 1 : การแจกจ่ายงาย
วิธีหนึ่งที่จะช่วยให้โค๊ดของคุณอ่านง่ายขึ้นนั้น ก็คือการสร้างไฟล์ไฟล์เดียวที่ผู้ใช้สามารถเข้าถึงได้ เช่น index.php โดยที่ไฟล์นี้มีหน้าที่ในการรับข้อมูลเข้ามาทั้งหมด กรองข้อมูล จากนั้นก็แจกจ่ายงานไปให้ ไปไฟล์อื่นทำ (ไฟล์ที่ไม่อนุญาตให้ผู้ใช้ทั่วไปเข้าถึง)
วิธีนี้จะช่วยให้จัดการข้อมูลที่ถูกดูดเข้ามาได้ง่าย เพราะข้อมูลที่ได้เข้ามาจะขึ้นอยู่กับไฟล์ไฟล์เดียว เป็นการป้องกันการลืมใส่มาตรการความปลอดภัยลงในไฟล์ไฟล์ใดไฟล์หนึ่ง เวลาที่จะเปลี่ยนแปลงระบบจัดการก็จะทำได้ง่ายด้วย
หลักการก็ง่ายๆเลย ไฟล์ index.php มีหน้าที่ในการรับข้อมูลมาจากผู้ที่เรียกใช้งาน โดยที่มีข้อมูลมาเรียบร้อย จากนั้นตรวจสอบดูว่าผู้ใช้ต้องการทำงานอะไร แล้วค่อยไปดูดไฟล์ที่เกี่ยวข้องออกมาประมวลผล ดังตัวอย่างสำหรับการใช้ URI เช่น http://localhost/index.php?task=showrecord&name=tuwannu
<?
switch($_GET['task']) {
case 'showrecord' :
$name = addslashes($_GET['name']);
include './system/record.php';
break;
case 'showcategory' :
include './system/category.php';
break;
default:
echo 'No Task';
break;
}
?>อธิบายโค๊ดนะครับ คือพอผู้ใช้เรียกไฟล์ index.php ขึ้นมา โดยระบุ task กับ name มา เราก็จะนำ task ไปเทียบกับข้อมูลในระบบ ในที่นี้ task จะเป็น showrecord พอโค๊ดตรวจสอบพบว่ามี task นี้อยู่ ก็จะตรวจสอบข้อมูลใน name ต่อ โดยในส่วนนี้อาจจะเป็นการ addslashes() เพื่อตัดส่วนที่เป็นอันตรายต่อระบบออกไป พอตรวจสอบเสร็จแล้ว ก็จะไปเรียกไฟล์ใน ./system/record.php ขึ้นมา (โดยที่โฟลเดอร์ system อาจจะกำหนดการเข้าถึงไว้ ทำให้ผู้ใช้ทั่วไปเข้าไปใช้โดยตรงไม่ได้) เป็นการป้องกันข้อมูลขึ้นมาอีกชั้นนึงครับผม หากหา task ไม่พบ ก็จะให้ขึ้นว่า No Task พูดง่ายๆ คือจำกัดว่าผู้ใช้สามารถทำได้แค่ showrecord หรือ showcategory แค่นี้แหละ
ทางเลือกที่สอง
ถ้าหากการรวมทุกอย่างมะรุมมะตุ้มอยู่หน้าเดียวกันจะเป็นการไม่สะดวกเกินไป ใช้ include() แทนก็ได้ครับ โดยการแยกไฟล์ที่เกี่ยวข้องกับการรักษาความปลอดภัยออกไปเป็นอีกส่วนหนึ่ง พอจะใช้ก็ include() ไฟล์นั้นเข้ามา วิธีนี้ก็เวิร์คเหมือนกัน แต่ทีนี้ก็ต้องระมัดระวังครับว่า include() ลงไปในทุกไฟล์ที่เกี่ยวข้อง หรือถ้าคุณสามารถกำหนด php.ini ได้ ก็ลองเปลี่ยน auto_prepend_file ดู ซึ่งเป็นการกำหนดว่าให้ PHP เรียกใช้ไฟล์ไหนโดยอัตโนมัติ จะได้ไม่ต้องห่วงเรื่องการไม่ได้ include() ไฟล์ลงในหน้าใดหน้าหนึ่ง
ตั้งชื่อให้น้องคนใหม่
หลังจากการตรวจสอบข้อมูลในบางครั้ง เราอาจจะมีการแปลงข้อมูลเล็กน้อยเพื่อให้เป็นข้อมูลที่ปลอดภัย เช่น addslashes() แต่พอประมวลผลเสร็จ ขอแนะนำให้นำข้อมูลแยกออกมาเป็นอีกไฟล์นึงซึ่งไม่เกี่ยวกับ $_GET หรือ $_POST อย่าทำพวก
<? $_GET['name'] = addslashes($_GET['name']); ?>
เพื่อเป็นการแยกแยะระหว่างข้อมูลดิบที่ได้มาจากผู้ใช้ และข้อมูลที่สามารถใช้ได้อย่างปลอดภัย
Error Reporting
- error_reporting ควรจะตั้งไว้ที่ E_ALL เนื่องจากตัว PHP จะทำการแสดงคำเตือนทั้งหมด เหมาะสำหรับเวลาที่ต้องการ debug ข้อมูล เป็นการทำความแน่ใจว่าสคริปต์ของคุณมีความถูกต้องมากที่สุด
- display_errors ควนจะตั้งเป็น On ในช่วงพัฒนาโค๊ด เพื่อเป็นการเปิดเผยคำเตือนต่างๆที่เกิดขึ้นในการพัฒนา ซึ่งจะช่วยในการแก้ไขโค๊ดเป็นไปได้ง่ายขึ้น ส่วนเวลาที่เริ่มนำโค๊ดไปใช้จริง ก็เปลี่ยนให้เป็น Off ซะ กันเผื่อว่าคนทั่วไปจะเห็นข้อผิดพลาดภายในเว็บ
- log_errors ควรตั้งเป็น On ตลอดเวลาเพื่อตรวจจับความผิดพลาดที่เกิดขึ้นในเว็บ โดยที่จะมี log เก็บไว้ในไฟล์ ตามที่ตั้งไว้สำหรับ error_logs
Post new comment