2010-03-29 27 views
12

Tôi chỉ có một trang web để quản lý, nhưng không quá chắc chắn về mã mà anh chàng trước đó đã viết. Tôi đang dán quy trình đăng nhập bên dưới, bạn có thể xem và cho tôi biết nếu có bất kỳ lỗ hổng bảo mật nào không? Thoạt nhìn, có vẻ như người ta có thể nhận được thông qua SQL injection hoặc thao tác cookie và tham số? M =.Có lỗ hổng bảo mật nào trong mã PHP này không?


 

define ('CURRENT_TIME', time());// Current time. 
define ('ONLINE_TIME_MIN', (CURRENT_TIME - BOTNET_TIMEOUT));// Minimum time for the status of "Online". 
define ('DEFAULT_LANGUAGE', 'en');// Default language. 
define ('THEME_PATH', 'theme');// folder for the theme. 

// HTTP requests. 
define ('QUERY_SCRIPT', basename ($ _SERVER [ 'PHP_SELF'])); 
define ('QUERY_SCRIPT_HTML', QUERY_SCRIPT); 
define ('QUERY_VAR_MODULE', 'm');// variable contains the current module. 
define ('QUERY_STRING_BLANK', QUERY_SCRIPT. '? m =');// An empty query string. 
define ('QUERY_STRING_BLANK_HTML', QUERY_SCRIPT_HTML. '? m =');// Empty query string in HTML. 
define ('CP_HTTP_ROOT', str_replace ('\ \', '/', (! empty ($ _SERVER [ 'SCRIPT_NAME'])? dirname ($ _SERVER [ 'SCRIPT_NAME']):'/')));// root of CP. 

// The session cookie. 
define ('COOKIE_USER', 'p');// Username in the cookies. 
define ('COOKIE_PASS', 'u');// user password in the cookies. 
define ('COOKIE_LIVETIME', CURRENT_TIME + 2592000)// Lifetime cookies. 
define ('COOKIE_SESSION', 'ref');// variable to store the session. 
define ('SESSION_LIVETIME', CURRENT_TIME + 1300)// Lifetime of the session. 

////////////////////////////////////////////////// ///////////////////////////// 
// Initialize. 
////////////////////////////////////////////////// ///////////////////////////// 

// Connect to the database. 
if (! ConnectToDB()) die (mysql_error_ex()); 

// Connecting topic. 
require_once (THEME_PATH. '/ index.php'); 

// Manage login. 
if (! empty ($ _GET [QUERY_VAR_MODULE])) 
( 
// Login form. 
    if (strcmp ($ _GET [QUERY_VAR_MODULE], 'login') === 0) 
    ( 
    UnlockSessionAndDestroyAllCokies(); 

    if (isset ($ _POST [ 'user']) & & isset ($ _POST [ 'pass'])) 
    ( 
     $ user = $ _POST [ 'user']; 
     $ pass = md5 ($ _POST [ 'pass']); 

    // Check login. 
     if (@ mysql_query ("SELECT id FROM cp_users WHERE name = '". addslashes ($ user). "' AND pass = '". addslashes ($ pass). "' AND flag_enabled = '1 'LIMIT 1") & & @ mysql_affected_rows() == 1) 
     ( 
     if (isset ($ _POST [ 'remember']) & & $ _POST [ 'remember'] == 1) 
     ( 
      setcookie (COOKIE_USER, md5 ($ user), COOKIE_LIVETIME, CP_HTTP_ROOT); 
      setcookie (COOKIE_PASS, $ pass, COOKIE_LIVETIME, CP_HTTP_ROOT); 
     ) 

     LockSession(); 
     $ _SESSION [ 'Name'] = $ user; 
     $ _SESSION [ 'Pass'] = $ pass; 
     // UnlockSession(); 

     header ('Location:'. QUERY_STRING_BLANK. 'home'); 
    ) 
     else ShowLoginForm (true); 
     die(); 
    ) 

    ShowLoginForm (false); 
    die(); 
) 

// Output 
    if (strcmp ($ _GET [ 'm'], 'logout') === 0) 
    ( 
    UnlockSessionAndDestroyAllCokies(); 
    header ('Location:'. QUERY_STRING_BLANK. 'login'); 
    die(); 
) 
) 

////////////////////////////////////////////////// ///////////////////////////// 
// Check the login data. 
////////////////////////////////////////////////// ///////////////////////////// 

$ logined = 0,// flag means, we zalogininy. 

// Log in session. 
LockSession(); 
if (! empty ($ _SESSION [ 'name']) & &! empty ($ _SESSION [ 'pass'])) 
( 
    if (($ r = @ mysql_query ("SELECT * FROM cp_users WHERE name = '". addslashes ($ _SESSION [' name'])."' AND pass = ' ". addslashes ($ _SESSION [' pass']). " 'AND flag_enabled = '1' LIMIT 1 ")))$ logined = @ mysql_affected_rows(); 
) 
// Login through cookies. 
if ($ logined! == 1 & &! empty ($ _COOKIE [COOKIE_USER]) & &! empty ($ _COOKIE [COOKIE_PASS])) 
( 
    if (($ r = @ mysql_query ("SELECT * FROM cp_users WHERE MD5 (name)='". addslashes ($ _COOKIE [COOKIE_USER ])."' AND pass = '". addslashes ($ _COOKIE [COOKIE_PASS]). " 'AND flag_enabled = '1' LIMIT 1 ")))$ logined = @ mysql_affected_rows(); 
) 
// Unable to login. 
if ($ logined! == 1) 
( 
    UnlockSessionAndDestroyAllCokies(); 
    header ('Location:'. QUERY_STRING_BLANK. 'login'); 
    die(); 
) 

// Get the user data. 
$ _USER_DATA = @ Mysql_fetch_assoc ($ r); 
if ($ _USER_DATA === false) die (mysql_error_ex()); 
$ _SESSION [ 'Name'] = $ _USER_DATA [ 'name']; 
$ _SESSION [ 'Pass'] = $ _USER_DATA [ 'pass']; 

// Connecting language. 
if (@ strlen ($ _USER_DATA [ 'language'])! = 2 | |! SafePath ($ _USER_DATA [ 'language']) | |! file_exists ('system/lng .'.$_ USER_DATA [' language '].' . php'))$_ USER_DATA [ 'language'] = DEFAULT_LANGUAGE; 
require_once ('system/lng .'.$_ USER_DATA [' language'].'. php '); 

UnlockSession(); 
+4

Bao gồm địa chỉ của trang web này và tôi sẽ cho bạn biết. :) – MusiGenesis

+0

Sử dụng các dấu gạch chéo (md5 ($ pass)) là thừa. SQL Injection không thể làm cho nó nghĩ md5(), nó có thể * đôi khi * làm cho nó vượt qua addslashes(). Ngoài ra md5() sẽ không bao giờ tạo ra các dấu nháy đơn, hai qutoes, các dấu gạch chéo ngược hoặc các byte rỗng, vì vậy addslashes() sẽ không bao giờ làm bất cứ điều gì với một băm md5(). Nó tốt hơn để sử dụng adodb và truy vấn parametrized. – rook

Trả lời

17

Vâng, có một vài lỗ hổng trong mã này.

này có khả năng có thể là một vấn đề:

define ('QUERY_SCRIPT', basename ($ _SERVER [ 'PHP_SELF'])); 

PHP_SELF là xấu bởi vì kẻ tấn công có thể kiểm soát biến này. Ví dụ: thử in PHP_SELF khi bạn truy cập tập lệnh bằng url này: http://localhost/index.php/test/junk/hacked. Tránh biến này càng nhiều càng tốt, nếu bạn sử dụng nó, hãy chắc chắn bạn khử trùng nó. Nó là rất phổ biến để xem XSS cây trồng lên khi sử dụng biến này.

1st dễ bị tổn thương:

setcookie (COOKIE_USER, md5 ($ user), COOKIE_LIVETIME, CP_HTTP_ROOT); 
setcookie (COOKIE_PASS, $ pass, COOKIE_LIVETIME, CP_HTTP_ROOT); 

Đây là một lỗ hổng khá nghiêm trọng. Nếu kẻ tấn công đã tiêm SQL trong ứng dụng của bạn thì họ có thể lấy hàm băm md5 và tên người dùng và đăng nhập ngay lập tức mà không cần phải bẻ gãy mã băm md5(). Nó giống như bạn đang lưu trữ mật khẩu trong văn bản rõ ràng.

Lỗ hổng phiên này là hai lần, nó cũng là "phiên bất tử", ID phiên phải luôn là các giá trị được tạo ngẫu nhiên lớn hết hạn. Nếu chúng không hết hạn thì chúng sẽ dễ dàng hơn để gây sức mạnh.

Bạn nên KHÔNG BAO GIỜ phát minh lại bánh xe, gọi session_start() khi bắt đầu ứng dụng của bạn và điều này sẽ tự động tạo id phiên bảo mật hết hạn. Sau đó sử dụng một biến phiên như $_SESSION['user'] để theo dõi nếu trình duyệt được thực đăng nhập

2 lỗ hổng:.

$ pass = md5 ($ _POST [ 'pass']); 

md5() được chứng minh là an toàn vì va chạm đã được tạo ra chủ đích. md5() nên không bao giờ được sử dụng cho mật khẩu. Bạn nên sử dụng một thành viên của họ sha2, sha-256 hoặc sha-512 là những lựa chọn tuyệt vời.

3rd dễ bị tổn thương:

CSRF

Tôi không thấy bất kỳ sự bảo vệ CSRF cho bạn chứng thực logic. Tôi nghi ngờ rằng tất cả các yêu cầu trong đơn của bạn đều dễ bị tấn công bởi CSRF.

+1

OMG những gì một ... câu trả lời dựa trên những tin đồn không phải là một kiến ​​thức. –

+2

chăm sóc để định lượng điểm của bạn với chi tiết cụ thể đại tá? – Neil

+4

@Col. Shrapnel thật sao? Tất cả những gì tôi thấy là sự thật được củng cố bởi nhiều năm nghiên cứu. – rook

0

Câu trả lời được chấp nhận bị thiếu rất nhiều và sai về một số điều. Dưới đây là các lỗ hổng mà tôi thấy trong mã:

define('QUERY_SCRIPT', basename($_SERVER['PHP_SELF'])); 

Như đã nói ở nơi khác, điều này có thể chứa nhiều hơn chỉ là đường dẫn tập lệnh. Sử dụng $_SERVER['SCRIPT_NAME'] hoặc __FILE__ thay thế.

define('CP_HTTP_ROOT', ... 

Hằng số này được sử dụng để đặt đường dẫn cookie thành đường dẫn tập lệnh. Điều này không an toàn nhưng người dùng sẽ cần phải đăng nhập riêng biệt cho mọi tập lệnh. Thay vào đó, hãy sử dụng các phiên (được thảo luận bên dưới) và đặt một đường dẫn cơ sở cho ứng dụng của bạn.

UnlockSessionAndDestroyAllCokies() 

Tôi không biết chính xác điều này đang làm, nhưng nó không tốt. Chỉ cần bắt đầu phiên sớm trong tập lệnh theo mọi yêu cầu. Kiểm tra thông tin người dùng hiện có trong phiên để biết họ đã đăng nhập chưa.

$pass = md5($_POST['pass']); 

Mật khẩu phải có một muối duy nhất với mỗi băm và tốt nhất là sử dụng thuật toán băm tốt hơn. Những ngày này (PHP 5,5+), bạn nên sử dụng password_hashpassword_verify để quản lý các chi tiết băm mật khẩu cho bạn.

mysql_query("SELECT id FROM cp_users WHERE name = '". addslashes($user)... 

Đây là câu hỏi cũ, nhưng ngày nay, chức năng PHP không còn được hỗ trợ. Sử dụng mysqli hoặc PDO. Sử dụng thư viện không được hỗ trợ để bạn mở lỗ hổng chưa được vá. addslashes không phải là một sự bảo vệ hoàn hảo chống lại SQL injection. Sử dụng câu lệnh đã chuẩn bị hoặc ít nhất là chức năng thoát chuỗi của thư viện.

if (isset($_POST['remember']) && $_POST['remember'] == 1) 
( 
    setcookie(COOKIE_USER, md5($user), COOKIE_LIVETIME, CP_HTTP_ROOT); 
    setcookie(COOKIE_PASS, $pass, COOKIE_LIVETIME, CP_HTTP_ROOT); 
) 

Và đây là vấn đề lớn nhất. Cookie lưu trữ thông tin đăng nhập của người dùng. Bạn đang gửi lại một tên người dùng băm và mật khẩu băm như các giá trị cookie với phản hồi. Đây có thể dễ dàng được đọc và sử dụng bởi bên thứ 3. Vì kịch bản này sử dụng một băm đơn giản, một bảng cầu vồng sẽ cho phép ai đó tìm kiếm nhiều mật khẩu người dùng. Nhưng vì phản hồi chứa thông tin xác thực "được bảo mật", kẻ tấn công sẽ không cần phải làm gì khác ngoài việc chuyển chúng vào bất kỳ yêu cầu nào khác để đăng nhập. Đây không phải là cách thích hợp để "ghi nhớ" người dùng và không cần thiết.

Kết nối của người dùng với yêu cầu chỉ được xử lý trong phiên. Đó là mục đích của họ. Các yêu cầu và phản hồi chứa cookie có số nhận dạng ngẫu nhiên. Chi tiết người dùng chỉ còn trên máy chủ và liên kết đến số nhận dạng này. (Side lưu ý:. Có một lỗi mà khối này được bao bọc bởi ngoặc thay vì niềng răng)

$_SESSION['Pass'] = $pass; 

Bây giờ mật khẩu của người sử dụng đang được lưu trữ ở hai nơi: cơ sở dữ liệu và phiên lưu trữ. Nếu các phiên được lưu trữ bên ngoài cơ sở dữ liệu (và PHP lưu trữ chúng trên đĩa theo mặc định), bây giờ bạn có hai cách mà ai đó có thể cố gắng ăn cắp thông tin đăng nhập của người dùng.

if ($logined !== 1 && !empty($_COOKIE[COOKIE_USER]) ... 
    if (($r = @mysql_query("SELECT * FROM cp_users WHERE MD5(name)='". addslashes($_COOKIE [COOKIE_USER ])."' AND pass = '". addslashes($_COOKIE [COOKIE_PASS]).. 

Giờ đây, kẻ tấn công có thể cố gắng đăng nhập bằng cách chuyển tiêu đề cookie trong yêu cầu bằng md5 băm của tên người dùng và mật khẩu đã được trao cho họ trong phản hồi trước. Biểu mẫu đăng nhập phải là nơi duy nhất lấy thông tin đăng nhập của người dùng và đăng nhập chúng. Biểu mẫu này (và tất cả những người khác) nên sử dụng mã thông báo CSRF.

UnlockSession(); 

Một lần nữa tôi không biết điều này đang làm gì, nhưng ở cuối tập lệnh, phiên sẽ chỉ được ghi vào bộ nhớ.

Các vấn đề liên quan