Cấu hình nginx cơ bản - Phần 3
nginx
14
Male avatar

manhdung viết ngày 27/05/2015

Trong phần này, tôi sẽ tập trung viết về cách phân quyền thư mục web của nginx, cách xác thực cơ bản khi truy cập website và cách lọc truy cập đến website theo source IP.

Phân quyền thư mục web

Về cơ bản để website hoạt động được, tôi chỉ cần gán quyền owner đúng và gán permission là read cho owner đó là website hoạt động được. Việc gán quyền tối thiểu như vậy sẽ loại bỏ rất nhiều rủi ro không đáng có như việc up shell vẫn có thể xảy ra do code filter không đủ, bộ lọc bị lỗi logic nào đó chưa test hết... nhưng tuy nằm trên thư mục web của site mà shell đó không có quyền execute thì đâu có thể gây nguy hại cho website được.

Trước hết, quyền owner đúng là thế nào ? Trong hai phần trước, tôi đã thực hiện cấu hình vhost dùng nginx và vhost này cũng hỗ trợ chạy php nhờ vào một service php-fpm. Ở đây nginx service chạy dưới quyền của user nginx và php-fpm service chạy dưới quyền của user apache (mặc định là vậy, tôi có thể sửa lại trong config). Các file php bắt buộc cần có quyền read cho user apache để chạy được còn các file tĩnh khác như html, text/plain thì cần có quyền read cho user nginx để chạy được. Vậy tôi chỉ cần lọc ra các file php gán owner apache:apache và permission 440, các file còn lại owner nginx:nginx và permission 440 là được. Riêng với thư mục thì owner là nginx:nginx và permission là 550 (vì user nginx cần quyền execute để change dir)

Nhưng rủi ro ở đây là gì ?

Tất cả các website đang sử dụng chung owner hết. Website nào trên webserver cũng dùng apache và nginx user làm owner. Nếu user này bị nhân nhượng thì sao ? Các zero day vulnerability có thể xuất hiện bất cứ lúc nào trong các sản phẩm của nginx hay php-fpm và mức độ nguy hại sẽ bao trùm tất cả các website.

Vậy có thể làm gì ?

Tôi tạo ra cho mỗi website một user riêng. Ví dụ với site vhost.example.com thì tôi tạo ra user vhost_example_com

useradd -c “vhost.example.com user” -s /sbin/nologin -d /home/www/vhost.example.com

Sau đó gán quyền owner và permission cho website như sau:

  • owner cho toàn bộ site

    chown -R vhost_example_com:vhost_example_com /home/www/vhost.example.com
    
  • File nên gán permission 644

    find /home/www/vhost.example.com -type f -exec chmod 644 {} \;
    
  • Directory nên gán permission 755

    find /home/www/vhost.example.com -type d -exec chmod 755 {} \;
    

Như vậy, khi cần thiết tôi vẫn có thể dùng user vhost_example_com để sửa code của website và vẫn chỉ cho phép user nginx hay apache chỉ có quyền chỉ đọc trên site. Việc gán owner và permission cũng đơn giản hơn.

Mở rộng với thư mục upload

Nếu giờ client cần upload file lên website thì sao ? Thư mục upload thường là điểm yếu của website.

Cái này hơi khó. Tôi không chắc cách làm này tốt nhất nhưng hiện thời tôi đang gán như sau cho thư mục upload:

chown -R apache:apache /home/www/vhost.example.com/upload
find /home/www/vhost.example.com/upload-type f -exec chmod 644 {} \;
find /home/www/vhost.example.com/upload -type d -exec chmod 755 {} \;

Bảo mật trong thư mục upload tôi tham khảo trong:
http://software-security.sans.org/blog/2009/12/28/8-basic-rules-to-implement-secure-file-uploads/

Hầu hết các hướng bảo mật trong tài liệu cần sự can thiệp của developer ở tầng application. Một trong các hướng bảo mật trong tài liệu là đặt authentication trên thư mục upload do vậy có thể khoanh vùng được ai là người upload các file khả nghi. Nếu thư mục upload này được dùng bởi client thì không thể giới hạn như vậy được.

Kiểm soát truy cập sử dụng basic authentication

Việc đầu tiên là tạo file htpasswd. Một cơ sở dữ liệu nhỏ để thực hiện xác thực. Tốt nhất file này không nên đặt trong thư mục chứa web hay thư mục cài đặt của nginx.

/usr/bin/htpasswd -c /usr/local/etc/.vhost.example.com.htpasswd test1

Một file ẩn /usr/local/etc/.vhost.example.com.htpasswd được tạo ra.

Passwd của user test1 được mã hóa.
Nếu cần thêm một user, tôi dùng lệnh sau:

/usr/bin/htpasswd  /usr/local/etc/.vhost.example.com.htpasswd test2

Nếu cần xóa một user, tôi dùng lệnh sau:

/usr/bin/htpasswd -D  /usr/local/etc/.vhost.example.com.htpasswd test2

Danh sách các user trong htpasswd có thể xem trực tiếp bằng cách cat chính file htpasswd.

Tiếp đến, tôi chỉ cần thêm hai dòng vào server block trong

/usr/local/nginx/conf.d/vhost.example.com.conf

auth_basic "private site";
auth_basic_user_file /usr/local/etc/.vhost.example.com.htpasswd;

Lúc này /usr/local/nginx/conf.d/vhost.example.com.conf như sau:

