編程學習網 > PHP技術 > PHP安全 > PHP安全-暴力攻擊
2016
03-15

PHP安全-暴力攻擊

暴力攻擊

  暴力攻擊是一種不使用任何特殊手段而去窮盡各種可能性的攻擊方式。它的更正式的叫法是窮舉攻擊——窮舉各種可能性的攻擊。

  對于訪問控制,典型的暴力攻擊表現為攻擊者通過大量的嘗試去試圖登錄系統。在多數情況下,用戶名是已知的,而只需要猜測密碼。

  盡管暴力攻擊沒有技巧性可言,但詞典攻擊似乎有一定的技巧性。最大的區別是在進行猜測時的智能化。詞典攻擊只會最可能的情況列表中進行窮舉,而不像暴力攻擊一樣去窮舉所有的可能情況。

  防止進行驗證嘗試或限制允許錯誤的次數還算是一個比較有效的安全手段,但是這樣做的兩難之處在于如何在不影響合法用戶使用的情況下識別與阻止攻擊者。

  在這種情況下,對一致性的判定可以幫助你區分二者。這個方法與第四章中所述的防止會話劫持的做法很相似,但區別是你要確定的是一個攻擊者而不是一個合法用戶。

  考慮下面的HTML表單:

CODE:

 

  <form action="http://example.org/login.php" method="POST">

  <p>Username: <input type="text" name="username" /></p>

  <p>Password: <input type="password" name="password" /></p>

  <p><input type="submit" /></p>

  </form>

攻擊者會察看這個表單并建立一段腳本來POST合法的數據給http://example.org/login.php:

CODE:

 

 <?php

 

  $username = 'victim';

  $password = 'guess';

 

  $content = "username=$username&password=$password";

  $content_length = strlen($content);

 

  $http_request = '';

  $http_response = '';

 

  $http_request .= "POST /login.php HTTP/1.1\r\n";

  $http_request .= "Host: example.org\r\n";

  $http_request .= "Content-Type: application/x-www-form-urlencoded\r\n";

  $http_request .= "Content-Length: $content_length\r\n";

  $http_request .= "Connection: close\r\n";

  $http_request .= "\r\n";

  $http_request .= $content;

 

  if ($handle = fsockopen('example.org', 80))

  {

    fputs($handle, $http_request);

 

    while (!feof($handle))

    {

      $http_response .= fgets($handle, 1024);

    }

 

    fclose($handle);

 

    /* Check Response */

  }

  else

  {

    /* Error */

  }

 

  ?>

使這段腳本,攻擊者還可以簡單地加入一個循環來繼續嘗試不同的密碼,并在每次嘗試后檢查$http_response變量。一旦$http_response變量有變化,就可以認為猜測到了正確的密碼。

  你可以通過很多安全措施去防止此類攻擊。我們注意到,在暴力攻擊中每次的HTTP請求除了密碼是不同的,其他部分完全相同,這一點是很有價值的。

  盡管在超過一定數量的失敗嘗試后臨時凍結帳號是一種有效的防范手段,但你可能會去考慮采用更確定的方式去凍結帳號,以使攻擊者更少地影響合法用戶對你的應用的正常使用。

  還有一些流程也可以增大暴力攻擊的難度,使它不太可能成功。一個簡單的遏制機制就能有效地做到這一點:

CODE:

 

 <?php

 

  /* mysql_connect() */

  /* mysql_select_db() */

 

  $clean = array();

  $mysql = array();

 

  $now = time();

  $max = $now - 15;

 

  $salt = 'SHIFLETT';

 

  if (ctype_alnum($_POST['username']))

  {

    $clean['username'] = $_POST['username'];

  }

  else

  {

    /* ... */

  }

  $clean['password'] = md5($salt . md5($_POST['password'] . $salt));

  $mysql['username'] = mysql_real_escape_string($clean['username']);

 

  $sql = "SELECT last_failure, password

          FROM   users

          WHERE  username = '{$mysql['username']}'";

 

  if ($result = mysql_query($sql))

  {

    if (mysql_num_rows($result))

    {

      $record = mysql_fetch_assoc($result);

 

      if ($record['last_failure']> $max)

      {

        /* Less than 15 seconds since last failure */

      }

      elseif ($record['password'] == $clean['password'])

      {

        /* Successful Login */

      }

      else

      {

        /* Failed Login */

 

        $sql = "UPDATE users

                SET    last_failure = '$now'

                WHERE  username = '{$mysql['username']}'";

 

        mysql_query($sql);

      }

    }

    else

    {

      /* Invalid Username */

    }

  }

  else

  {

    /* Error */

  }

 

  ?>

上例會限制在上次驗證失敗后對同一用戶再試嘗試的頻率。如果在一次嘗試失敗后的15秒內再次嘗試,不管密碼是否正確,驗證都會失敗。這就是這個方案的關鍵點。但簡單地在一次失敗嘗試后15秒內阻止訪問還是不夠的——在此時不管輸入是什么,輸出也會是一致的,只有在登錄成功后才會不同。否則,攻擊者只要簡單地檢查不一致的輸出即可確定登錄是否成功。

掃碼二維碼 獲取免費視頻學習資料

Python編程學習

查 看2022高級編程視頻教程免費獲取