Quản lý môi trường trong lập trình dự án PHP

Dạo gần đây một số dự án bị leak key S3, Sendgird, Database… Mặc dù hầu hết là các thông tin ở môi trường dev ảnh hưởng ít, tuy nhiên vấn đề này mà xảy ra trên PRD tuỳ tính chất của thông tin bị leak mà sẽ sẽ ảnh hưởng rất lớn. Dưới đây thì mình sẽ đưa ra một số case mình điều tra cũng như đưa các phương án phòng ngừa mọi người cùng tham khảo.

1. Vấn đề

・ Server dev của một dự án A: key S3( bao gồm AWS Access Key ID và Secret Access Key) bị leak lên Git ・Server dev của một dự án B: Database bị xoá hết các table có tiền tố users.

2. Đánh giá mức độ ảnh hưởng vs các bước cần xử lý ngay

Đối vs dự án A Sau khi phát hiện key bị leak lên git sẽ tiền hành ngay các bước sau:

  1. Kiểm tra lại quyền của cặp access key id vs secret access key. Nếu như ngoài quyền S3 mà key này còn có quyền thao tác vs các tài nguyên khác ví dụ như EC2( thêm, xoá…) thì sẽ rất nguy hiểm. Tài khoản của bạn sẽ rất dễ bị dùng để clone ra một đống server để đào coin vs cuối tháng billing của bạn có thể lên đến vài chục thậm chí đến cả trăm nghìn đô. Trong case này của mình thì rất may là key này đã setting đúng( chỉ có quyền access vào bucket của dự án A trên S3).

  2. Sau đó thì deactive keys này ko cho phép sử dụng tiếp.

  3. Điều tra nguyên nhân vì sao lại bị leak keys.

    Đối với dự án B Ở thời điểm kiểm tra thì toàn bộ các bảng bắt đầu bằng user trong DB đều bị mất. Các bản backup đều không có. Kiểm tra có job backup tuy nhiên lại không chạy. Vấn đề này nếu thực sự xảy ra trên môi trường production của khách hàng thì sẽ rất là nghiêm trọng. Mất data sẽ là mất tiền, thậm chí còn rất nhiều tiền. Nên việc backup data nếu không sử dụng các dịch vụ của bên thứ 3 tự động backup thì bắt buộc mình phải có bước xử lý backup dữ liệu. Do là môi trường dev nên mính đã tiến hành các bước sau đây. Nếu thực sự là PRD nếu không xác định được nguyên nhân ngay thì thậm chí phải tạm thời maintaince toàn bộ hệ thống nếu cần thiết.

  4. Đổi password của tài khoản access vào database.

  5. Khôi phục lại database( chạy lại seed)

  6. Điều tra nguyên nhân

3. Điều tra nguyên nhân

Cả 2 dự án đều liên quan đến việc lộ keys chỉ set trong file .env nên cách tiến hành đều như nhau. Keys chỉ set trong .env - đã kiểm tra lại security group của server đều chỉ open all cho các port 22( ssh) vs http ( 80), ssl ( 443) nên mình nghĩ đến 2 khả năng dưới đây. Tất nhiên nếu security group bạn set không đúng thì sẽ có rất nhiều trường hợp bạn phải nghĩ tới. Lời khuyên ở chỗ này cho các bạn: Hạn chế truy cập đến server chỉ open cho những access cần thiết. Hạn chế thì có nhiều cách như hạn chế port, hạn chế ip trong security group, hay thêm basic authentication… Tuỳ dự án mà các bạn chọn cho mình phương án thích hợp

Lộ file SSH keys ・ Kiểm tra xem file SSH key hiện tại được share cho ai. Cắt hết quyền share cho các member không cần thiết. ( Hai dự án này thì đều share cho các bạn TeamLead) nên khả năng bị leak key ssh ra ngoài rất thấp. ・ Để chắc chắn hơn thì mình tiếp tục kiểm tra file log ssh bằng các câu lệnh dưới đây.

zgrep "Accepted publickey" /var/log/auth.log.* | zgrep -v "27.72.98.245" | zgrep -v "221.133.18.67"
grep "Accepted publickey" /var/log/auth.log | grep -v "27.72.98.245" | grep -v "221.133.18.67"

Giải thích lại command trên cho anh em dễ hiểu. Câu đầu là mình tìm tất cả các log có chứa dòng Accepted publickey ( vì khi ssh vào sẽ có log bắt đầu bằng Accepted publickey), sau đó loại bỏ tất cả các rows có chứa ip của công ty mình ( 27.72.98.245 vs 221.133.18.67) trong các file zip có tên file bắt đầu bằng auth.log. Câu thứ 2 thì thực hiện chức năng tương tự câu 1 chỉ khác là tìm trong file auth.log.

Sau khi thực hiện 2 command này thì mình xác định không có ip lạ nào ssh trực tiếp vào server. Chỗ này cũng khuyên luôn anh em nên hạn chế SSH theo cả IP.

