This article is an extension to my previous articles:
- Generation of CAPTCHA Image Using Generic Handler for Login Page
- Stored Procedure For Login Page and Custom Error Handling
1. Filtering from login page
If the filtering of the XSS attack occurred from the login page then:
- Cross-site scripting (XSS): Cross-site scripting is nothing but injection of client-side scripts into a website. These scripts can be HTML scripts or JavaScript scripts. Cross-site scripting can be performed by passing scripts in the form of a TextBox (input controls), query strings, cookies, session variables and application variables.
- Anti XSS remedy: the HtmlEncode function located in the Microsoft's AntiCross-Site Scripting Library. In contrast with the Server.HtmlEncode and HttpUtility.HtmlEncode functions, the later function takes a more aggressive approach by using a white-list filtering instead of a black-list, hence more PCI standards-compliant and more secure.
- Using FilteredTextBox Extender: Using this extender the user is restricted to enter valid data as input and the chances of injecting a client script or database related script is diminished.
Input controls should have a filtertextbox extender as below.
- <asp:TextBox ID="txtLogin" runat="server" Width="175px" MaxLength="20" AutoCompleteType="Disabled"></asp:TextBox>
- <asp:FilteredTextBoxExtender ID="fltr_txtLogin" runat="server" FilterType="UppercaseLetters,LowercaseLetters,Numbers" TargetControlID="txtLogin">
- </asp:FilteredTextBoxExtender>
-
- <asp:TextBox ID="txtPassword" runat="server" Width="175px" MaxLength="20" AutoCompleteType="Disabled" TextMode="Password"></asp:TextBox>
- <asp:FilteredTextBoxExtender ID="fltr_txtPassword" runat="server" FilterType="Numbers, LowercaseLetters, UppercaseLetters, Custom" TargetControlID="txtPassword" ValidChars="@!_%$#"></asp:FilteredTextBoxExtender>
-
- <asp:TextBox ID="txtCode" runat="server" Width="175px" MaxLength="5" AutoCompleteType="Disabled"></asp:TextBox>
- <asp:FilteredTextBoxExtender ID="fltr_txtCode" runat="server" FilterType="Numbers"
- TargetControlID="txtCode"></asp:FilteredTextBoxExtender>
2. Alert user if other session is active on another machine for requested credentials.
And
3. Having single session per user means at a time only one session will be active for each user.
If someone has logged in from another machine using the same credentials then the user must be alerted about another active session on the credentials provided.
To maintain a single session, we have already added two columns in UserMaster. The IsLogin flag maintains a user's Login Status and UserSession column maintains a unique session id. If the user selects the OK button then a new session id is updated against the user details in UserMaster else returned to the login page.
Modified Login page aspx script
Login.aspx.cs Code behind
- #region " [ using ] "
- using System;
- using System.Configuration;
- using System.Data;
- using System.Data.SqlClient;
- using System.Web.UI;
- #endregion
-
- public partial class Login : System.Web.UI.Page
- {
- protected void Page_Load(object sender, EventArgs e)
- {
- if (!Page.IsPostBack)
- {
- UpdateCaptchaText();
- }
- }
-
- #region " [ Button Event ] "
- protected void btnRefresh_Click(object sender, ImageClickEventArgs e)
- {
- UpdateCaptchaText();
- }
-
-
- protected void btnLogin_Click(object sender, EventArgs e)
- {
- if (!string.Equals(txtCode.Text.Trim(), (string)Session["Captcha"]))
- {
- lblError.Text = "Enter correct code.";
- return;
- }
-
- lblError.Text = string.Empty;
- DataTable dtUser = new DataTable();
- string userSession = Guid.NewGuid().ToString();
- Session["UserSession"] = userSession;
- try
- {
- dtUser = checkUserLogin(userSession, "LOGIN");
-
- if (dtUser != null)
- {
- if (dtUser.Columns.Contains("RES"))
- {
- lblError.Text = dtUser.Rows[0][0].ToString();
- ClearPage();
- }
- else
- {
- Session["UserID"] = dtUser.Rows[0]["UserID"];
- Session["UserName"] = dtUser.Rows[0]["UserName"];
- Session["LastLogin"] = dtUser.Rows[0]["LastLogin"];
-
- if (string.Equals(dtUser.Rows[0]["IsLogin"].ToString(), "True"))
- {
- tblAlert.Visible = true;
- tblLogin.Visible = false;
- }
- else
- {
- Response.Redirect("~/Welcome.aspx");
- }
- }
- }
- else
- {
- ClearPage();
- lblError.Text = "Unexpected error.";
- }
- }
- catch
- {
- throw;
- }
- finally
- {
- dtUser.Dispose();
- }
- }
-
- protected void btnOk_Click(object sender, EventArgs e)
- {
- checkUserLogin(Session["UserSession"].ToString(), "CHANGELOGIN");
- Response.Redirect("~/Welcome.aspx");
- }
-
- protected void btnCancel_Click(object sender, EventArgs e)
- {
- Response.Redirect("~/login.aspx");
- }
- #endregion
-
- #region " [ Private Function ] "
- private DataTable checkUserLogin(string userSession, string mode)
- {
- DataSet dsData = new DataSet();
- SqlConnection sqlCon = null;
- SqlDataAdapter sqlCmd = null;
-
- try
- {
- using (sqlCon = new SqlConnection(ConfigurationManager.ConnectionStrings["connectionString"].ConnectionString))
- {
- sqlCmd = new SqlDataAdapter("USP_UserLogin", sqlCon);
- sqlCmd.SelectCommand.CommandType = CommandType.StoredProcedure;
- sqlCmd.SelectCommand.Parameters.AddWithValue("@loginID", txtLogin.Text.Trim());
- sqlCmd.SelectCommand.Parameters.AddWithValue("@password", txtPassword.Text.Trim());
- sqlCmd.SelectCommand.Parameters.AddWithValue("@sessionID", userSession);
- sqlCmd.SelectCommand.Parameters.AddWithValue("@mode", mode);
-
- sqlCon.Open();
- sqlCmd.Fill(dsData);
-
- sqlCon.Close();
- }
- }
- catch
- {
- throw;
- }
- return dsData.Tables[0];
- }
-
- private void ClearPage()
- {
- txtCode.Text = string.Empty;
- txtPassword.Text = string.Empty;
- txtCode.Text = string.Empty;
- UpdateCaptchaText();
- }
-
- private void UpdateCaptchaText()
- {
- txtCode.Text = string.Empty;
- Random randNum = new Random();
-
-
- Session["Captcha"] = randNum.Next(10000, 99999).ToString();
- imgCaptcha.ImageUrl = "~/ghCaptcha.ashx?" + Session["Captcha"];
- }
- #endregion
- }
Expected result
1. If the user has logged into the application and then if the same credentials are used for the login on another machine then the user will receive an alert that another session is active, do you want to terminate it.
2. If the OK button is clicked then a new session is updated in usermaster table otherwise the page is refreshed.
Also on the home.aspx page it is required to check that the sessionID stored in the database and the sessionID received from the current user are the same. This ensures that only one session is active per user.
The following is the Page Load event of the Home.aspx page.
- protected void Page_Load(object sender, EventArgs e)
- {
- if (!Page.IsPostBack)
- {
- BindUserData();
- if (!CheckUserSession())
- {
- Response.Redirect("~/login.aspx");
- }
- }
- }