We have recently been challenged to update a web application, we needed to do a security improvement on certain pages to prevent them from being opened on multiple tabs. The application would need to allow the user to open a new tab and the first tab that was opened to show an invalid access message.
The outcome would be that a user can have a page opened only in one tab of a browser. I will refer in this post only to this problem, in the next post will discuss about multiple log-ins in different browser security issue. So after applying both solutions that I found, you would have an application that prevents certain pages to be opened in multiple tabs, and prevents multiple log-ins on different locations and browsers. So let begin :), with preventing multiple tabs.
My solution uses a combination of Session, ViewState and hidden fields. In the example I will use a SessionHandler class that manages all my sessions. Here is the SessionHandler class with the method we will us. Instead of this class you can use
Session["validInstanceGuid"]
but it is not so elegant and can introduce errors because is not strongly typed.
public static class SessionHandler
{
const string validInstanceGuid = "validInstanceGuid";
public static string ValidInstanceGuid
{
get
{
if (HttpContext.Current.Session[validInstanceGuid] == null)
{ return string.Empty; }
else
{ return HttpContext.Current.Session[validInstanceGuid].ToString(); }
}
set { HttpContext.Current.Session[validInstanceGuid] = value; }
}
}
So basically
SessionHandler.ValidInstanceGuid
will store a unique guid to identify the valid instance of the tab. I. Now lets say that you have a page Default.aspx and this page opens SingleTab.aspx page. What we have to do is set the unique guid on Default.aspx page like this
1. On Default.aspx add a hidden field.
2. On Default.aspx.cs create the method GenerateUniqueTabGuid().
public string GenerateUniqueTabGuid()
{
SessionHandler.ValidInstanceGuid= Guid.NewGuid().ToString().Replace("-", "");
return SessionHandler.ValidInstanceGuid;
}
3. On Default.aspx.cs on Page_Load call the GenerateUniqueTabGuid() and place the guid in the hidden field created in step 1.
if (!Page.IsPostBack) {
hfldUniqueTabGuid.Value = GenerateUniqueTabGuid();
}
II. On SingleTab.aspx page that will be available only in one tab. We have to read the guid and store it in ViewState, and then on each request to compare the ViewState value with the Session value.
1. In Page_Load of SingleTab.aspx page we will store the guid in ViewState. The client ID of the hidden field in my case is ctl00$MainContent$hfldUniqueTabGuid but may be different depending on how you structure the MasterPage or if you use one or not.
if (!IsPostBack)
{
foreach (string fieldName in Request.Form)
{
if (fieldName == "ctl00$MainContent$hfldUniqueTabGuid")
{
ViewState["validInstanceGuid"] = Request.Form["ctl00$MainContent$hfldUniqueTabGuid"].ToString();
}
}
}
2. We have to do one more thing in Page_Load of SingleTab.aspx to compare the ViewState with the Session. If they don't match then I redirect to InvalidAccess.aspx page. You can do whatever you choose here
if (ViewState["validInstanceGuid"].ToString() != SessionHandler.ValidInstanceGuid)
{
Response.Redirect("InvalidAccess.aspx");
}
III. We are done you now have restricted access to the current tab. User can go to parent page Default.aspx and navigate to SingleTab.aspx. Apperantly the SingleTab.aspx is opened in two tabs. But when the user makes an action on the first tab he will be redirected to InvalidAccess.aspx page on the next action.
IV. If you want you can automatically display InvalidAccess.aspx if you use a timer(I recommend using ajax request to a page that gives a json response) and that verifies ViewState and Session every let say... 15 seconds. And if the two are not equal then redirect to InvalidAccess.aspx. Multiple log-ins will be discussed in an upcoming post.