Sau bước này mình có thể loại bỏ việc lộ ssh key.

Một phần nào của hệ thống khi gọi thông qua các request trực tiếp có hiển thị keys Do hệ thống chỉ set key này trong file .env nên khả năng cao các request vào các case lỗi thì mới hiển thị file .env. Suy nghĩ theo hướng này nên mình điều tra trước ở file access log của apache( hoặc nginx) tương ứng vs từng môi trường.

zgrep -v "/api" /var/log/apache2/access.log.* | zgrep -v "200"
grep -v "/api" /var/log/apache2/access.log | grep -v "200"

“/api” ở đây là tiền tố bắt đầu của các request sử dụng api của hệ thống nên tạm thời mình bỏ qua trước. Đối vs tuỳ dự án thì cái keys này có thể sẽ khác nên các bạn chọn cho phù hợp. Ở đây không phải là loại trừ các request thông thường của dự án không xảy ra lỗi mà lọc trước các request này vì khả năng thấp có thể xảy ra ở các request này. Sau khi điều tra ở các request đặc biệt trước nếu không có gì bất thường thì ta kiểm tra tiếp sau.

Ở kết quả của command trên thì các bạn nên lưu ý vào các request có sử dụng User-Agent đặc biệt khác so với các request thông thường vs mã code trả ra không phải là 200. Cái này nhìn vào logs các bạn có thể thấy luôn. Có thể có một vài request lạ được lặp đi lặp lại theo thời gian nên các bạn phải lọc ra và thử call bằng postman hoặc một tools nào đó để có thể call request tương tự. Ở đây mình dùng postman

Ở đây thì mình phát hiện ra luôn có một request lạ như dưới đây và kết quả sau khi gọi thì các bạn xem ở hình đính kèm.

54.89.44.126 - - [30/Mar/2021:08:12:13 +0000] "POST / HTTP/1.1" 405 866 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"

alt text Mình thấy nội dung msg vs nội dung file .env được trả hết ra nên xác định đây có thể là nguồn dẫn đến leak key.

Tiếp tục kiểm tra thêm lý do vì sao lại show hết ra .env thì phát hiện laravel nếu set debug mode = true thì sẽ trả ra nội dung set trong file .env. Laravel bản mới có vẻ đã vá lỗi này rồi. Đến đây thì mình có thể xác định được dự án A đã bị leak key do nguyên nhân này.

Dự án B thì đặc biệt hơn một chút là liên quan đến DB. Mình điều tra cùng 1 cách như trên và xác định được là đúng là cũng bị leak username/password access vào DB do bật debug mode của laravel. Kiểm tra kĩ thêm một chút thì thấy DB không cho phép remote access( nói nôm na tức là không được access từ ngoài vào mà chỉ được access từ trong instance bằng host 127.0.0.1 hoặc localhost). Đến đây thì hơi hoang mang một chút nên xem tiếp logs access thì thấy có nhiều access vào phpmyadmin. Kiểm tra lại thì đúng thật là có cài phpmyadmin. Chỗ này thì mình đưa phỏng đoán khả năng bị leak username/password vs access được vào DB thông qua phpmyadmin.

Tuy nhiên hệ thống lại chưa enable general log ( log access vào mysql) nên mình không có thông tin để kiểm tra lại chính xác là thông tin mình phỏng đoán ở trên đã chính xác chưa. Sau một thời gian disable debug mode ở laravel + đổi password ko thấy bị lại tình trạng tương tự nên khả năng phỏng đoán trên của mình là chính xác.

4. Cách biện pháp phòng ngừa

Công ty mình dùng Laravel nhiều nên khả năng bị lỗi này ở các dự án khác là có nên mọi người nên check lại và thực hiện các biện pháp dưới đây ngay lập tức.

  1. Set debug_mode = false cho các dự án làm bằng laravel
  2. Hạn chế access vào môi trường dev thông qua ips
  3. Password phải đặt đủ chữ hoa, thường, số, không đặt password có nghĩa( nên random)
  4. Keys aws phải đảm bảo chỉ set đủ quyền access vào các resources cần thiết. Hạn chế dùng keys mà chuyển sang dùng roles
  5. Log là rất quan trọng trong quá trình vận hành nên enable các logs cần thiết. Tất nhiên bạn phải đánh đổi về performance của hệ thống. Đổi lại bạn sẽ thấy tác dụng to lớn nhưng khi gặp issuses.

Cái quan trọng nhất là mọi người đều phải có nhận thức vs ý thức để đảm bảo an toàn thông tin cũng như sớm phát hiện các rủi ro có thể xảy ra.

Bài viết này ngoài lý do, cách giải quyết vấn đề liên quan thì mình cũng muốn chia sẽ cách suy nghĩ, cũng như phương hướng giải quyết của mình khi xảy ra các issues.

Post a Comment

Mới hơn Cũ hơn