Thursday, April 8, 2010

Brute force protect your website



<head runat="server">
    <title></title>
    <style type="text/css">
        .table
        {
            background-image: url('Images/buttonbg.png');
            background-repeat: repeat;
        }
        .buttonBg
        {
            background-color: Silver;
            background-image: none;
            border-style: solid;
            border-width: 1;
            border-color: #c63 #930 #930 #c63;
        }
        .textbox_username
        {
            background: #ffffff url('images/icon_username.png') no-repeat;
            background-position: 1 1;
            padding-left: 19px;
            border: 1px solid #999999;
            border-top-color: #CCCCCC;
            border-left-color: #CCCCCC;
            color: #333333;
            font: 90% Verdana, Helvetica, Arial, sans-serif;
            font-size: 12px;
            height: 20px;
        }
        .textbox_password
        {
            background: #ffffff url('images/icon_password.png') no-repeat;
            background-position: 1 1;
            padding-left: 19px;
            border: 1px solid #999999;
            border-top-color: #CCCCCC;
            border-left-color: #CCCCCC;
            color: #333333;
            font: 90% Verdana, Helvetica, Arial, sans-serif;
            font-size: 12px;
            height: 20px;
        }
        .button
        {
            border: 1px solid #999999;
            border-top-color: #CCCCCC;
            border-left-color: #CCCCCC;
            background-color: white;
            color: #333333;
            font: 90% Verdana, Helvetica, Arial, sans-serif;
            font-size: 11px;
            -moz-border-radius: 3px;
        }
    </style>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <table class="table">
            <tr>
                <td colspan="4">
                    <asp:Label ID="lblUserLogOn" runat="server" Text="User Log On" Style="font-size: smaller;
                        font-family: Verdana; font-weight: bolder;"></asp:Label>
                </td>
            </tr>
            <tr>
                <td rowspan="3">
                    <img src="Images/Security.PNG" style="width: 80px; height: 80px;" alt="" />
                </td>
                <td>
                    <asp:Label ID="lblUserName" runat="server" Text="User Name" Style="font-size: x-small;
                        font-family: Verdana; font-weight: bold;"></asp:Label>
                </td>
                <td>
                    <asp:TextBox ID="txtUserName" runat="server" CssClass="textbox_username" TabIndex = "1" ></asp:TextBox>
                </td>
            </tr>
            <tr>
                <td>
                    <asp:Label ID="lblPassword" runat="server" Text="Password" Style="font-size: x-small;
                        font-family: Verdana; font-weight: bold;"></asp:Label>
                </td>
                <td>
                    <asp:TextBox ID="txtPassword" runat="server" CssClass="textbox_password" TabIndex = "2"></asp:TextBox>
                </td>
            </tr>
            <tr>
                <td colspan="2" style="text-align:right; padding-right:2px;">
                    <asp:Button ID="btnLogOn" runat="server" Text="LogOn" CssClass="buttonBg" 
                        TabIndex = "3" onclick="btnLogOn_Click"/>
                </td>
            </tr>
            <tr>
            <td colspan="3" style="text-align:right; padding-right:2px;">
                <asp:Label ID="lblInvalid" runat="server" Text="Incorrect username or password." style="color:#FF0000;"></asp:Label>
            </td>
            </tr>
        </table>
    </div>
    
    </form>
</body>
</html>

public partial class SimpleLoginTemplate_LogOn : System.Web.UI.Page
{

    protected void Page_Load(object sender, EventArgs e)
    {
        //ClearLogonCounter();

        switch (btnLogOn.Enabled)
        {
            case false:
                break;
            case true:
                btnLogOn.Enabled = NumberOfLogonAttemps() <= 5 ? true : false;
                break;
        }
    }

    protected void btnLogOn_Click(object sender, EventArgs e)
    {
        AddOrCountLogonAttempt();

        if (NumberOfLogonAttemps() > 5)
        {
            if (!lblInvalid.Text.Trim().Equals("User has been locked for 5 minutes."))
                //If the attempt is > 5 Lock the user for 5 min
                //After that the userName cleared from the cache
                Cache.Insert(txtUserName.Text.Trim(), (int)Cache[txtUserName.Text.Trim()], null, DateTime.Now.AddMinutes(5), TimeSpan.Zero);

            lblInvalid.Text = "User has been locked for 5 minutes.";
            btnLogOn.Enabled = false;
        }
        else
        {
            btnLogOn.Enabled = true;
            switch (LogOn())
            {
                //Clear the count if user logon correctly
                case true:
                    ClearLogonCounter();
                    break;
                case false:
                    break;
            }
        }
    }

    private bool LogOn()
    {
        lblInvalid.Text = "Incorrect username or password.";
        return false;
    }

    #region "Brute force protect"
    //http://madskristensen.net/post/Brute-force-protect-your-website.aspx
    private int NumberOfLogonAttemps()
    {
        if (Cache[txtUserName.Text.Trim()] == null)
           return 0;
        //txtNoOfTries.Text = Convert.ToString( Cache[txtUserName.Text.Trim()]);
        return (int)Cache[txtUserName.Text.Trim()];
    }

    private void ClearLogonCounter()
    {
        if (Cache[txtUserName.Text.Trim()] != null)
        {
            Cache.Remove(txtUserName.Text.Trim());
        }
    }

    private void AddOrCountLogonAttempt()
    {
        if (Cache[txtUserName.Text.Trim()] == null)
        {
            //NoAbsoluteExpiration -- item should never expire
            // Sliding expiration means we reset the X seconds after each request.
            //http://wiki.asp.net/page.aspx/655/caching-in-aspnet/

            Cache.Insert(txtUserName.Text.Trim(), 1, null, System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(1));
        }
        else
        {
            int tries = (int)Cache[txtUserName.Text.Trim()];
            Cache[txtUserName.Text.Trim()] = tries + 1;
        }
    }

    #endregion
}

Reference:madskristensen.net
All credits goes to him.

No comments: