The user would typically enter a user name and password, and the web application fetches the database row that coincides with the user name entered in the form textbox control. A program method compares the password entered against the password stored in the database. If a match is made, the web application method returns a Boolean true, and the IIS server sends the browser an authorized HTML page for viewing or altering sensitive information.
Perhaps the worst method that a novice programmer creates for the login click event in the above form code-behind file is a concatenated SQL string that allows the hacker to inject malicious code into the user name textbox.
private void btnSubmitLogin_Click(object sender, System.EventArgs e)
{
string strConnection = "server=localhost;database=northwind;uid=sa;pwd=;";
SqlConnection connection = new SqlConnection(strConnection);
connection.Open();
string strSQL = "SELECT * FROM Users WHERE UserName='" + txtUserName.Text + "' AND Password='" + txtPassword.Text + "'";
int intReturnRowCount;
SqlCommand cmdSQL = new SqlCommand(strSQL, connection);
intReturnRowCount = (int) cmdSQL.ExecuteScalar();
if (intReturnRowCount > 0)
{
Server.Transfer("SensitivePage.aspx");
}
else
{
lblMessage.Text = "Login incorrect. Please try again.";
}
connection.Close();
}
Instead of entering the user name and password as above, the hacker enters OR 1 = 1--‘. The SQL string that goes to the database stored procedure compiler in this case is:
SELECT * FROM UserTable WHERE UserName = ‘’ OR 1 = 1 -- AND Password = ‘’
The database engine executes the malicious concatenated string, and ignores the “AND Password = ‘’ “ since it has become a SQL comment. The “UserName = ‘’ “ is an invalid expression in the WHERE clause, but the “OR 1 = 1” portion evaluates to a Boolean true. The resultset returned from the “SELECT * “ SQL query includes all the rows from the Users table because of the true condition in the WHERE clause.
The moral is: do not use imbedded and dynamically-built SQL strings for login; instead, use stored procedures approved by a DBA. Furthermore, the application login logic should count the number of tries that an intruder attempts to enter a password, and lock the intruder out after a certain number of tries with that user name.
Another good programming login technique is to validate the login strings at the HTML page level and in a business logic layer against a regular expression that also removes any unwanted password characters without notifying the user. The code to check for bad characters against a regular expression could be:
public static string CleanStringRegex(string inputText)
{
//*********************************************************************
//
///
/// Validates the input text using a Regular Expression and replaces any input expression
/// characters with empty string.Removes any characters not in [a-z A-Z 0-9_].
///
///
The text to validate.
///
Sanitized string
//
//*********************************************************************
if (inputText != null && inputText.Length != 0)
{
RegexOptions options = RegexOptions.IgnoreCase;
return AppBase.BLL.ReplaceRegex(inputText, @"[^\\.!?""',\-\w\s@]", options);
}
else
{
throw new ArgumentException("Parameter may not be null or empty.");
}
}
Instead of entering the user name and password as above, the hacker enters OR 1 = 1--‘. The SQL string that goes to the database stored procedure compiler in this case is:
SELECT * FROM UserTable WHERE UserName = ‘’ OR 1 = 1 -- AND Password = ‘’
The database engine executes the malicious concatenated string, and ignores the “AND Password = ‘’ “ since it has become a SQL comment. The “UserName = ‘’ “ is an invalid expression in the WHERE clause, but the “OR 1 = 1” portion evaluates to a Boolean true. The resultset returned from the “SELECT * “ SQL query includes all the rows from the Users table because of the true condition in the WHERE clause.
The moral is: do not use imbedded and dynamically-built SQL strings for login; instead, use stored procedures approved by a DBA. Furthermore, the application login logic should count the number of tries that an intruder attempts to enter a password, and lock the intruder out after a certain number of tries with that user name.
Another good programming login technique is to validate the login strings at the HTML page level and in a business logic layer against a regular expression that also removes any unwanted password characters without notifying the user. The code to check for bad characters against a regular expression could be: