web-dev-qa-db-ja.com

一定期間、複数の失敗したログインの要求をブロックします

Webサイトがあり、BOTsからの要求をブロックして、Webサイトへのブルートフォースログインを試みたいと思います。

現在、ログイン試行の保存にSessionを使用しており、ログインに3回失敗するとキャプチャが表示されますが、問題があります。ユーザーがブラウザを閉じると、セッションが削除されます。

BOTsとブルートフォースログインを防ぐために、どのような解決策を検討する必要がありますか?次のログインを管理するために保存する必要があるユーザーシステムまたはブラウザーのプロパティは何ですか?

編集1)

ASP.NETメンバーシッププロバイダーを使用していません。独自の認証クラスと承認クラスを使用しています

16
Arian

クライアントがCookieを保存する必要があり、攻撃者があなたを助けようとしないため、セッションを使用することはできません。グローバルな状態が必要になります。

悪者は匿名プロキシを使用するだけなので、わざわざIPアドレスを追跡する必要はありません。

必要がない限りアカウントロックアウトを使用しないでください(PCI要件)。これにより、攻撃者はユーザーにDoSを実行できます。

また、サーバーに多くの作業を行わせることで、自分でDoSを実行することを避けたいと考えています。

これは機能します:

認証に失敗した場合は、ユーザー名をカウントとともにグローバル状態で保存します。そのユーザー名での認証がさらに失敗した場合は、同期されたcount++。これにはredisを使用します。

count >= thresholdの場合、続行する前に解決済みのCAPTCHA値を要求します。ログイン画面にCAPTCHAを表示します。

successful認証時に、グローバル状態で保存されているユーザー名をクリアします。ユーザーに「信頼できるユーザーエージェント」のHMACを与える cookie ので、将来、そのUAのそのユーザー名に対してCAPTCHAを実行する必要はありません。

パスワードについても同じことができますが、おそらくより高いしきい値を使用します。

CAPTCHAが気に入らない場合は、たとえば、クライアントに非常に大きな数の素因数を計算して送信させることにより、プルーフオブワークを要求します。

その間、bcryptを使用してパスワードをハッシュしていることと、コスト係数が十分に高く、パスワードのハッシュに250ミリ秒以上かかることを確認してください。これにより、サーバーの速度が低下しますが、攻撃者の速度も低下します。 CAPTCHAに合格しない限り、ハッシュを避けてください(必要な場合)。

長く、複雑で、記憶に残るものを使用するようにユーザーを促しますか?パスワード。ブルートフォース攻撃が困難になります。

33
Neil McGuigan

