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麰鷈龁鷆黸


评论 (写第一个评论)