Giới thiệu

Vài ngày trước, khi tư vấn cho một dự án Laravel hiện đã được release, tôi thấy rằng nó đã bật debug trong file .env APP_DEBUG = true.

Vấn đề là khi trường hợp này xảy ra, tất cả thông tin trong file này được hiển thị cho người dùng hoặc bất kỳ ai truy cập trang web như: DB_DATABASE, DB_USERNAME, DB_PASSWORD và những thông tin quan trọng khác.

Và có nhiều dev quên thay đổi biến APP_DEBUG thành false. Bạn có thể kiểm tra nó trên Google: DB_password filetype:env

Bạn thấy có nhìn thấy web của mình ở đây không?

Hình ảnh này trông khá đáng sợ phải không?

Như bạn có thể nhận thấy, điều này dẫn đến rủi ro bảo mật rất lớn vì trang web có thể bị tấn công.

Một ví dụ khác là, biến APP_DEBUG được đặt thành true sẽ hiển thị tất cả các giá trị từ file .env.

Có thể thấy rằng tất cả các thông tin đều bị lộ, ngay cả cấu trúc nơi lưu trữ dự án, tất nhiên có nhiều biến số nữa bị lộ.

Khai thác lỗ hổng

Kết quả của việc bị lộ thông tin, không gì khác ngoài bị hacker khai thác lỗ hổng, tấn công hoặc lấy cắp thông tin. Một số kết quả mà tôi rút ra được từ quá trình điều tra:
1. Việc bị lộ email/password là thực sự nghiêm trọng. Cho dù không thể login được đối với tài khoản này, thì từ password mang tính cá nhân như thế này sẽ là một gợi ý không thể tốt hơn cho hacker có thể đăng nhập các tài khoản khác sau tìm được các thông tin cá nhân của user để thử:

MAIL_USERNAME=dev.test.web@gmail.com
MAIL_PASSWORD=Super!@#4

2. Việc để lộ id, secret key hay các thông tin setting khi sử dụng service của các bên thứ 3 (Facebook, Google, AWS,...) như thế này sẽ khiến user có thể phải trả tiền mặc dù mình không phải là người sử dụng dịch vụ. Bởi vì người khác hoàn toàn có thể sử dụng key này để call api hay thực hiện các thao tác tương tác với service.

;;;;;;;;;;; Facebook Settings ;;;;;;;;;;;;;;;
FACEBOOK_CLIENT_ID=588421581329613
FACEBOOK_CLIENT_SECRET=fed436dcf0f991b9120a00a2584b005d

;;;;;;;;;;; Google Settings ;;;;;;;;;;;;;;;
GOOGLE_CLIENT_ID=853517816712-f9v3sq7oimhbs70s6apga1kjlhpkl1ra.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=0M2wZoMUww8UJtRzUsKzQck9

# AWS RDS
DB_CONNECTION=mysql
DB_HOST=rdswssh45zep1dpvgvsjvpo.mysql.rds.aliyuncs.com
DB_PORT=3306
DB_DATABASE=game
DB_USERNAME=jtp
DB_PASSWORD=crgGodH8WaYAXgtu

;;;;;;;;;; ReCaptcha Secret Key ;;;;;;;;;;;;;;; RECAPTCHA_SECRET_KEY=6LfarB8UAAAAAJBSIY-T0qpfeUevEPNob8f3LcSz

SMS_API_KEY=NCSAQRVGA2MDVBIP
SMS_SECRET=YCBIMEO7NSB6BEO7TTS62BCZOWACLNDE

3. Đối với những ứng dụng sử dụng db internal thì việc khai thác lỗ hổng có thể chưa đạt được do cần phải biết được password hosting để connect DB qua ssh.

Nhưng với những ứng dụng sử dụng db external và public thế này, khi đã lộ thông tin thì chắc chắn hacker sẽ lấy được DB

Thông tin DB bị lộ
Thông tin DB bị lộ
Đây là một nạn nhân đã bị tôi lấy được DB

Đây là một nạn nhân đã bị tôi truy cập được DB. Tuy thông tin cũng không có nhiều giá trị :( nhưng đây cũng là một ví dụ để bạn cẩn thận hơn.

Giải pháp


Chúng ta có một số giải pháp để ngăn điều này xảy ra.

Đối với Laravel (<=7x): Che dấu các biến môi trường với Debug blacklist

Điều đầu tiên và rõ ràng nhất là chúng ta phải luôn nhớ đặt APP_DEBUG thành false. Nhưng nếu vì lý do nào đó mà chúng ta quên thực hiện bước này trong khi triển khai dự án, chúng ta có một công cụ mà nhiều dev đã bỏ qua và được gọi là debug_blacklist.

Nó là một mảng được tạo thành từ 3 key:

  • _ENV: các biến được hiển thị trong Enviroment Variables
  • _SERVER: các biến được hiển thị trong Server/Request Data
  • _POST: các biến được gửi qua phương thức này

Chúng ta sẽ làm một ví dụ về cách cấu hình của mảng đã nói trong file config/app.php. Các biến sẽ bị ẩn: APP_KEY, DB_DATABASE, DB_USERNAME, DB_PASSWORD, cả trong key _ENV_SERVER.

return [
 
    // ...
 
    'debug_blacklist' => [
        '_ENV' => [
            'APP_KEY',
            'DB_PASSWORD',
        ],
 
        '_SERVER' => [
            'APP_KEY',
            'DB_PASSWORD',
        ],
 
        '_POST' => [
            'password',
        ],
    ],
];

Bây giờ chúng ta kiểm tra lại trên trang hiển thị lỗi (debug).

Chúng ta có thể thấy giá trị của các biến được config ẩn đi thì sẽ hiện được thay thế bằng **** như thế này (`APP_KEY`, DB_PASSWORD). Những biến không được config trong mảng debug_blacklist sẽ hiển thị ra ngoài.

Sử dụng debug_blacklist giúp chúng ta bảo vệ thông tin của các biến môi trường trong các dự án đang trong quá trình phát triển và biến APP_DEBUG được set true, chúng ta có thể thêm bất kỳ biến nào xuất hiện trên màn hình lỗi và những biến này sẽ bị ẩn đi giống như các biến hiển thị ở bên trên.

Bạn có thể tham khảo thêm giải pháp này tại Laravel document.

Giải pháp khác

Một giải pháp khác là chúng ta cấp quyền 400 hoặc 404 đối với file .env khi CHMOD để người dùng bình thường không thể truy cập.

sudo chmod 400 <YOUR PROJECT PATH>/.env

Kết luận

Theo như tôi tìm hiểu thì các lỗi sơ đẳng này thường chỉ bị khi dùng framework Symfony hoặc Laravel các phiên bản cũ (<=7.x). Đối với phiển bản Laravel 8.x trở lên, đã khắc phục điểm này bằng cách không show toàn bộ các biến môi trường khi debug.

Nhưng theo tài liệu chia sẻ, vẫn có khả năng gây ra rủi ro cho ứng dụng của bạn.

For local development, you should set the APP_DEBUG environment variable to true. In your production environment, this value should always be false. If the variable is set to true in production, you risk exposing sensitive configuration values to your application's end users.

Do đó, cho dù sử dụng framework nào, mới hay cũ, thì bạn cũng nên lưu ý cho vấn đề này bằng việc bảo vệ file .env một cách cẩn thận.

Hy vọng bài viết này sẽ giúp ích cho các bạn thêm 1 kinh nghiệm nhỏ trong quá trình phát triển dự án. Cảm ơn vì đã đọc bài!

Tham khảo

https://laravel.com/docs/7.x/configuration#hiding-environment-variables-from-debug