最も簡単なのは、ボットを検出するcloudflare( https://www.cloudflare.com/features-security )などのCDNプロバイダーをソリューションの前に置くことです。多くのCDNがこれを提供しており、cloudflareには無料の料金があります。

または、これを自分で行おうとしている場合は、データベース内のユーザー名ごとの試行回数をカウントし、このカウントに基づいてキャプチャを表示できます。

4
ABrowne

IpAddress(匿名プロキシ)に基づいて無効なログインを識別します。アプリケーションの状態に保存される各無効なログインIPとログインカウントと時間。

クラスInvalidLoginを作成する

public class InvalidLogin
{
    public string IP { get; set; }
    public DateTime Attempttime { get; set; }
    public int AttemptCount { get; set; }
}

ログインイベント

protected void Login_Click(object sender, EventArgs e)
        {
            bool Testsuccessfullogin = false;
            if (Testsuccessfullogin)
            {
                //Your code after successfull login
            }
            else
            {
               //Invalid Login --- Capture Each login event based on IP
                string strIp;
                strIp = Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; //when user is behind proxy server
                if (strIp == null)
                {
                    strIp = Request.ServerVariables["REMOTE_ADDR"];//Without proxy
                }

                List<InvalidLogin> user = null;
                if (HttpContext.Current.Application["Users"] == null) //Adding List to Application State
                {
                    user = new List<InvalidLogin>();
                }
                else
                {
                    user = (List<InvalidLogin>)HttpContext.Current.Application["Users"];
                }
                var remove = user.RemoveAll(x => x.Attempttime < DateTime.Now.AddMinutes(-15));//Remove IP Before 15 minutes(Give 15 Min Time Next Login)
                var checkLogged = user.Find(x => x.IP == strIp);
                if (checkLogged == null)
                {
                    user.Add(new InvalidLogin
                    {
                        IP = strIp,
                        Attempttime = DateTime.Now,
                        AttemptCount = 1

                    });
                     Application.Lock();
                     HttpContext.Current.Application["Users"] = user;
                      Application.UnLock();
                }
                else
                {
                    if (checkLogged.AttemptCount < 4)
                    {
                        checkLogged.Attempttime = DateTime.Now;
                        checkLogged.AttemptCount++;
                        Application.Lock();
                        HttpContext.Current.Application["Users"] = user;
                        Application.UnLock();
                    }
                }



                if (checkLogged != null)
                {
                    if (checkLogged.AttemptCount > 3)
                    {
                        captcha.Visible = true;  //Showing captcha 
                    }
                }




            }
        }
3
Benjamin

独自の認証クラスと承認クラスを使用している場合は、各ユーザーのログイン試行の失敗回数とその日付と時刻をカウントする必要があります。

試行回数が制限に達した場合、「アカウントが15分間ブロックされました。しばらくしてからもう一度お試しください」などのエラーメッセージが表示され、次のログインプロセスが中断されます。

例えば。ログインのテーブルは[Logins]という名前です。

You need to add new colums:
1. [LastLoginAttemptAt] DATETIME NULL
2. [LoginFailedAttemptsCount] INT NOT NULL DEFAULT 0

したがって、クラスLoginには次の新しいフィールドがあります。

public class Login {
    public DateTime? LastLoginAttemptAt {get;set;}
    public int LoginFailedAttemptsCount {get;set;}
}

また、somewere構成変数(ログインに失敗した最大試行回数とブロック期間の値)を格納する必要があります。

const int MaxNumberOfFailedAttemptsToLogin = 10;
const int BlockMinutesAfterLimitFailedAttemptsToLogin = 15; // 15 min

SignInメソッドでは、次のことを行います(製品バージョンではなく、コードの基本的な例)。

public void SignIn(string username, string password)
{    
    var login = _userService.TryGetLogin(username);
    if (login == null){
        // Login by username not found.
        // Return error message "Invalid username or password"
        return;
    }

    if (login.LoginFailedAttemptsCount > MaxNumberOfFailedAttemptsToLogin
    && login.LastLoginAttemptAt.HasValue
    && DateTime.Now < login.LastLoginAttemptAt.Value.AddMinutes(BlockMinutesAfterLimitFailedAttemptsToLogin))
    {
        // Login is blocked, need to break the process.
        // Return error message "Your account was blocked 
        // for a 15 minutes, please try again later."
        return;
    } else {
        login.LoginFailedAttemptsCount = 0;
        login.LastLoginAttemptAt = DateTime.Now;
    }

    var success = login.ValidatePassword(password);
    if (!success)
    {
        // Invalid password, need to update the number of attempts.
        login.LastLoginAttemptAt = DateTime.Now; //or UTC
        login.LoginFailedAttemptsCount++;
        // Update(login);
        // Return error message "Invalid username or password"
        return;
    } else {
        login.LoginFailedAttemptsCount = 0;
        login.LastLoginAttemptAt = DateTime.Now;
        // Update(login);
        // Success!
    }
}
2
Yuriy A.

他の人がしていないことを付け加えたいのは、可能であれば、ボットが検出されたという事実をボットに警告したくないということだけです。あなたが何らかのメッセージで彼らをブロックすると、彼らは彼らが何をしたかを記録して調整するだけです。たとえば、IPで「通知」している場合は、入力しているパスワードが成功しないようにしてください。彼らはあなたがいくつかの複雑なパスワードなどを持っていると思い込んで、あなたがそれらに気づいたことを確信することなく他の場所に行きます。

また、「試行」をipを使用してデータベースに保存することをお勧めします。その後、簡単に戻って、サイトに対して行われた試行を確認できます。 Webログを照会することもできますが、それはもっと面倒です。また、成功したログインをログに記録して、ボットが戻ってきてさらに調査を適用したときに気付くことができるようにします。

0
Bruce Dunwiddie

これを行う場合、データベースの列を使用して、最初の試行のログイン試行番号と日付タイムスタンプを格納します。次に、ログインに関するロジックをいくつか用意します

 if(loginAttempt>5 && DateTime.Now<loginDate.AddMinute(5))
{
    //Locked out
}
0
Dzm2012

何度か失敗した後でアカウントを一時停止し、ユーザーにセキュリティの質問に答えて再度有効にすることができます。また、最後のいくつかのパスワードの再利用を許可しないでください。安全である必要があります。

コーディングでやりたい場合は、3回目のログイン試行時間_[MaxAttemptTime]_(_DateTime.Now_)とアカウントの解放時間_[ReleaseTime]_(たとえば20分後DateTime.Now.AddMinutes(20))。

これで、同じユーザーからログインが試行されるたびに、_[ReleaseTime]_に基づいてログインを拒否する必要があります。本物のユーザーが正常にログインしたら、これらのカウンターをリセットします。

0