2012-05-14 36 views
24

Tôi vừa xem qua mã này trong thư viện HTTP Auth của khung công tác Zend. Dường như nó đang sử dụng một hàm so sánh chuỗi đặc biệt để làm cho nó an toàn hơn. Tuy nhiên, tôi không hoàn toàn hiểu được ý kiến. Ai có thể giải thích tại sao chức năng này an toàn hơn làm $a == $b?Chức năng so sánh chuỗi an toàn

/** 
* Securely compare two strings for equality while avoided C level memcmp() 
* optimisations capable of leaking timing information useful to an attacker 
* attempting to iteratively guess the unknown string (e.g. password) being 
* compared against. 
* 
* @param string $a 
* @param string $b 
* @return bool 
*/ 
protected function _secureStringCompare($a, $b) 
{ 
    if (strlen($a) !== strlen($b)) { 
     return false; 
    } 
    $result = 0; 
    for ($i = 0; $i < strlen($a); $i++) { 
     $result |= ord($a[$i])^ord($b[$i]); 
    } 
    return $result == 0; 
} 
+0

Đây là những gì 'hash_equals' thực hiện trong PHP 5.6+ – caw

Trả lời

36

Có vẻ như họ đang cố gắng ngăn chặn timing attacks.

Trong mật mã học, một cuộc tấn công thời gian là một tấn công kênh bên trong đó những kẻ tấn công cố gắng thỏa hiệp một hệ mật bằng cách phân tích thời gian thực hiện để thực hiện các thuật toán mật mã. Mỗi thao tác logic trong máy tính cần có thời gian để thực thi và thời gian có thể khác nhau dựa trên đầu vào; với các phép đo chính xác về thời gian cho mỗi hoạt động, kẻ tấn công có thể làm việc ngược về đầu vào.

Về cơ bản, nếu mất một khoảng thời gian khác để so sánh đúng mật khẩu và mật khẩu không chính xác, bạn có thể sử dụng thời gian để tìm ra số ký tự bạn đã đoán đúng.

Hãy xem xét một so sánh chuỗi vô cùng thiếu sót (điều này về cơ bản là chức năng bình đẳng chuỗi bình thường, với rõ ràng một wait gia tăng):

function compare(a, b) { 
    if(len(a) !== len(b)) { 
     return false; 
    } 
    for(i = 0; i < len(a); ++i) { 
     if(a[i] !== b[i]) { 
      return false; 
     } 
     wait(10); // wait 10 ms 
    } 
    return true; 
} 

Giả sử bạn đưa ra một mật khẩu và nó (liên tục) mất một lượng thời gian cho một mật khẩu và khoảng 10 ms còn lại cho một mật khẩu khác. Thứ này nói lên điều gì? Nó có nghĩa là mật khẩu thứ hai có một ký tự chính xác hơn ký tự đầu tiên.

Điều này cho phép bạn thực hiện tấn công phim - nơi bạn đoán mật khẩu một ký tự tại một thời điểm (dễ dàng hơn nhiều so với đoán từng mật khẩu có thể). Trong thế giới thực, có những yếu tố khác liên quan, vì vậy bạn phải thử nhiều lần, nhiều lần để xử lý sự ngẫu nhiên của thế giới thực, nhưng bạn vẫn có thể thử mỗi mật khẩu một ký tự cho đến khi rõ ràng mất nhiều thời gian hơn, sau đó bắt đầu trên hai mật khẩu ký tự, v.v.

Chức năng này vẫn có một vấn đề nhỏ ở đây:

if(strlen($a) !== strlen($b)) { 
    return false; 
} 

Nó cho phép bạn sử dụng thời gian tấn công để tìm ra độ dài chính xác của mật khẩu, cho phép bạn không bận tâm đoán mật khẩu bất kỳ ngắn hơn hoặc dài hơn. Nói chung, you want to hash your passwords trước tiên (sẽ tạo chuỗi có độ dài bằng nhau), vì vậy tôi đoán họ không coi đó là vấn đề.

+1

thực sự. "đừng đến đó vì nó nguy hiểm, nhưng đi đến đó, bởi vì đó là con đường duy nhất" –

+1

Thú vị, nhưng hoàn toàn không chính xác. – rook

+0

@rook - tại sao nó chính xác? Từ các ý kiến ​​trong mã, đó là những gì zend đang cố gắng đạt được. – iWantSimpleLife

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