Bảo mật phiên PHP


125

Một số hướng dẫn để duy trì bảo mật phiên có trách nhiệm với PHP là gì? Có thông tin trên tất cả các trang web và đã đến lúc tất cả hạ cánh ở một nơi!

Câu trả lời:


88

Có một số điều cần làm để giữ an toàn cho phiên của bạn:

  1. Sử dụng SSL khi xác thực người dùng hoặc thực hiện các thao tác nhạy cảm.
  2. Tạo lại id phiên bất cứ khi nào mức bảo mật thay đổi (chẳng hạn như đăng nhập). Bạn thậm chí có thể tạo lại id phiên mỗi yêu cầu nếu bạn muốn.
  3. Có thời gian nghỉ
  4. Không sử dụng đăng ký toàn cầu
  5. Lưu trữ chi tiết xác thực trên máy chủ. Đó là, đừng gửi chi tiết như tên người dùng trong cookie.
  6. Kiểm tra $_SERVER['HTTP_USER_AGENT']. Điều này thêm một rào cản nhỏ để chiếm quyền điều khiển phiên. Bạn cũng có thể kiểm tra địa chỉ IP. Nhưng điều này gây ra vấn đề cho người dùng đã thay đổi địa chỉ IP do cân bằng tải trên nhiều kết nối internet, v.v. (đó là trường hợp trong môi trường của chúng tôi ở đây).
  7. Khóa quyền truy cập vào các phiên trên hệ thống tệp hoặc sử dụng xử lý phiên tùy chỉnh
  8. Đối với các hoạt động nhạy cảm, hãy xem xét yêu cầu người dùng đăng nhập cung cấp lại chi tiết xác thực của họ

15
Chỉ sử dụng SSL cho một số hoạt động là không đủ, trừ khi bạn có các phiên riêng biệt cho lưu lượng được mã hóa và không được mã hóa. Nếu bạn sử dụng một phiên duy nhất trên HTTPS và HTTP, kẻ tấn công sẽ đánh cắp nó trong yêu cầu không phải HTTPS đầu tiên.
Kornel

6
-1 tác nhân người dùng là tầm thường để giả mạo. Những gì bạn đang mô tả lãng phí mã và không phải là một hệ thống bảo mật.
rook

24
@The Rook, nó có thể là một rào cản tầm thường (kẻ tấn công có thể bắt giữ tác nhân người dùng của nạn nhân bằng cách sử dụng trang web của riêng họ) và dựa vào bảo mật thông qua che khuất nhưng nó vẫn là một rào cản bổ sung. Nếu HTTP Tác nhân Người dùng thay đổi trong quá trình sử dụng phiên, điều đó cực kỳ đáng ngờ và rất có thể là một cuộc tấn công. Tôi không bao giờ nói bạn có thể sử dụng nó một mình. Nếu bạn kết hợp nó với các kỹ thuật khác, bạn có một trang web an toàn hơn nhiều.
grom

5
@grom Tôi nghĩ nó giống như đặt một miếng băng dính qua cửa của bạn và nói rằng nó sẽ ngăn mọi người xâm nhập.
rook

8
Nếu bạn đang kiểm tra tác nhân người dùng, bạn sẽ chặn tất cả các yêu cầu từ người dùng IE8 khi họ chuyển chế độ tương thích. Xem những điều thú vị mà tôi đã theo dõi vấn đề này bằng mã của riêng mình: serverfault.com/questions/200018/http-302-probols-on-ie7 . Tôi đang kiểm tra tác nhân người dùng, bởi vì đó là một điều tầm thường để giả mạo, như những người khác đã nói.
phù hợp


11

Hai (hoặc nhiều hơn) xu của tôi:

  • Không tin ai
  • Bộ lọc đầu vào, đầu ra thoát (cookie, dữ liệu phiên cũng là đầu vào của bạn)
  • Tránh XSS (giữ cho HTML của bạn được định dạng tốt, hãy xem PHPTAL hoặc HTMLPurifier )
  • Phòng thủ chuyên sâu
  • Không để lộ dữ liệu

Có một cuốn sách nhỏ nhưng hay về chủ đề này: Essential PHP Security của Chris Shiflett .

Bảo mật PHP thiết yếu http://shiflett.org/images/essential-php-security-small.png

Trên trang chủ của cuốn sách, bạn sẽ tìm thấy một số ví dụ mã thú vị và các chương mẫu.

Bạn có thể sử dụng kỹ thuật được đề cập ở trên (IP & UserAgent), được mô tả ở đây: Cách tránh hành vi trộm cắp danh tính


