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麓鶩齱鶧點


评论 (写第一个评论)