Category Archive Apache Apache HTTP Server

Byphunsanit

PHP: open_basedir ขังเดี่ยว PHP เว็บใครเว็บมัน

ขึ้นหัวข้อมาน่ากลัวเลย แต่จริง ๆ แล้วคำว่า ขังเดี่ยว PHP มันไม่เกินจริงเลย เพราะการ set open_basedir ไว้เป็นวิธีแยก site ของ PHP ให้แยกออกจากเว็บอื่น ๆ ที่อยู่บน server เดียวกัน เพื่อความปลอดภัย (Security) สำหรับเซิร์ฟเวอร์ที่รันหลายเว็บไซต์ (Multi-site) เพราะหน้าที่ของมันคือการ จำกัดขอบเขต ให้ PHP ของเว็บไซต์หนึ่ง ไม่สามารถเข้าไปอ่านหรือแก้ไขไฟล์ของอีกเว็บไซต์หนึ่งได้


ทำไมต้องใช้ open_basedir ในระบบ Multi-site

ถ้าคุณไม่ตั้งค่านี้ และมีเว็บไซต์หนึ่งในเซิร์ฟเวอร์ถูกแฮก (เช่น โดนฝัง Shell script) แฮกเกอร์จะสามารถใช้คำสั่ง PHP สแกนหาไฟล์ wp-config.php หรือไฟล์รหัสผ่านของเว็บไซต์อื่นๆ ในพาธเดียวกันได้ทันที

ตัวอย่างโครงสร้างไฟล์:

  • Site A: /var/www/site_a/public_html
  • Site B: /var/www/site_b/public_html

การตั้ง open_basedir จะทำให้ Site A มองเห็นแค่ไฟล์ในโฟลเดอร์ของตัวเองเท่านั้น ไม่สามารถแก้ไขหรือแม้แต่อ่านไฟล์นอกจากที่ใส่ไว้ใน open_basedir ได้


วิธีการตั้งค่า

  1. การตั้งค่า open_basedir สำหรับหลายเว็บไซต์ ไม่ควร ทำในไฟล์ php.ini หลัก (Global) เพราะจะทำให้ทุกเว็บติดเงื่อนไขเดียวกันหมด เราควรแยกตั้งค่าตามราย Site ดังนี้ครับ การขังเดี่ยวของเราจะไม่ได้ผล เท่าที่ควร เหมือนเอาคนป่วยมาอยู่ในห้องเดียวกันกับคนอื่นในแผนก ไม่นานก็จะกลายเป็นป่วยเหมือนกันยกตี้
  2. กรณีใช้ Apache (.htaccess หรือ VirtualHost)
    คุณสามารถกำหนดผ่านไฟล์ .htaccess (ถ้า Server ยอมให้ Override) หรือในไฟล์ VirtualHost:
    <VirtualHost *:80>

    ServerName site_a.com
    php_admin_value open_basedir “/var/www/site_a:/tmp

    </VirtualHost>
  3. กรณีใช้ Nginx กับ PHP-FPM (แนะนำมันดีกว่า Apache จริง ๆ)
    วิธีที่ง่ายที่สุดคือการตั้งค่าใน Config ของแต่ละเว็บไซต์

    ; ในไฟล์คอนฟิกของ Site A
    php_admin_value[open_basedir] = "/var/www/site_a:/tmp"

    ; ในไฟล์คอนฟิกของ Site B
    php_admin_value[open_basedir] = "/var/www/site_b:/tmp"

    Tip: ควรใส่ /tmp ไว้ด้วยเพื่อให้ PHP ยังสามารถเขียนไฟล์ชั่วคราว (เช่น การ Upload รูป) ได้ปกติ

ข้อควรระวังและ Best Practices

ข้อควรระวังรายละเอียด
Path Separatorใน Linux ใช้เครื่องหมาย : เพื่อแยกหลาย Path (เช่น /home/user:/tmp)
Symlinksถ้าคุณมีการใช้ Symbolic Link ข้ามโฟลเดอร์ open_basedir อาจจะบล็อกการทำงานได้ ต้องระบุ Path จริงลงไปด้วย
PHP Functionsฟังก์ชันอย่าง include, file_get_contents, fopen จะถูกจำกัดทั้งหมดภายใต้กฎนี้
Session & Uploadsอย่าลืมเช็คว่า session.save_path และ upload_tmp_dir อยู่ในขอบเขตที่อนุญาตหรือไม่

วิธีการทดสอบว่าใช้งานได้จริงหรือไม่

สร้างไฟล์ test.php ใน Site A แล้วลองสั่งให้อ่านไฟล์ของ Site B
<?php
// ลองอ่านไฟล์ข้าม Site
echo file_get_contents('/var/www/site_b/public_html/index.php');
?>
ถ้าตั้งค่าสำเร็จ: จะเกิด Error ว่า “open_basedir restriction in effect”
ถ้าอ่านได้: แสดงว่าการตั้งค่าของคุณยังผิดอยู่ อาจจะลอง restart server ดูก่อน


ตัวอย่าง phpMyAdmin

fastcgi_param PHP_VALUE "open_basedir=/var/www/phpmyadmin/:/tmp/:/var/lib/php/sessions/";
ส่วนที่ php ใน site นี้ทำงานได้

  • /tmp/
  • /var/lib/php/sessions/
  • /var/www/phpmyadmin/

ตัวอย่าง WordPress

fastcgi_param PHP_VALUE "open_basedir=/tmp/:/var/www/plusmagi.com/pitt/";
ส่วนที่ php ใน site นี้ทำงานได้

  • /tmp/
  • /var/www/plusmagi.com/pitt/