8

私は、潜在的に多くのユーザーを持つ PHP で構築されたかなり大きな Web サイトに取り組んでいます。ログイン画面を自動試行から保護する方法を検討しています。登録フォームに CAPTCHA チェックを既に含めていますが、サイトをさらに強化したいと考えています。

私が知っているStackOverflowにも同様の質問があり、これを自分でゼロから実装できることは知っていますが(ログイン試行とその時間をデータベースに保存します)、それでも私はそのパスが嫌いです:

  • 概念的には、この種のロジックはアプリケーション レベルではなく、Web サーバー/インフラストラクチャ レベルに属していると思います。アプリケーションにこのロジックと複雑さがあるのは嫌いです
  • 特にデータベース レベルでのパフォーマンスが心配です。
  • このような共通のユーティリティをゼロから構築したくないという点で、私は怠け者です。

どんなアドバイスでも大歓迎です。これを実行できるある種の Apache モジュールを特に探していると思います。私のプラットフォームは PHP5 (CodeIgniter を使用)、Apache2、MySQL 5 です。

4

3 に答える 3

18

更新: レート制限に sleep() を使用しないでください! これはまったく意味がありません。私は手に良い解決策を持っていません。


ログイン試行が失敗した直後から始めるのが良いでしょsleep(1);う - 実装が簡単で、ほとんどバグがありません。

人間にとって 1 秒は大した時間ではありません (特に、人間によるログイン試行は頻繁に失敗しないため)。辞書攻撃は別の問題かもしれませんが、同じドメインにあります。

攻撃者がこれを回避するためにあまりにも多くの接続を開始した場合、一種の DOS 攻撃に対処します。問題は解決しました (しかし、別の問題が発生しました)。

あなたが考慮すべきいくつかのもの:

  • IP ごとにのみアカウントをロックすると、プライベート ネットワークに問題が発生する可能性があります。
  • ユーザー名だけでアカウントをロックすると、既知のユーザー名に対するサービス拒否攻撃が可能になります
  • IP /ユーザー名ベース(ユーザー名が攻撃されるもの)でロックすると、よりうまく機能する可能性があります

私の提案: 完全なロックは望ましくない(DOS)ため、より良い代替手段は次のとおりです。一意のIPから特定のユーザー名のログイン試行をカウントします。あなたは単純なテーブルでこれを行うことができますfailed_logins: IP/username/failed_attempts

ログインが失敗した場合、wait(failed_attempts);秒。xx 分ごとに、failed_logins:failed_attempts1 ずつ減少する cron スクリプトを実行します。

申し訳ありませんが、既製のソリューションを提供することはできませんが、これは簡単に実装できるはずです。

わかった、わかった。疑似コードは次のとおりです。

<?php
$login_success = tryToLogIn($username, $password);

if (!$login_success) {
    // some kind of unique hash
    $ipusr = getUserIP() . $username;

    DB:update('INSERT INTO failed_logins (ip_usr, failed_attempts) VALUES (:ipusr, 1) ON DUPLICATE KEY UPDATE failed_logins SET failed_attempts = failed_attempts+1 WHERE ip_usr=:ipusr', array((':ipusr' => $ipusr));

    $failed_attempts = DB:selectCell('SELECT failed_attempts WHERE ip_usr=:ipusr', array(':ipusr' => $ipusr));

    sleep($failed_attempts);
    redirect('/login', array('errorMessage' => 'login-fail! ur doin it rong!'));
}
?>

免責事項:これは特定の地域では機能しない場合があります。私が最後に聞いたのは、アジアでは国全体が NAT されているということでした (また、彼らは皆カンフーを知っています)。

于 2009-05-20T08:04:28.203 に答える
2

非常にダミーのテストされていない例ですが、主なアイデアはここにあると思います)。

if ($unlockTime && (time() > $unlockTime))
{
    query("UPDATE users SET login_attempts = 0, unlocktime = 0 ... ");
}
else
{
   die ('Your account is temporary locked. Reason: too much wrong login attempts.');
}
if (!$logged_in)
{
    $loginAttempts++;
    $unlocktime = 0;
    if ($loginAttempts > MAX_LOGIN_ATTEMPTS) 
    {
        $unlockTime = time() + LOCK_TIMEOUT;
    }
    query("UPDATE users SET login_attempts = $loginAttempts, unlocktime = $unlocktime ... ");
}

間違いをお詫びします - 数秒で書きました 広告はテストされませんでした... IP、ニックネーム、session_id などで同じことができます...

于 2009-05-20T09:03:16.400 に答える
-3

実際に問題が発生するまで、アプリの「強化」と「スケーリング」を待ってみませんか?最も可能性の高いシナリオは、アプリに「多数のユーザー」が存在することは決してないということです。これは私には時期尚早の最適化のように聞こえますが、避けるべきものです。

  • ボットが悪用されたら、サインアップを強化します。1日あたりの登録数が1000を超えるまで、キャプチャを実際に削除します。
  • パフォーマンスの問題が発生したら、実際のボトルネックを修正してパフォーマンスを向上させます。
于 2009-05-20T09:48:32.703 に答える