4.7 Drupal flood 行为溢出控制机制详解

Drupal龫龧龥龢龠龝龙龕龔龒龐龎龙龋龊龉龇龆龅龃龁齽齹齸齵齳齯齭

Sorry, there have been more than 5 failed login attempts for this account. It is temporarily blocked. Try again later or request a new password.

鼩鼦鼤龋龊龆龅齵龐龎鼡鼟鼜鼛齵龉龇鼘鼖鼕鼔鼟鼜鼛龃鼐龙鼏鼌龐龎鼘鼖鼉龝鼤鼆龊龊鼂黾黼黻黹黵黲黱黭黩黨鼦黭黥黣黢齵IP龃鼏鼌鼟鼡鼟鼜鼛龐龎鼖黝黙IP黗龐龎黔鼦黓龕齵黱黒黎黋IP+鼟鼜鼛齵黇黅鼦5龉鼖黁龆鼘鼩龝龃鼏鼌黀麼龙麹鼖麵麴黗麱麮麫麵flood麩麥齵麤龎黱

麣麟鼕鼔flood龒麛鼦鼔麚麟麖麕麓麒drupal麑麏麎麋麇龁麅麂鹿鹽鹺鹹鹷鹴鹰黱黙麵鼘黋龐龎鹭鹪鹩鹦黅鼖黔龠鹩鹥麚麟麓麒齸鹰鼩麎鹣鹟鹛鹙齸齭

Drupal龁麅齵flood鹕黅鼖鹑鹎齵鹋鹈鼩鼦齭鹇黀麼齵龙麹鹆鼖鹃鼔黋鹂黨龠鹩龅鹁龉鹃鼔鹭鹪黱麋鸿鼘鼔龥鸼鼛鸸齭鹭鹪鸴鸰鹦黅黱

Drupal黒黎龁麅鼘鸮鼔鹭鹪鸴鸰鹦黅齭user login鸫contact黱麋麇鸨鼟鼜龐龎鹪鸦鼖鹑龆鸤鸢鸡鹰齵鸠鸟error龁齽鸼鸞鼖龢鸨麼鸝龒鼟鼜龐龎鹭鹪鸜鼟flood齵鸝鹷齭

function user_login_final_validate($form, &$form_state) {
  if (empty($form_state['uid'])) {
    // Always register an IP-based failed login event.
    flood_register_event('failed_login_attempt_ip', variable_get('user_failed_login_ip_window', 3600));
    // Register a per-user failed login event.
    if (isset($form_state['flood_control_user_identifier'])) {
      flood_register_event('failed_login_attempt_user', variable_get('user_failed_login_user_window', 21600), $form_state['flood_control_user_identifier']);
    }

    if (isset($form_state['flood_control_triggered'])) {
      if ($form_state['flood_control_triggered'] == 'user') {
        form_set_error('name', format_plural(variable_get('user_failed_login_user_limit', 5), 'Sorry, there has been more than one failed login attempt for this account. It is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', 'Sorry, there have been more than @count failed login attempts for this account. It is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', array('@url' => url('user/password'))));
      }
      else {
        // We did not find a uid, so the limit is IP-based.
        form_set_error('name', t('Sorry, too many failed login attempts from your IP address. This IP address is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', array('@url' => url('user/password'))));
      }
    }
    else {
      // Use $form_state['input']['name'] here to guarantee that we send
      // exactly what the user typed in. $form_state['values']['name'] may have
      // been modified by validation handlers that ran earlier than this one.
      $query = isset($form_state['input']['name']) ? array('name' => $form_state['input']['name']) : array();
      form_set_error('name', t('Sorry, unrecognized username or password. <a href="@password">Have you forgotten your password?</a>', array('@password' => url('user/password', array('query' => $query)))));
      watchdog('user', 'Login attempt failed for %user.', array('%user' => $form_state['values']['name']));
    }
  }
  elseif (isset($form_state['flood_control_user_identifier'])) {
    // Clear past failures for this user so as not to block a user who might
    // log in and out more than once in an hour.
    flood_clear_event('failed_login_attempt_user', $form_state['flood_control_user_identifier']);
  }
}

