Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Mutating Login

0.00/5 (No votes)
23 Nov 2011 5  
Login system with breach redundancy handling.

Introduction

I came up with the concept for this after watching Die Hard 4.0 where the White Hat hacker in the movie had written what he called a "mutating security algorithm". I thought that it might be useful to have a system that changes (or mutates) passwords if a login fails enough times that it might present a security risk. 

This login system is not like your conventional system. Classic login systems rely on a defined username and password combination to allow users access to private information. A lot of people don't often use sufficiently strong passwords when they register to be part of a community website or even when they set their login information on internet banking systems.

These passwords are normally things like birthdates or names that have meaning to the registrant. This is where the security risk comes in.
A plausible scenario would be a situation in which a woman signs up for facebook and sets her password as her daughter's full name. Friends of hers on facebook that  may be feeling "mischievous" might guess that her password has something to do with her daughter, and make attempts at guessing her login details.

In this situation, a classic login system would allow for an unlimited number of guesses during which the "attacker" might eventually  guess right and gain access.

This login system addresses such a situation and provides more security to the registered user.

Background

This system was written in Visual Basic.NET and uses a SQL Server database for storage of user information. Most user data is stored as plain text, with the exception of the user's password which is encrypted using SHA1.

Challenges during development were small issues around the encryption of the user's password as well as the tracking of login attempts through the use of a session variable which gets counted on each attempt. These issues were purely conceptual in nature and were resolved relatively quickly.

How It Works

Upon registration, a new user will be sent an email which will contain details about his/her account. These details include their user id, username, and password.
To log in, the user will have to enter their user id first to verify that they indeed do have an account on the system. Once the user id is verified, they will be asked to supply the username and password that is associated with the user id that they entered.

Where there are less than 3 login attempts on record for the current session, the login hashes and salts the value entered into the password field on the login form, and selects a record with user id, username, and password value that are identical to user input. If this selection doesn't return a single row from the database, the login was invalid and an attempt gets counted in the user's session.

Should there be 3 login attempts counted, the account is flagged as locked and, until such time as it is recovered by the user, will not be included in selection for future login attempts.
In addition, a 36 character long value is generated after the account gets locked. This value is then hashed and salted and stored in the database as the new password for the account.

Login.aspx.vb  

Imports System.Data
Imports System.Data.SqlClient

