2010-08-22 40 views
6

Bạn tôi đã tìm thấy sự cố trong tập lệnh của tôi, nó cung cấp cho các tệp truy cập vào tệp gốc.Gốc bảo mật PHP

Url này cung cấp cho tập tin passwd:

http://site.com/attachment.php?file=../../../../../../etc/passwd 

Làm thế nào để thoát khỏi lỗ hổng bảo mật này?

+3

* (tham khảo) * http: //en.wikipedia. org/wiki/Directory_traversal – Gordon

+0

Như @Starx đã chỉ ra, hãy cố gắng tránh sử dụng đường dẫn tệp làm số nhận dạng cho tài liệu (Có các mối quan tâm khác, ngoài việc truyền tải thư mục). (Ý tưởng của @MartIX 'về băm (md5) có thể giúp cho việc triển khai gọn gàng). Hơn nữa nó là một ý tưởng tốt ** không chạy máy chủ của bạn dưới dạng root **. Sử dụng một người dùng riêng biệt chỉ có các quyền trên hệ thống cần thiết để hoàn thành nhiệm vụ của mình. – zpea

+0

(Đó là nếu bạn có nghĩa là có thể truy cập tệp chỉ có thể đọc được bởi người dùng gốc, như '/ etc/shadow'.'/Etc/passwd' có thể đọc được bởi bất kỳ người dùng nào trong Unix hiện đại, dĩ nhiên) – zpea

Trả lời

4

Có một số giải pháp khác nhau. Nếu chỉ có thể có một tên tệp, một giải pháp basename() sẽ hoạt động.

Tuy nhiên, nếu nó có thể là con đường, một giải pháp phức tạp hơn là cần thiết

//assume current directory, but can be set anything. Absolute path of course 
$basedir = dirname(__FILE__); 
//assume our files are below document root. 
//Otherwise use it's root dir instead of DOCUMENT_ROOT 
$filename = realpath($_SERVER['DOCUMENT_ROOT'].$_GET['file']); 
if (substr($filename,0,strlen($basedir)) !== $basedir) { 
    header ("HTTP/1.0 403 Forbidden"); 
    exit; 
} 

đó cũng là một tùy chọn cấu hình PHP hữu ích open_basedir

14

Không tải xuống tệp bằng chuỗi URL .... Xác định ID duy nhất để biểu thị tệp, chứ không phải đường dẫn.

Bạn có thể đã thấy các lượt tải xuống như thế này http://www.mysite.com/download.php?id=23423 những gì họ làm, sử dụng id này, để lấy tên tệp và đường dẫn từ db rồi tải xuống.

1

Tôi cho rằng bạn có thư mục chứa tất cả tệp đính kèm.

Chỉ cần kiểm tra xem tệp có nằm trong thư mục của bạn không.

// http://www.php.net/manual/en/function.basename.php 
// http://cz.php.net/manual/en/function.file-exists.php 
if (file_exists($attachments_path . "/" . basename($_GET['file'])) { 
    // do work 
} 

Starx đã đăng một giải pháp có vẻ ổn. Nó có thể được thực hiện mà không có một cơ sở dữ liệu, mặc dù. Nếu ai đó tải lên tệp, bạn có thể lưu trữ tệp dưới dạng md5($filename).$extension và sử dụng tập lệnh của bạn.

+1

Vì vậy, nếu có một tập tin gọi là "passwd" trong thư mục đính kèm, mã cho phép tải xuống/etc/passwd? Tôi không phải là lập trình viên PHP, nhưng tôi nghĩ bạn nên rõ ràng hơn khi nói rằng tệp cần truy cập phải được tạo theo cùng một cách: $ filename = $ attachment_path. "/". basename ($ _ GET ['file']) –

3

Bạn có thể sử dụng realpath()dirname() để kiểm tra URL chống lại $_SERVER['DOCUMENT_ROOT'] (hoặc bất kỳ thư mục nào là "an toàn" để tải xuống).

Nếu kết quả của realpath() điểm bên ngoài thư mục an toàn, bạn có thể từ chối yêu cầu tải xuống.

Ngoài ra còn có chỉ thị bảo mật open_basedir (và tùy chọn thời gian chạy là 5.3).