鼕鼔鶽龇鼦龐龎麩鶼龁鶻龙齵鶺鶹鶵鶱鶯鶬齵鶪鼟鶩鶨鼖 麋麇龢鸨鶦鶥鶡齵鶟龒鶜鸮鼔鶙flood鶜鶖齵鶽龇鶪鼟齭flood_register_event 鸫 flood_clear_event黱齸鹰麋麇鶕鶽龇鶒鶎鸰鶌鶟齸齭

/**
 * Registers an event for the current visitor to the flood control mechanism.
 *
 * @param $name
 *   The name of an event.
 * @param $window
 *   Optional number of seconds before this event expires. Defaults to 3600 (1
 *   hour). Typically uses the same value as the flood_is_allowed() $window
 *   parameter. Expired events are purged on cron run to prevent the flood table
 *   from growing indefinitely.
 * @param $identifier
 *   Optional identifier (defaults to the current user's IP address).
 */
function flood_register_event($name, $window = 3600, $identifier = NULL) {
  if (!isset($identifier)) {
    $identifier = ip_address();
  }
  db_insert('flood')
    ->fields(array(
      'event' => $name,
      'identifier' => $identifier,
      'timestamp' => REQUEST_TIME,
      'expiration' => REQUEST_TIME + $window,
    ))
    ->execute();
}

flood_register_event鼦鼟鵸鵵鵳flood鵰鵮鼖鼡鶽龇齵鵫黀鼔鵨龇鼦鵰鵮鼛鵤鼖龐龎鼕麥鼟龒鼘鸮鼔鵰鵮鼖1.failed_login_attempt_ip 2. failed_login_attempt_user黱 鵡鵞鼦鸟鵜黋ip鸫鼟鼜鼛齵龐龎鹭鹪鹩鸴鸰鹦黅黱

鵫鵙鼔鵨龇鼦鵕鵒龙麹鼖龢鸨鹋鹈鹪鼡鵰鵮鵑鵍齵鵕鵒龙麹鼖鵌麋麇鵉鹦黅龅鵅龙麹鹆齵鵂鴿鴻龉黱

鵫鴹鼔鵨龇鼦黋鹂鴷鴳鼖鴱齹鹑龕麋麇鹦黅齵鼦ip鴮鴬齵鵂鴿鴻鴩鼖鹇龐龎鹭鹪鼕麥齵鹦黅鼩鼦齹鴧鴦鼜鹺IP黀鴢鹇龋龊龐龎鴟鼦鴛鴙鼘黀麼龉龇鼖鼕鼔ip鼩龝龃鼏鼌龐龎鹭鹪黀鴘龙麹鼖黒黎鼦50龉黱鼟鼜龐龎鼕麥黔鼟龒鼘IP+鼟鼜鼛齵鴷鴳鴖龢鸨鹑龆鴓鴏鴎鴌齭user_failed_login_identifier_uid_only齵鴉鴎鴈黋鼟鼜鼛齵鴄鴂鹦黅鼖鴟鼦鼕鼔鹦黅鶩鳾鳽鴿鼟鳻鹣鼖鳷鸨黀鳳鳯鳬鼟鳩鼖鼩鼦齹鴧鴦鼜鹺黀鴢龋龊鹃鼔鼟鼜鼛齵龐龎鴛鴙鼖鼡鼟鼜鼛+IP鹪鳦鳤齵鴷鴳麑龝龃鳡鼏黀鴘龙麹鼖鵡鵞鼩鼦鹇黀麼龙麹鹆鼕鼔ip鳯龠鼆鼟鼕鼔鼟鼜鼛鶌龋龊龐龎鼘黱