+1 cho dự phòng XSS. Không có điều đó, không thể bảo vệ chống lại CSRF, và do đó ai đó có thể "cưỡi" phiên mà không cần lấy ID phiên.
Kornel

11

Tôi nghĩ một trong những vấn đề chính (đang được giải quyết trong PHP 6) là register_globals. Ngay bây giờ một trong những phương pháp chuẩn được sử dụng để tránh register_globalslà sử dụng $_REQUEST, $_GEThoặc $_POSTmảng.

Cách "chính xác" để làm điều đó (kể từ 5.2, mặc dù đó là một lỗi nhỏ ở đó, nhưng ổn định kể từ 6, sắp ra mắt) là thông qua các bộ lọc .

Vì vậy, thay vì:

$username = $_POST["username"];

bạn sẽ làm:

$username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING);

hoặc thậm chí chỉ:

$username = filter_input(INPUT_POST, 'username');

2
Điều này không liên quan đến câu hỏi nào cả.
Nhà phát triển Pixel

5
Có thật không? Vậy thì tại sao trong câu trả lời được chấp nhận họ lại đề cập đến việc không sử dụng đăng ký toàn cầu? Sẽ không, theo như hầu hết các nhà phát triển chạy bộ có liên quan, đăng ký toàn cầu và xử lý biến số thuộc phạm vi "phiên" ngay cả khi về mặt kỹ thuật không phải là một phần của đối tượng "phiên"?
cmcculloh

9
Tôi đồng ý, điều này không trả lời đầy đủ câu hỏi, nhưng nó chắc chắn là một phần của câu trả lời cho câu hỏi. Một lần nữa, điều này làm sáng tỏ một gạch đầu dòng trong câu trả lời được chấp nhận, "Đừng sử dụng đăng ký toàn cầu". Điều này cho biết phải làm gì thay thế.
cmcculloh


5

Sử dụng địa chỉ IP không thực sự là ý tưởng tốt nhất theo kinh nghiệm của tôi. Ví dụ; văn phòng của tôi có hai địa chỉ IP được sử dụng tùy thuộc vào tải và chúng tôi liên tục gặp sự cố khi sử dụng địa chỉ IP.

Thay vào đó, tôi đã chọn lưu trữ các phiên trong cơ sở dữ liệu riêng cho các tên miền trên máy chủ của mình. Bằng cách này, không ai trong hệ thống tệp có quyền truy cập vào thông tin phiên đó. Điều này thực sự hữu ích với phpBB trước 3.0 (họ đã sửa lỗi này) nhưng tôi nghĩ đó vẫn là một ý tưởng hay.


3

Điều này khá tầm thường và rõ ràng, nhưng hãy chắc chắn với session_destroy sau mỗi lần sử dụng. Điều này có thể khó thực hiện nếu người dùng không đăng xuất rõ ràng, vì vậy có thể đặt hẹn giờ để thực hiện việc này.

Đây là một hướng dẫn tốt về setTimer () và clearTimer ().


3

Vấn đề chính với các phiên và bảo mật PHP (bên cạnh việc chiếm quyền điều khiển phiên) đi kèm với môi trường bạn đang ở. Theo mặc định, PHP lưu trữ dữ liệu phiên trong một tệp trong thư mục tạm thời của hệ điều hành. Không có bất kỳ suy nghĩ đặc biệt hoặc lập kế hoạch, đây là một thư mục có thể đọc được trên thế giới, vì vậy tất cả thông tin phiên của bạn được công khai cho bất kỳ ai có quyền truy cập vào máy chủ.

Đối với việc duy trì phiên trên nhiều máy chủ. Tại thời điểm đó, tốt hơn là chuyển PHP sang các phiên do người dùng xử lý trong đó nó gọi các hàm được cung cấp của bạn thành CRUD (tạo, đọc, cập nhật, xóa) dữ liệu phiên. Tại thời điểm đó, bạn có thể lưu trữ thông tin phiên trong cơ sở dữ liệu hoặc memcache như giải pháp để tất cả các máy chủ ứng dụng có quyền truy cập vào dữ liệu.

Lưu trữ các phiên của riêng bạn cũng có thể thuận lợi nếu bạn ở trên một máy chủ dùng chung vì nó sẽ cho phép bạn lưu trữ nó trong cơ sở dữ liệu mà bạn thường kiểm soát nhiều hơn sau đó là hệ thống tệp.


3

Tôi thiết lập các phiên của mình như thế này-

trên trang đăng nhập:

$_SESSION['fingerprint'] = md5($_SERVER['HTTP_USER_AGENT'] . PHRASE . $_SERVER['REMOTE_ADDR']);