Public Class Login
    Inherits System.Web.UI.Page

    Private connstr As String = "Data Source=.\SQLEXPRESS; Initial Catalog=test; Integrated Security=True;"
    Private conn As SqlConnection = New SqlConnection(connstr)

    Public NewPass As String = Nothing
    Public HashedPass As String = Nothing
    Public UserId As Integer = Nothing

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        If Not IsPostBack Then
            pnlLoginForm.Visible = False
            Session("LoginAttempt") = 0
        End If

        If Session("LoginAttempt") = 2 Then
            ' This account may be vulnerable, generate a random string for the new password and lock the account
            Dim s As String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
            Dim r As New Random
            Dim sb As New StringBuilder
            Dim idx As Integer = Nothing
            For i As Integer = 1 To 8
                idx = r.Next(0, 61)
                NewPass += sb.Append(s.Substring(idx, 1)).ToString
            Next
            HashedPass = Crypt.Compute(NewPass, "SHA512", Nothing)
            Dim sql As String = "UPDATE Users SET Password = @Pass, LockedYN = @Lock"
            Dim cmd As New SqlCommand(sql, conn)
            cmd.Parameters.AddWithValue("@Pass", NewPass)
            cmd.Parameters.AddWithValue("@Lock", "Yes")

            conn.Open()
            cmd.ExecuteNonQuery()
            conn.Close()
        End If
    End Sub

	Private Sub btnVerifyID_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnVerifyID.Click
		If txtUserId.Text IsNot Nothing Then
			Dim UserData As New DataSet
			Dim UserAdapter As New SqlDataAdapter
			UserAdapter.SelectCommand = New SqlCommand("SELECT * FROM Users " & _
													   "WHERE UserId = @ID", conn)
			UserAdapter.SelectCommand.Parameters.AddWithValue("@ID", txtUserId.Text)
			UserAdapter.Fill(UserData)
			If UserData.Tables(0).Rows.Count <> 1 Then
				lblError.Text = "Specified User ID does not exist."
				lblError.ForeColor = Drawing.Color.Red
			Else
				If UserData.Tables(0).Rows(0)(4).ToString = "Yes" Then
					lblError.Text = "The account you tried to log into has been locked to prevent possible unauthorized access. " & _
					"If this is your account, please check your email for instructions to unlock it."
					lblError.ForeColor = Drawing.Color.Red
				Else
					UserId = txtUserId.Text
					pnlLoginForm.Visible = True
				End If
			End If
		End If
	End Sub

	Private Sub btnLogin_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnLogin.Click
		If txtUser.Text IsNot Nothing And txtPass.Text IsNot Nothing Then
			If Session("LoginAttempt") <> 2 Then
				Dim pass As String = Crypt.Compute(txtPass.Text, "SHA512", Encoding.UTF8.GetBytes(Crypt.SaltValue))

				Dim UserData As New DataSet
				Dim UserAdapter As New SqlDataAdapter
				UserAdapter.SelectCommand = _
					New SqlCommand("SELECT * FROM Users " & _
						"WHERE Username = @User AND Password = @Pass " & _
						"AND LockedYN = @Lock", conn)
				UserAdapter.SelectCommand.Parameters.AddWithValue("@User", txtUser.Text)
				UserAdapter.SelectCommand.Parameters.AddWithValue("@Pass", pass)
				UserAdapter.SelectCommand.Parameters.AddWithValue("@Lock", "No")
				UserAdapter.Fill(UserData)

				If UserData.Tables(0).Rows.Count <> 1 Then
					lblError.Text = "Invalid username or password."
					lblError.ForeColor = Drawing.Color.Red
					Session("LoginAttempt") = CInt(Session("LoginAttempt")) + 1
				Else
					Session("LoggedIn") = True
					Response.Redirect("Home.aspx")
				End If
			Else
				lblError.Text = "The account you tried to log into is now locked due to excessive failed login attempts. " & _
					"If this is your account, please check your email for instructions to unlock it."
				lblError.ForeColor = Drawing.Color.Red
			End If
		Else
			lblError.Text = "Please enter a username and password."
			lblError.ForeColor = Drawing.Color.Red
		End If
	End Sub
End Class 

What this release contains 

This release contains the basic security "measures". Due to challenges with free time, I haven't been able to add the code to process the emails yet. 

Currently included are:

  • Functions to handle SHA1 encryption of user passwords
  • General session management that keeps track of login attempts
  • Bare-bones user interface used while testing. This has not been cleaned up in this version. 

Plans for the future

I always like it when I can find software that works on multiple platforms, so I'll be working on a PHP version that uses mysql as a data backend.

To put any security worries to bed, the next version will include functionality to redirect users off of the login page if they are currently logged in to their account.

Probably the most crucial change in the works will be the modification of the user id from an integer field to a guid(). This will eliminate the possibility of user ids being guessed and make "spoofing" another user's account a lot more complicated. 

Using the code

Before you can use this system, you'll need to change the connection strings. Currently each file that works with the data source has one in it:

  • Create.aspx.vb 
  • Login.aspx.vb 

' This is what the connection string currently looks like:
Private connstr As String = "Data Source=.\SQLEXPRESS; Initial Catalog=test; Integrated Security=True;"

' The values for Initial Catalog and Data Source will need to be changed in order for the system to work correctly with your database. 

Only one table is needed for the system to function correctly. The table must include the following structure for the system to work correctly. 

Users Table:
UserID (PK, int, not null) -- identity(1,1)
Username (varchar(20), not null)
Password (varchar(36), not null)
EmailAddress (varchar(100), not null)
LockedYN (char(3), not null) -- default 'No'

Here's a CREATE sample to get you going: 

CREATE TABLE [dbo].[Users](
	[UserID] [int] IDENTITY(1,1) NOT NULL,
	[Username] [varchar](20) NOT NULL,
	[Password] [varchar](36) NOT NULL,
	[EmailAddress] [varchar](100) NOT NULL,
	[LockedYN] [char](3) NOT NULL,
 CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED 
(
	[UserID] ASC
)

 

Feel free to add more columns to your user table if you wish, but if you remove or change any of these, the system will break.  

Points of Interest   

Google is your friend. The encryption was particularly challenging for me to make work. I found a number of samples that I worked through and based my code (Crypt.aspx.vb) on. 

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here