黔鶜黀鼔鶽龇鼦齭flood_clear_event

/**
 * Makes the flood control mechanism forget an event for the current visitor.
 *
 * @param $name
 *   The name of an event.
 * @param $identifier
 *   Optional identifier (defaults to the current user's IP address).
 */
function flood_clear_event($name, $identifier = NULL) {
  if (!isset($identifier)) {
    $identifier = ip_address();
  }
  db_delete('flood')
    ->condition('event', $name)
    ->condition('identifier', $identifier)
    ->execute();
}

鳟鼛鵞鳝鼖鼩鼦麫麵鸴鸰麤龎鼖鳜鳚鵨龇鶌鶟鼖麫麵齵鼦鹃鼔鴷鴳齵鹃鼔鵰鵮齵鸴鸰麤龎黱鼟鼜龐龎鼕麥鼦鹇鼟鼜龐龎鴈鳘鹽鼖鳗鼡鼟鼜鼛齵鴷鴳齵龐龎鵰鵮麫鳔鼖鵡鵞鼦鼤龐龎鴈鳘鼘鳐鶥鼤鼦黓龕鼟鼜鼖鼩鳯麎鼤鳌鳈鳆龕鼘黱

鶜鼘鵵鵳鸫麫麵鼖麣麟黔鳂鲾鲻鼖鼩鼦麋麇鲹鼡鲷鵉鹇龐龎龙鲾鲻龒麛黭黥齵鴷鴳黋鹂鶜麏鶜黁龆鸴鸰鹦黅鴻龉麒

鹑龆黋鼟鼜龐龎龆鲵齵鶵鶱鶪鼟鲳鲯鼖麋麇鶟龒鼖鵫鵙鶯龐龎鶵鶱齵鶩鶨齭user_login_authenticate_validate鼖鼕鼔鶽龇麥鸜鼟鼘flood_is_allowed鶽龇鶌鲬鲨鲾鲻黱

/**
 * A validate handler on the login form. Check supplied username/password
 * against local users table. If successful, $form_state['uid']
 * is set to the matching user ID.
 */
function user_login_authenticate_validate($form, &$form_state) {
  $password = trim($form_state['values']['pass']);
  if (!empty($form_state['values']['name']) && strlen(trim($password)) > 0) {
    // Do not allow any login from the current user's IP if the limit has been
    // reached. Default is 50 failed attempts allowed in one hour. This is
    // independent of the per-user limit to catch attempts from one IP to log
    // in to many different user accounts.  We have a reasonably high limit
    // since there may be only one apparent IP for all users at an institution.
    if (!flood_is_allowed('failed_login_attempt_ip', variable_get('user_failed_login_ip_limit', 50), variable_get('user_failed_login_ip_window', 3600))) {
      $form_state['flood_control_triggered'] = 'ip';
      return;
    }
    $account = db_query("SELECT * FROM {users} WHERE name = :name AND status = 1", array(':name' => $form_state['values']['name']))->fetchObject();
    if ($account) {
      if (variable_get('user_failed_login_identifier_uid_only', FALSE)) {
        // Register flood events based on the uid only, so they apply for any
        // IP address. This is the most secure option.
        $identifier = $account->uid;
      }
      else {
        // The default identifier is a combination of uid and IP address. This
        // is less secure but more resistant to denial-of-service attacks that
        // could lock out all users with public user names.
        $identifier = $account->uid . '-' . ip_address();
      }
      $form_state['flood_control_user_identifier'] = $identifier;

      // Don't allow login if the limit for this user has been reached.
      // Default is to allow 5 failed attempts every 6 hours.
      if (!flood_is_allowed('failed_login_attempt_user', variable_get('user_failed_login_user_limit', 5), variable_get('user_failed_login_user_window', 21600), $identifier)) {
        $form_state['flood_control_triggered'] = 'user';
        return;
      }
    }
    // We are not limited by flood control, so try to authenticate.
    // Set $form_state['uid'] as a flag for user_login_final_validate().
    $form_state['uid'] = user_authenticate($form_state['values']['name'], $password);
  }
}
/**
 * Checks whether a user is allowed to proceed with the specified event.
 *
 * Events can have thresholds saying that each user can only do that event
 * a certain number of times in a time window. This function verifies that the
 * current user has not exceeded this threshold.
 *
 * @param $name
 *   The unique name of the event.
 * @param $threshold
 *   The maximum number of times each user can do this event per time window.
 * @param $window
 *   Number of seconds in the time window for this event (default is 3600
 *   seconds, or 1 hour).
 * @param $identifier
 *   Unique identifier of the current user. Defaults to their IP address.
 *
 * @return
 *   TRUE if the user is allowed to proceed. FALSE if they have exceeded the
 *   threshold and should not be allowed to proceed.
 */
