Bạn đã từng xây dựng một website bằng Laravel và public nó ra ngoài internet với mong muốn mọi người truy cập, sử dụng nó. Nhưng hãy nhớ rằng có những thông tin mà trang web của bạn sẽ không muốn người dùng nhìn thấy nó.Đó có thể là các tệp chứa thông tin cấu hình cơ sở dữ liệu, API keys hoặc cũng có thể là private keys cho web server’s SSL certificate của bạn. Hoặc cũng có thể là các thông tin do người dùng tải lên cho mục đích sử dụng cá nhân, không có người dùng nào khác được truy cập vào các thông tin nhạy cảm này để đọc, chỉnh sửa, ghi đè hay xoá mà không được phép. Lúc này bạn cần bảo vệ nó khỏi một số nhóm người dùng độc hại ví dụ như các hacker.

Bài viết này sẽ cho bạn thấy cách tấn công vào ứng dụng web qua path url của trang web không được bảo vệ kỹ càng các tệp thông tin nhạy cảm. Chúng ta sẽ bắt đầu với các trang web xây dựng bằng Laravel và sau đó sẽ là các cách để loại bỏ nguy cơ tấn công này.

Path Traversal Attack là gì ?

Giống như các cuộc tấn công XSS (cross-site-scripting) và SQL injection, thì mục đích tấn công qua path traversal là các thông tin của người dùng website mà trước đó không được loại bỏ phát hiện và ngăn chặn từ sớm giai đoạn phát qua các dòng code của lập trình viên. Với XSS, những hacker dựa vào trang web thực mã độc của chúng dưới dạng JavaScript. Và với SQL injection, những hacker cố gắng sửa đổi các truy vấn cơ sở dữ liệu thô. Với tấn công duyệt qua Path Traversal, những kẻ tấn công muốn webserver thông tin đầu vào độc hại của chúng như một tên tệp với thông tin đường dẫn. Bằng cách này, họ có thể làm cho webserver cung cấp thông tin hoặc sửa đổi bất kỳ tệp nào miễn là PHP có thể truy cập tệp đó, ngay cả khi người dùng cuối không cho phép.

Có hai cách mà hacker có thể đưa vào thông tin đường dẫn không mong muốn. Một sử dụng một đường dẫn tuyệt đối bắt đầu từ thư mục gốc của hệ điều hành (“/”). Cách khác sử dụng đường dẫn tương đối với ký hiệu hai chấm để đi lên một thư mục trong cấu trúc phân cấp (“…/”).

Hiểu về cấu trúc thư mục của Laravel

Để hiểu được cách thực hiện tấn công Path Traversal xảy bạn cần hiểu được cấu trúc thư mục của Laravel. Khi tạo một project Laravel mới bạn sẽ thấy cấu trúc thư mục của nó.

Trong cấu hình webserver của bạn, có một thư mục gốc cho dự án Laravel của bạn. Nó không phải là thư mục chính của project mà là thư mục con được public. Do đó, webserver có thể cung cấp trực tiếp bất kỳ tệp nào trong thư mục con đó mà không liên quan đến Laravel. Các tệp trong các thư mục khác như tệp tin cấu hình nhạy cảm, … vì vậy chúng được bảo vệ khỏi truy cập trực tiếp.

Giả sử trang web của bạn là example.com, request https://example.com/file.jpg sẽ hiển thị file.jpg từ thư mục public nếu nó tồn tại. Request cho https://example.com/path/to/page sẽ chuyển đến index.php vì đường dẫn đó không tồn tại dưới dạng tệp trong thư mục public và Laravel sẽ xử lý nó theo các route bạn đã định nghĩa.

Ví dụ: bạn có chuyển ra khỏi thư mục con public bằng cách yêu cầu https://example.com/../config/app.php không? tất nhiên là không. Các webserver như Apache hoặc Nginx đã bảo vệ website của bạn khỏi việc truy cập trái phép ra khỏi thư mục gốc (thư mục public). Và tất cả các đường dẫn khác được xử lý bởi các route index.php và Laravel, không tương ứng trực tiếp với các tệp. Vậy vấn đề nằm ở đâu?

Laravel File Delivery

Đôi khi bạn muốn cho phép truy cập vào một file ngoài thư mục public cho người dùng. Một ví dụ điển hình là bạn chỉ muốn cho phép người dùng đã xác thực truy cập tệp đó. Laravel hỗ trợ kiểu truy cập này này với hàm download() trên Response object. Dưới đây là một ví dụ về route để tải xuống một file cụ thể từ thư mục storage/app:

