[Notes] CloudFlare SSL Proxy và PHP Website.

Trường hợp tôi đang gặp phải:

Client → CloudFlare (Flexible SSL, Static Caching) → Nginx (php-fpm)

Một số yêu cầu tôi đã xử lý:

[+] Chuyển các truy cập HTTP sang HTTPS

Sau khi CloudFlare nhận được HTTP Request từ Client sẽ thêm các Headers sau trước khi Forward vào Nginx


Cf-Visitor : { "scheme": "http"}
X-Forwarded-Proto: http

[+] Có thể sử dụng một trong 2 headers này dùng làm patern để redirect, ví dụ:

if ($http_cf_visitor ~ '{"scheme":"http"}') {
     return 301 https://$server_name$request_uri;
}

Hoặc

if ($http_x_forwarded_proto = "http") {
      return 301 https://$server_name$request_uri;
}

[+] CloudFlare Caching và Redirect Loop khi chuyển request sang HTTPS

Khi sử dụng phương pháp Redirect sang HTTPS, nếu Static Caching của CloudFlare đang được mở thì mặc định ta sẽ gặp trường hợp như sau (ví dụ đối với các tập tin image, js, css):

- Client gửi HTTPS đến /image_abc.jpeg : Truy cập bình thường

- Client gửi HTTP đến http://..../image_abc.jpeg : Nginx trả về HTTP Status 301 như cấu hình. CloudFlare sẽ Cache lại Response này và Client nhận được Response như sau:

HTTP/1.1 301 Moved Permanently
Expires: …....
Cache-Control: …..
Server: …...
CF-RAY: ….....
Location: https://..../image_abc.jpeg

Client gửi tiếp Request đến https://..../image_abc.jpeg để lấy tập tin image_abc.jpeg thông qua HTTPS, nhưng CloudFlare vẫn sẽ trả về Reponse 301 đã Cache trước đó là

HTTP/1.1 301 Moved Permanently
Expires: …....
Cache-Control: …..
Server: …...
CF-RAY: ….....
Location: https://..../image_abc.jpeg

do CloudFlare thực hiện Static Cache dựa theo Request URI dạng “.../image_abc.jpeg” và cache cả các Response trả về với Status 301, 302 nên điều này sẽ dẫn đến lỗi Redirect Loop tại Client.

Để xử lỗi này ta chỉ cần thêm “Cache-Control: no-cache” vào các Reponse ta không muốn CloudFlare Cache, CloudFlare sẽ bỏ qua các Response này không Cache lại. Ví dụ với cấu hình Redirect ở trên, ta cập nhật lại như sau:

if ($http_x_forwarded_proto = "http") {
 add_header Cache-Control no-cache;
      return 301 https://$server_name$request_uri;
}

[+] Các CMS như Magento, Wordpress, PhpMyAdmin đứng sau CloudFlare SSL Proxy.

Các CMS như Magento và Wordpress được thiết kế một bộ URL Routing riêng, thường dựa vào các biến $_SERVER['SERVER_PORT'] hoặc $_SERVER['HTTPS'] để Source-Code trở nên linh hoạt hơn dựa theo Runtime Enviroment (Back-end Server). Đặc điểm của các biến $_SERVER['SERVER_PORT'] và $_SERVER['HTTPS'] phụ thuộc vào môi trường của Back-End Server. Trong mô hình hiện tại:

Flexible SSL Proxy → Nginx HTTP Server (php-fpm) → PHP Source-Code

theo như trên thì Nginx hiện tại chỉ chạy HTTP Server, giả sử đang Listen ở port 80 vậy

$_SERVER['SERVER_PORT'] = 80;
$_SERVER['HTTPS'] = null; # Không tồn tại

Việc này sẽ khiến không đồng nhất giữa cấu hình ở CMS Admin Dashboard, xử lý Client Request dựa theo 2 biến trên khi Site sử dụng HTTPS vì Runtime-Enviroment của Source-Code là HTTP không phải HTTPS

(Client : HTTPS) → (HTTPS : CloudFlare : HTTP) → [(HTTP : Nginx : HTTP) → Source-Code] 

dẫn đến các lỗi như Redirect Loop, Mixed-Content Scripts,... Để xử lý trường hợp này, ta có một số cách như sau để tạo ra các biến trên: - Tại cấu hình fast-cgi của Nginx thêm vào các biến sau:

location ~ \.php {
 …...
 …...
 fastcgi_param  HTTPS 'on';
 fastcgi_param  SERVER_PORT 443;
}

- Hoặc tại Source-Code khởi tạo các biến trên ( Magento có thể thêm vào index.php, Wordpress có thể thêm vào wp-config.php ):

….
if( isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') { 
 $_SERVER['HTTPS'] = 'on'; 
 $_SERVER['SERVER_PORT'] = 443; 
}
….

Nhận xét

Bài đăng phổ biến từ blog này

CVE-2019-12839: Lỗ hổng thực thi mã lệnh tùy ý trên OrangeHRM CMS

[Steganography] Kỹ thuật che dấu thông tin - Phần 2

PHP Race Condition Vulnerability Example