function flood_is_allowed($name, $threshold, $window = 3600, $identifier = NULL) {
  if (!isset($identifier)) {
    $identifier = ip_address();
  }
  $number = db_query("SELECT COUNT(*) FROM {flood} WHERE event = :event AND identifier = :identifier AND timestamp > :timestamp", array(
    ':event' => $name,
    ':identifier' => $identifier,
    ':timestamp' => REQUEST_TIME - $window))
    ->fetchField();
  return ($number < $threshold);
}

鲠鵉鶟齸鵫鵙鼔鵨龇 threshold鼖鲞黥麏鶜鸰鲨龆鼖鼕鼔鶼鲚鲘鹪齭鲗鴉黱鳟鼛鵞鳝鼩鼦鹃鼔鴷鴳鹇鹃鼔鵰鵮齵鵕鵒龙麹鹆龢鲔鹭鼡鵰鵮鹭鹪齵鶺鹣鴻龉黱

鲒鵕鵒龙麹鸫鲗鴉鼖鲑鼔鵰鵮鶜鼦鶜鶼鲎齵鴎鴌鹦黅齵鼖鴱齹鼟鼜龐龎齵鵕鵒龙麹鴖鸨ip鴷鴳鹪鸦鳩齭variable_get('user_failed_login_ip_window', 3600)鼖鲗鴉齭variable_get('user_failed_login_ip_limit', 50)鼖鲋鳝鼩鼦齭鹇1鲊龙鹆鼖鲑鼔ip黨龠鲔鹭50龉龐龎鹭鹪黱黁龆鼕鼔鲗鴉鼩龝龃鳡鼏黱

麣麟鳡鼏龅鵅龙麹麓麒鼕鼔鳯鼦鲈麼齵龙麹鼖鹣鹟鲇黀齸flood_is_allowed鶽龇鶒鼩鼘鹈鼘鼖鼩鼦黗鶟齸鹇黭黥龙麹鲅黥齵鵕鵒龙麹鹆鼖鳌鳈齵鸴鸰麤龎齵龇鴌鶜麏鶜鲄龒鲗鴉鼖鲁鲄龒鼘鼩鱿鼌鱾齸鶌齵鹭鹪鼖鲁麏鶜鲄龒鼖鼩鹑龆鼖鱽鱻鲅齸鱷鹭黱

麣鱴鵸鼤鱱龙鱮龃鹈鼏鼖黔鱬鶟鼤鵂鴿齵龙麹鸟鱫鼖鳯龆鱩齹鼦黀鵒鱨鵂鴿齵鼖麣鱦鱣鸡鼩鼦鹇黀鼔鵕鵒龙麹鹽鱟龠鱽鱻龋龊黱鴱齹ip龐龎黒黎鼩鼦鹇1鲊龙鹽鼘黱