(cụm từ được xác định trên trang cấu hình)

sau đó trên tiêu đề xuyên suốt phần còn lại của trang web:

session_start();
if ($_SESSION['fingerprint'] != md5($_SERVER['HTTP_USER_AGENT'] . PHRASE . $_SERVER['REMOTE_ADDR'])) {       
    session_destroy();
    header('Location: http://website login page/');
    exit();     
}

3

php.ini

session.cookie_httponly = 1
change session name from default PHPSESSID

eq Apache thêm tiêu đề:

X-XSS-Protection    1

httpd.conf -> <FilesMatch "\. (php | phtml | aspx | htm | html) $"> Bộ tiêu đề X-XSS-Protection "1" </ FilesMatch>
user956584

Hãy lưu ý rằng điều đó X-XSS-Protectionkhông thực sự hữu ích chút nào. Trong thực tế, thuật toán bảo vệ chính nó thực sự có thể bị khai thác, làm cho nó tồi tệ hơn trước.
Pacerier

2

Tôi sẽ kiểm tra cả IP và Tác nhân người dùng để xem họ có thay đổi không

if ($_SESSION['user_agent'] != $_SERVER['HTTP_USER_AGENT']
    || $_SESSION['user_ip'] != $_SERVER['REMOTE_ADDR'])
{
    //Something fishy is going on here?
}

5
IP có thể thay đổi một cách hợp pháp nếu người dùng đứng sau trang trại proxy cân bằng tải.
Kornel

2
Và user_agent có thể thay đổi mỗi khi người dùng nâng cấp trình duyệt của họ.
Scotts

3
@scotts Tôi đồng ý với phần IP nhưng đối với nâng cấp trình duyệt, bạn sẽ đặt phiên khi họ đăng nhập để tôi không thấy cách họ sẽ nâng cấp trình duyệt ở đó mà không tạo phiên mới sau khi họ đăng nhập lại.
JasonDavis

Tôi tin rằng user_agent cũng có thể thay đổi khi chuyển đổi giữa chế độ tương thích trong IE8. Nó cũng rất dễ giả.

Đúng nhưng những gì về người dùng có IP tĩnh eq GSM và được thay đổi cứ sau nửa giờ. Vì vậy, IP được lưu trữ trong Phiên + tên máy chủ, KHI IP! = REMOTE_ADDR kiểm tra máy chủ và so sánh hostanmes eq. 12.12.12.holand.nl-> khi nào là holand.nl == đúng. Nhưng một số máy chủ lưu trữ có tên máy chủ dựa trên IP Sau đó cần so sánh mặt nạ 88,99.XX.XX
user956584

2

Nếu bạn sử dụng session_set_save_handler (), bạn có thể đặt trình xử lý phiên của riêng mình. Ví dụ: bạn có thể lưu trữ các phiên của mình trong cơ sở dữ liệu. Tham khảo các bình luận php.net để biết ví dụ về trình xử lý phiên cơ sở dữ liệu.

Các phiên DB cũng tốt nếu bạn có nhiều máy chủ nếu không, nếu bạn đang sử dụng các phiên dựa trên tệp, bạn sẽ cần đảm bảo rằng mỗi máy chủ web có quyền truy cập vào cùng một hệ thống tệp để đọc / ghi các phiên.


2

Bạn cần chắc chắn dữ liệu phiên là an toàn. Bằng cách xem php.ini của bạn hoặc sử dụng phpinfo (), bạn có thể tìm thấy các cài đặt phiên. _session.save_path_ cho bạn biết nơi họ được lưu.

Kiểm tra sự cho phép của thư mục và của cha mẹ của nó. Nó không nên công khai (/ tmp) hoặc có thể truy cập bởi các trang web khác trên máy chủ được chia sẻ của bạn.

Giả sử bạn vẫn muốn sử dụng phiên php, Bạn có thể đặt php để sử dụng một thư mục khác bằng cách thay đổi _session.save_path_ hoặc lưu dữ liệu trong cơ sở dữ liệu bằng cách thay đổi _session.save_handler_.

Bạn có thể đặt _session.save_path_ trong php.ini của mình (một số nhà cung cấp cho phép) hoặc cho apache + mod_php, trong tệp .htaccess trong thư mục gốc trang web của bạn : php_value session.save_path "/home/example.com/html/session". Bạn cũng có thể đặt nó vào thời gian chạy với _session_save_path () _.

Kiểm tra hướng dẫn của Chris Shiflett hoặc Zend_Session_SaveHandler_DbTable để đặt và xử lý phiên thay thế.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.