Hướng dẫn dưới đây giúp thiết lập CGI (Common Gateway Interface) trên Apache2 để xây dựng các ứng dụng web động bằng bất kỳ ngôn ngữ nào.
Mục lục
Bật module CGI trên Apache2
Cài đặt Apache2 nếu chưa cài.
$ sudo apt-get install apache2
Cho phép Module CGI hoạt động.
$ sudo a2enmod cgi $ sudo systemctl restart apache2
Chuẩn bị Document Root cho ứng dụng CGI
Tạo một Document Root mới cho trang web, ví dụ /var/www/example
.
$ sudo mkdir -p /var/www/example/cgi-bin $ sudo chown -R www-data:www-data /var/www/example
Cấu hình VirtualHost
Giả sử tên miền bạn sẽ sử dụng là www.example.com
. File cấu hình sau cho phép tất cả các ứng dụng đặt trong thư mục cgi-bin
của web root có thể được khởi chạy bằng CGI.
/etc/apache2/sites-available/example.conf
Define VAR_DOMAIN www.example.com Define VAR_EMAIL webmaster@example.com Define VAR_ROOT /var/www/example <VirtualHost *:80> ServerName ${VAR_DOMAIN} ServerAdmin ${VAR_EMAIL} DocumentRoot ${VAR_ROOT} <IfModule mod_alias.c> <IfModule mod_cgi.c> Define VAR_CGI_BIN </IfModule> <IfModule mod_cgid.c> Define VAR_CGI_BIN </IfModule> <IfDefine VAR_CGI_BIN> ScriptAlias /cgi-bin/ ${VAR_ROOT}/cgi-bin/ <Directory ${VAR_ROOT}/cgi-bin> AllowOverride None Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch Require all granted </Directory> </IfDefine> </IfModule> ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost>
Hãy thay thế www.example.com
bằng tên miền của bạn, cũng như /var/www/example
bằng đường dẫn web root tương ứng.
Yêu cầu Apache2 sử dụng VirtualHost này. Tham số của a2ensite
là tên của file config trên (có hoặc không có phần mở rộng .conf
đều được).
$ sudo a2ensite example $ sudo systemctl reload apache2
Thử hoạt động của CGI
Tạo một file CGI script trong thư mục /var/www/example/cgi-bin
và phân quyền executable cho script.
Ví dụ, CGI script sau được viết bằng ngôn ngữ BASH sẽ in tất cả các biến môi trường và giá trị của chúng ra trình duyệt. Phần mở rộng của script là gì cũng được.
/var/www/example/cgi-bin/env-var.cgi
#!/bin/bash echo "Content-type: text/html" echo "" # mandatory echo "<html>" echo "<head>" echo "<title>Environment Variables</title>" echo "</head>" echo "<body>" echo "Environment Variables:" echo "<pre>" # Dump all environment variables and their values /usr/bin/env echo "</pre>" echo "</body>" echo "</html>" exit 0
Phân quyền executable cho CGI script, nếu không sẽ gặp lỗi 500 Server Error khi truy cập.
$ sudo chmod +x /var/www/example/cgi-bin/env-var.cgi
Truy cập CGI script từ trình duyệt qua địa chỉ: http://www.example.com/cgi-bin/env-var.cgi
.
Thực thi CGI dưới quyền root
Các ứng dụng CGI sẽ được thực thi dưới quyền của user www-data
, là một user có quyền lực tương đối hạn chế. Để thực hiện những tác vụ có quyền lực cao như root
thì có 2 hướng:
Cách 1: Điều khiển service đang chạy quyền root bằng IPC
Script CGI có điều khiển một ứng dụng Daemon khác chạy dưới quyền root thông qua một phương thức IPC (Interprocess Communication) như Pipe, UNIX domain socket v.v…
Đây là cách tương đối an toàn vì lúc này vấn đề an toàn chỉ tập trung ở Daemon và CGI Script của bạn.
Cách 2: Sử dụng suEXEC
Apache2 có một module là suExec cho phép chạy lệnh CGI dưới quyền một user khác. Dù không hỗ trợ tài khoản root
, ta vẫn có thể thiết lập user đó có quyền sudo
. Tham khảo cách cấu hình tại đây.
Cách 3: Cấp quyền sudo cho user www-data
Đây là cách rất nguy hiểm có thể tạo lỗ hổng bảo mật nghiêm trọng vì user www-data
được sử dụng với nhiều web khác chứ không chỉ giới hạn ở app CGI của bạn.
Bạn chỉ nên giới hạn số lệnh cho phép và những lệnh đó không nên có quyền chỉnh sửa hệ thống.
Ngoài ra do ứng dụng web không hỗ trợ tương tác người dùng nên phải cấu hình sudo
có thể thực thi mà không hỏi password.
$ sudo visudo
Thêm vào dòng sau trong trình sudo editor:
www-data ALL=(ALL) NOPASSWD: /path/to/command-1, /path/to/command-2
Với command-1 và command-2 là các lệnh bạn muốn chạy dưới quyền root với www-data, danh sách các lệnh cho phép ngăn cách bằng dấu phẩy.
Tuyệt đối ĐỪNG BAO GIỜ cấp quyền lực vô hạn cho www-data
như thế này!
www-data ALL=(ALL) NOPASSWD:ALL