server{
     listen       80;
     server_name vhost.example.com www.vhost.example.com;
     root /home/www/vhost.example.com;
     error_log  /var/log/nginx/vhost.example.com_error.log error;
     access_log  /var/log/nginx/vhost.example.com_access.log  main;
     auth_basic           "private site";
     auth_basic_user_file /usr/local/etc/.vhost.example.com.htpasswd;

     location /{
         index index.html index.php;

     }
     location ~ \.php {
        fastcgi_pass unix:/tmp/php_fpm.sock;
        fastcgi_index   index.php;
        include         /usr/local/nginx/conf/fastcgi_params;
        fastcgi_param   SCRIPT_FILENAME $document_root/$fastcgi_script_name;
    }

}

Sau khi reload lại nginx service
service nginx reload

Chú ý: Nên reload service nginx để đảm bảo các connection hiện tại đến nginx không bị ngắt đột ngột.

Tôi truy cập vào http://vhost.example.com/test.php
alt text

Nhập user name test1, password của user này như trong

/usr/local/etc/.vhost.example.com.htpasswd;

để truy cập thành công.

Việc sử dụng auth_basic có thể áp dụng linh động trên từng location. Ở đây tôi áp dụng auth_basic theo nguyên tắc deny all, allow selected. Tôi mặc định deny trên toàn bộ vhost sau đó allow trong một số location. Ví dụ tôi muốn bất kỳ ai cũng truy cập được vào location public mà không có rào cản gì. Tôi làm như sau:

mkdir -p /home/www/vhost.example.com/public
vi /home/www/vhost.example.com/public/test1.php
<?php
echo "test1.php"
?>

Tôi thêm dòng sau vào config vhost:

     location /public/{
        auth_basic off;
     } 

Lúc này /usr/local/nginx/conf.d/vhost.example.com.conf như sau:

server{
     listen       80;
     server_name vhost.example.com www.vhost.example.com;
     root /home/www/vhost.example.com;
     error_log  /var/log/nginx/vhost.example.com_error.log error;
     access_log  /var/log/nginx/vhost.example.com_access.log  main;
         auth_basic           "private site";
         auth_basic_user_file /usr/local/etc/.vhost.example.com.htpasswd;

     location /{
         index index.html index.php;
     }

     location /public/{
        auth_basic off;
     }  

     location ~ \.php {
        fastcgi_pass unix:/tmp/php_fpm.sock;
        fastcgi_index   index.php;
        include         /usr/local/nginx/conf/fastcgi_params;
        fastcgi_param   SCRIPT_FILENAME $document_root/$fastcgi_script_name;
    }

}

Sau khi reload lại nginx service, tôi truy cập vào

http://vhost.example.com/public/test1.php
và không có rào cản gì.

Giới hạn truy cập dựa vào source IP

Cũng tuân theo nguyên tắc deny all, allow selected. Tôi thêm hai dòng sau vào vhost config:

allow 192.168.3.0/24;
deny all;

Như vậy mọi request từ subnet 192.168.3.0/24 sẽ được cho phép còn lại sẽ bị deny hết. Cũng như auth_basic. Viêc sử dụng các chỉ thị allow và deny cũng linh động theo từng location.

Cuối cùng, /usr/local/nginx/conf.d/vhost.example.com.conf sẽ như sau:

server{
     listen       80;
     server_name vhost.example.com www.vhost.example.com;
     root /home/www/vhost.example.com;
     error_log  /var/log/nginx/vhost.example.com_error.log error;
     access_log  /var/log/nginx/vhost.example.com_access.log  main;

     auth_basic           "private site";
     auth_basic_user_file /usr/local/etc/.vhost.example.com.htpasswd;

     allow 192.168.3.0/24;
     deny all;

     location /{
         index index.html index.php;
     }

     location /public/{
        auth_basic off;
     }

     location ~ \.php {
        fastcgi_pass unix:/tmp/php_fpm.sock;
        fastcgi_index   index.php;
        include         /usr/local/nginx/conf/fastcgi_params;
        fastcgi_param   SCRIPT_FILENAME $document_root/$fastcgi_script_name;
    }
}

Kết thúc phần 3. Trong phần 4, tôi sẽ trình bày cách config vhost hỗ trợ https.

Nguồn tham khảo:

http://nginx.com/resources/admin-guide/restricting-access/

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

Male avatar

manhdung

44 bài viết.
239 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
Male avatar
67 11
Giới thiệu RabbitMQ là một message broker ( messageoriented middleware) sử dụng giao thức AMQP Advanced Message Queue Protocol (Đây là giao thức ph...
manhdung viết hơn 2 năm trước
67 11
Male avatar
45 4
Giả định bạn tiếp nhận một server mới toanh, bạn cần tìm một số thông tin về nó như loại CPU, loại main, loại memory, memory dùng của hãng nào... c...
manhdung viết hơn 1 năm trước
45 4
Male avatar
38 7
Giới thiệu MongoDB là một giải pháp nosql database. Data được lưu ở dạng các bson document. Hỗ trợ vertical scaling và horizontal scaling, dynamic...
manhdung viết hơn 2 năm trước
38 7
Bài viết liên quan
Male avatar
25 13
Vẫn theo khung sườn đã định trước từ phần 1, trong phần này tôi sẽ giới thiệu cách cấu hình nginx để thực hiện vai trò của một load balancer. Trư...
manhdung viết hơn 2 năm trước
25 13
White
6 3
Gần đây mình thấy có một module khá thú vị của nginx trên github nên đã thử biên dịch nginx với module này và test thử. Nhân tiện nên note lại để m...
Quăng viết hơn 1 năm trước
6 3
White
44 9
Bài viết này xin đề cập tới Nginx Load balancing 1. Thế nào Load Balancing Load Balancing hay còn gọi là Cân bằng tải ?? một kỹ thuật thường đượ...
Cùi Bắp viết hơn 1 năm trước
44 9
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


Male avatar
{{userFollowed ? 'Following' : 'Follow'}}
44 bài viết.
239 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!