Route::get('/download/PrivateDocument', function() {
  return response()->download(storage_path('app/PrivateDocument.pdf'));
});

Ví dụ đoạn code trước đó là hoàn toàn an toàn vì không có tham số do người dùng truyền vào có thể gây ra lỗi. Bây giờ, hãy tưởng tượng bạn có nhiều file trong thư mục storage/app. Trong trường hợp này, bạn có thể tạo một function download được tham số hóa như sau:

Route::get('/download', function(\Illuminate\Http\Request $request) {
  return response()->download(storage_path('app/'.$request->get('filename')));
});

Để có thể truy cập được file như ví dụ đầu, người dùng sẽ nhập URL sau: https://example.com/download?filename=PrivateDocument.pdf

Vấn đề

Giả sử hacker cố gắng truy cập vào file trái phép. Ví dụ qua URL sau:

https://example.com/download?filename=../../.env

Chia buồn bạn đã mất hết thông tin biến môi trường nhạy cảm trong file .env.

“Vì không có kiểm tra path traversal attack. Hacker có thể tuỳ ý duyệt thư mục máy chủ website của bạn và lấy hết thông tin quan trọng. Vậy làm thế nào để ngăn chặn tấn công dạng này trong Laravel?”

Giải pháp

Nếu bạn xác định được các file cần thiết đều ở một thư mục, bạn có thể sử dụng hàm basename() tích hợp sẵn của PHP để loại bỏ bất kỳ thông tin đường dẫn nào khỏi tên file:

Route::get('/download', function(\Illuminate\Http\Request $request) {
  $filename = basename($request->get('filename'));
  return response()->download(storage_path('app/'.$filename));
});

Giải pháp trên sẽ ngăn chặn các truy cập trái phép với các thông tin nhạy cảm truyền qua đường dẫn. Nhưng nó có một hạn chế là không truy cập được các thư mục con nếu bạn muốn phân chia file theo thư mục. Ví dụ, bạn có thể có các file khác trong thư mục con và được phép truy cập. URL sau sẽ không truy cập được, ngay cả khi file đúng là lưu trữ ở đó /app/user1/document.pdf, vì nó sẽ tìm kiếm file như sau /app/document.pdf:

https://example.com/download?filename=user1/document.pdf

Chúng ta có thể giải quyết điều này bằng một hàm PHP khác có tên là realpath(). Không giống như basename(), hàm này sửa đổi một chuỗi và xóa tiền tố của nó, realpath() cũng sẽ tìm kiếm file được truy cập. Nó trả về false nếu file không tồn tại, bạn có thể sử dụng thông tin này để tạo ra thông báo lỗi thích hợp. Tuy nhiên, nếu file tồn tại, nó sẽ trả về toàn bộ đường dẫn của nó, giải quyết mọi ký hiệu không phù hợp trong trường hợp này.

Sau khi sử dụng realpath(), bạn có thể kiểm tra xem url được phép có phải là tiền tố của tên file đã nhập hay không và thực hiện hành động cần thiết nếu là truy cập trái phép. Ví dụ đoạn code sau đây minh họa điều đó. Đầu tiên, nó chỉ định thư mục được truy cập vào $basepath, sau đó đọc chỉ định tên file và xử lý nó bằng realpath(), và cuối cùng kiểm tra xem file có tồn tại hay không và nó có nằm trong $basepath hay không:

Route::get('/download', function(\Illuminate\Http\Request $request) {
  $basepath = storage_path('app');
  $filename = realpath($basepath.'/'.$request->get('filename'));
  if ($filename !== false && substr($filename, 0, strlen($basepath)) == $basepath)
    return response()->download($filename);

  App::abort(404);
});

Ví dụ trên sẽ trả về mã lỗi 404 cho cả file không tồn tại và tên file không hợp lệ.

Kết luận

Cách tấn công Path Traversal sẽ khiến cho bạn bị mất các thông tin nhạy cảm qua việc truy cập trái phép vào các thư mục, file không được phép. Để ngăn chặn điều này bạn cần sử dụng các kỹ thuật khác nhau như mục giải pháp đã đưa ở phần trên. Quan trọng nhất vẫn là bạn cần kiểm tra kỹ mọi thông tin đưa lên từ người dùng.


Khóa học PHP Laravel Fullstack 7 tháng - Cam kết việc làm - Khóa học dành người mới bắt đầu

Chi tiết - tại đây