鳷鸨鳐鱜鱚齸鼟鼜龐龎鼕麥齵鸴鸰鹦黅鱙鲵鼩鼦鴖鸨ip鴷鴳鹪鸦鳩齭 鹇龐龎鶵鶱齵鱙鲵麥鼖鱖鸜鼟flood_is_allowed鶌鲾鲻黭黥ip鹇龆黗1鲊龙鹆齵龐龎鹭鹪鼦鱕鳌鳈鲄龒鼘50龉鼖鲁鱒鲄龒鱎鼏鼌龐龎鼖鲁鱍鲄龒鼖鱎鸜鼟flood_register_event黹鱋黀鱉鸴鸰麤龎鼖黩鹽鱈鹭黱


Druapl齵鼕鼔鳘龠鱅鱃齵黔鱂鱁鼖麏鶜龃鱁鰾鰺鰷鸰鶌鼖鹇鰵鶩鰳鰱鸤鸢鵵鵡龒鶜鸮鼔鵫鴹鶩鰮鰭龁麅鼘龐龎鸫contact齵鵕鵒龙麹鸫鴻龉齵鹹鹷鼖鸨鰩鸴鸰麤龎齵麫麵鰧鹋黱flood_unblock鰮鰭 鸫 flood_control鰮鰭.

image

image

麣麟鹑龆黋flood齵鱁鰾鼘鹈鼖麋麇鲹鼡龢鸨鰣龒龢鸨鹇黝黙鴮鶩麑龠鼟龒黙鼖鴱齹麋麇黋龕鰠齵ip鰞鰜鸝鹷鹩黀齸鳡鼏鹕黅鼖鴱齹鰣黋鵵鵳鹩黀齸鰘鰗鼖鼩龢鸨鰖鹷鴱齹1鲊龙鹆黀鼔ip黨龠鵵鵳10鼔鼟鼜黱黔龢鸨黋鰔鰐鶵鶱黲鰌鰉鹩鲾鲻鼖鴱齹1鲊龙鹆黀鼔ip黨龠鰌鰉10龉鶵鶱黲黱

麋麇龢鸨鵨鰆flood_unblock鸫flood_control鼖鰅鰄鹩黀鼔鹽鹺鹹鹷鰀鯿鵰鵮齵鵕鵒龙麹鸫鲗鴉鼖黔鶜鰧鹋flood麤龎齵鹴鹰鼖龢鸨鯻鯸鳡鼏黱

鱜鱚黀齸齭flood鹕黅鲠鵉鼦鼟鶌黋ip鼂黾鼟鼜鲔鹭鯷鯳鹭鹪齵鴻龉鹦黅黱

鯱鯭鯪鯧齭drupal龁麅齵flood鹕黅鶜黀鼔鶥鶡齵黢鯥鼩鼦鹹鹷鯱鯭鳯鶩鯣鼖黹鱋黀鼔鵰鵮齵鹦黅鼖鯡鯞鼦龒鼡鵰鵮鯝鲹齵鶖鯛鶽龇麥黗鶪鼟鼖鼕麑鼦鹪鱱麏鶜龠鯚龁麅鹽鹺鹹鹷鰧鹋鳘龠齵鯖鯓鼖麏鶨鹇鹽鯐鯏黀鰧鹋黱鯍齹鴧龠鴏鴈黋url鯏黀鲔鹭鲾鲻鼩鶦鶩鯣鼘鼖鶙web鲹鼟鰘鯉鯈龁麅齵鹹鹷鶦鲒鼖鴱齹鯇麥鯅鲹鼟鰘鯉鯈龁麅齵cc鰞鰜鰘鰗鯁鱎鰅麼鳝鳘龠鼖鴟鼦黥龁鼦鼤齵鹭鹪鼦鹑龆鱾鵒鶩鳾龁麅齵鼖鴱齹龐龎鵵鵳鮾鼦黥鹺鶪鼟鼤龁麅齵ajax url鼖鯍鳯鼦鴢鱾鼟齵drupal麩鶼龁鶻黱


评论 (写第一个评论)