ASP.NET WebForms FormsAuthentication problem with cross-domain iFrames - asp.net

Well, I have 2 ASP.NET WebForm websites, running on production on the same windows server machine, let's call them site A and site B. There are some pages in website A in which there is an iFrame, pointing to website B. I want my users to be authenticated on site B when they browse site B through site A (through iFrames). In order to do that, the source of my iFrame on my site A is like that :
B.com/index.aspx?guid={aGuid}&pageIWant={pageIWant}
So, I will not go into details there because it works and it is not the problem, but how it works basically is that in the Page_Load of index.aspx.vb of my site B, I get the guid in the querystrings representing a user, I get this user from database, I log this user using forms authentication and then I redirect the user to the "pageIWant", another querystrings parameter. So, here is what I do in the page_load, basically :
/*Get the guid*/
Dim user = /*get user from guid*/
/*some checks*/
FormsAuthentication.SetAuthCookie(user.Login, True)
Select Case Request.QueryString("pageIWant")
Case "1"
Response.Redirect("documents.aspx")
Case "2"
/*etc*/
End Select
The index.aspx page of site B does not require authentication, but the page "documents.aspx" does. Hopefully, I did authenticate my user in the page load of index.aspx, so I go through Application_AuthenticateRequest in the Global.asax.vb and everything is fine, my user can access the page. Here is the code in my Application_AuthenticateRequest method :
Sub Application_AuthenticateRequest(ByVal sender As Object, ByVal e As EventArgs)
If Request.IsAuthenticated Then
If Request.Cookies("ESERVICES_LOGIN") IsNot Nothing Then
Dim aTicket As FormsAuthenticationTicket = FormsAuthentication.Decrypt(Request.Cookies("ESERVICES_LOGIN").Value)
HttpContext.Current.User = New GenericPrincipal(New GenericIdentity(aTicket.Name), aTicket.UserData.Split(","c))
Else
FormsAuthentication.SignOut()
HttpContext.Current.User = New GenericPrincipal(New GenericIdentity(String.Empty, String.Empty), New String() {})
Response.Clear()
End If
End If
End Sub
In this case, when I redirect to the page "documents.aspx", the Request.IsAuthenticated is set to true because I previously called FormsAuthentication.SetAuthCookie(user.Login, True)
Here is the problem : since I installed on my windows server machine (hosting the websites) the two following KBs :
https://support.microsoft.com/en-us/help/4534978/kb4534978
https://support.microsoft.com/en-us/help/4535104/kb4535104
Request.IsAuthenticated is still false when I redirect to "documents.aspx" page, despite the fact that I call FormsAuthentication.SetAuthCookie before... and no exception is thrown ! My user is not logged in anymore.
I uninstalled the two KB and the problem is not occuring anymore, so I am sure there is something with one of those two KBs that causes my problem.
Something really strange is that when I try to reproduce the problem in localhost, I do not face the problem at all -> the problem seems to happen only when website A and website B do not have the same domain name. I've made multiple tests about this hypothesis and it seems to be true.
So, there is something wrong with the framework (or how I use it), and because of that, FormsAuthentication does not work properly through iFrame, when the iFrame source does not have the same domain name as the iFrame container, and when those two KBs are installed on the windows server machine hosting the website. That is silly and I cannot find the problem when debugging.
Please note that in both case, wheter authentication works or not, my auth cookie is created successfully...
Would someone have any idea about what's happening there? Do not hesitate to ask any questions if my problem is not clear.
Regards

I found an explanation.
Since 2019, Microsoft is releasing KBs that changes the default value of the "SameSite" attribute for the cookies. Before, when creating an auth cookie with FormsAuthentication.SetAuthCookie, the SameSite attribute was not specified, and in most browsers, the default value for it was "none" and it worked just fine. (this is not the case with Chrome anymore since february 2020, the default value became "lax").
Now, with the KBs I mentionned, the default value became "Strict", that's why my authentication doesn't work anymore in my case.
So, I'll have to specify the samesite attribute of my auth cookie to "None" manually if possible, and think about the security issues I could have with that. As a last resort, I could also just use the same domain name for my two websites.

Related

Allow folder access only to admin user

I'm new to ASPX and VB.NET and i'm trying to create two different content for two kinds of users.
Actually all pages for a normal user are ready and now i'm trying to make the Admin part i've created a folder Administrator in which there is a index.aspx that only user that logged and have as role in the database "ADMIN" should access it.
The loggin part is done as the following:
Protected Sub loginBtn_Click(sender As Object, e As EventArgs)
If UserExists(username.Value, password.Value) Then
FormsAuthentication.SetAuthCookie(username.Value, False)
If username.Value = "gab" Then
Page.Response.Redirect("\Administrator\Index.aspx", True)
Else
Page.Response.Redirect("Default.aspx", True)
End If
Else
username.Value = ""
ClientScript.RegisterStartupScript(Me.[GetType](), "alert", "openModal();", True)
End If
End Sub
For now i just check if the username is "gab" but lately i'd a function that SELECT the role from the database.
The issue is that if a normal user log and in the path just write \Administrator\index.aspx he can access that folder and even if an administrator change path to "Default.aspx" he can access content of a normal user
I would do that a normal user could see just his aspx pages and the admin just pages in Administrator folder but i need some suggestions on how to do it.
There are a number of ways you can do it, including many not listed here.
You may consider checking the permissions of each user on page load and redirecting them when necessary. This does add mean that you are hitting the database again on each page load, so you'll need to take that into consideration.
You may also try using client side storage, like a cookie, and running the checks client side. You'll want to be careful with what you store on the client side as it may open up security vulnerabilities.
If I knew more about your project, I may be able to give you more specifics.

Redirecting User to home page when not logged in and trying to access a certain web page vb.net

Ok so far i have working the ability to log in and access a certain web page ('bookrepair.aspx') through the use of roles and permissions. I used this to then deny any non-logged on users which works however it throws me up the "Server in '/' Application error". However i would like it to redirect the user to the home page ('home.aspx') and display a message to them saying "Only logged in users can access Book Repair"
So for i have this piece of code in my 'bookrepair.aspx' page
Private Sub Pages_BookRepair_Load(sender As Object, e As EventArgs) Handles Me.Load
If Not Me.Page.User.Identity.IsAuthenticated Then
Response.Redirect("Home.aspx")
MsgBox("Only logged in user's can access Book Repair")
End If
End Sub
However i still get the "Server in '/' Application error when trying to access it not logged in.
Any ideas?
I don't use the User.Identity functionality just because of all the issues you have to address in order to authenticate users. I make it simple and set a flag in either the Session or ViewState object which would indicated whether or not the user is logged on. For example:
If Session("LoggedOn") = "NO" Then
Response.Redirest("MainPage.aspx", False) 'False to indicate that the rest of the code in the procedure is not to be executed.
End IF
It's what works best for me, I have total control over it, do not have to worry that the browser supports it because Session is maintained on the server. I've never had an issue with it.

Classic ASP dumping Session Variables (WITHOUT Authentication)

I have inherited an Classic ASP Site and a "bolt-on" ASP.NET site...
NEITHER are using Authentication, BOTH sides have a manual "reinvent-the- wheel" (hard-coded) security system that validates the user/pw from a SQL 2000 database (i.e. "if the user is found via a SQL SELECT, let them in").
New development is in ASP.NET... and they have "integrated" the two sites via ONE login (described above) on the Classic ASP side... then passing a GUID (saved at the time of login to the users record) they validate the GUID on the ASP.NET side ("yes, this is the correct GUID, therefore this is my user... let them in").
Up until now this has been working ONE DIRECTION (Classic ASP to ASP.NET) only with no issues.
(Getting to the problem, bear with me...)
Now they want to perform the same basic design from ASP.NET to Classic ASP by updating the GUID, passing it back, where the lookup validates the user, send them to the correct Classic ASP page... (so the user can return to the Classic ASP side without re-loging-in, previously required) HOWEVER...
***HERE's THE PROBLEM
Session("UserID") is used on the Classic ASP side to (hard code) validate the user... then Response.Redirect is run to send them back to the page that they previously left via "sRedirectToString" ...
'user is found in DB, so send them to the correct page...
Dim sRedirectToString = 'the correct url
Call Response.Redirect (sRedirectToString)
HOWEVER, Session("UserID") gets cleared by IIS or IE (dun'no) and the (hard-coded) validation fails because Session("UserID") is NULL (blank)
Here's the simple (only) validation:
If Trim(Session("UserID") & "") = "" Then
'Session timed out
Response.Redirect('the denied page)
Else
Response.Write "<meta http-equiv=""X-UA-Compatible"" content=""IE=EmulateIE7"">"
End If
So, why are the Session Variables being cleared by a Redirect? (there is no other system authentication is being used).
There is no Session.Abort, nor any specific coding that is clearing Session("UserID").
But when Session("UserID") is tested (see code above) it is found empty and redirects to the DENIED.asp page.
So, hoping there is some property like "PersistSessionVariables" (or something) that I can set so they don't clear...
BUT THEY DO INDEED CLEAR IMMEDIATELY AFTER THE REDIRECT AND THIS IS CONFUSING TO ME.
I appreciate all the Wizards help!

Cookies NULL On Some ASP.NET Pages (even though it IS there!)

I'm working on an ASP.NET application and I'm having difficulty in understanding why a cookie appears to be null.
On one page (results.aspx) I create a cookie, adding entries every time the user clicks a checkbox. When the user clicks a button, they're taken to another page (graph.aspx) where the contents of that cookie is read.
The problem is that the cookie doesn't seem to exist on graph.aspx. The following code returns null:
Request.Cookies["MyCookie"];
The weird thing is this is only an issue on our staging server. This app is deployed to a production server and it's fine. It also works perfectly locally.
I've put debug code on both pages:
StringBuilder sb = new StringBuilder();
foreach (string cookie in Request.Cookies.AllKeys)
{
sb.Append(cookie.ToString() + "<br />");
}
this.divDebugOutput.InnerHtml = sb.ToString();
On results.aspx (where there are no problems), I can see the cookies are:
MyCookie
__utma
__utmb
__utmz
_csoot
_csuid ASP.NET_SessionId
__utmc
On graph.aspx, you can see there is no 'MyCookie'
__utma
__utmb
__utmz
_csoot
_csuid ASP.NET_SessionId
__utmc
With that said, if I take a look with my FireCookie, I can see that the same cookie does in fact exist on BOTH pages! WTF?!?!?!?! (ok, rant over :-) )
Has anyone seen something like this before? Why would ASP.NET claim that a cookie is null on one page, and not null on another?
This was happening because I was running the app under a different virtual directory. When I ran it on the original one, it worked.
I would suggest loading the IIS debug diagnostics tools. It is entirely possible that on that particular server there is a resource problem or unhandled exception that is killing that particular cookie AFTER it is added to the response but before it is flushed to the user. This is basically caused by a series of exceptions that occur in rapid succession causing rapid fail protection to shut down the w3wp.exe process that your page is running under. When the process is spooled back up to feed the response, the cookie is gone and all that goes out is the rendered html.
You might also try turning off rapid fail protection or altering memory settings/recycling settings on the application pool.

Logoff button IIS6 ASP.NET Basic Authentication

I have a requirement for an explicit logout button for users in a ASP.NET web app. I am using IIS6 with Basic Authentication (SSL). I can redirect to another web page but the browser keeps the session alive. I have googled around and found a way to do it by enabling an active x control to communicate with IIS and kill the session. I am in a restricted environment that does not allow forms authentication and active x controls are not forbidden as well. Has anyone else had this requirement and how have you handled it?
Okay that is what I was afraid of. I have seen similar answers on the net and I was hoping someone would have a way of doing it. Thanks for your time though. I guess I can use javascript to prevent the back button like the history.back()
I was struggling with this myself for a few days.
Using the IE specific 'document.execCommand('ClearAuthenticationCache');' is not for everyone a good option:
1) it flushes all credentials, meaning that the user will for example also get logged out from his gmail or any other website where he's currently authenticated
2) it's IE only ;)
I tried using Session.Abandon() and then redirecting to my Default.aspx. This alone is not sufficient.
You need to explicitly tell the browser that the request which was made is not authorized. You can do this by using something like:
response.StatusCode = 401;
response.Status = "401 Unauthorized";
response.AddHeader("WWW-Authenticate", "BASIC Realm=my application name");
resp.End();
This will result in the following: the user clicks the logout button ==> he will get the basic login window. HOWEVER: if he presses escape (the login dialog disappears) and hits refresh, the browser automagically sends the credentials again, causing the user to get logged in, although he might think he's logged out.
The trick to solve this is to always spit out a unique 'realm'. Then the browser does NOT resend the credentials in the case described above. I chose to spit out the current date and time.
response.StatusCode = 401;
response.Status = "401 Unauthorized";
string realm = "my application name";
response.AddHeader("WWW-Authenticate", string.Format(#"BASIC Realm={0} ({1})", realm, DateTimeUtils.ConvertToUIDateTime(DateTime.Now)));
resp.End();
Another thing that you need to do is tell the browser not to cache the page:
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetExpires(DateTime.MinValue);
Response.Cache.SetNoStore();
With all these things in place it works (for me) in IE, but until now I still wasn't able to prevent firefox from logging in the user when the user first presses escape (hides the basic login dialog) and then refresh (F5) or the browsers back button.
The Session.Abandon method destroys all the objects stored in a Session object and releases their resources. If you do not call the Abandon method explicitly, the server destroys these objects when the session times out.
Have you tried calling Session.Abandon in response to the button click?
Edit:
It would seem this is a classic back button issue.
There is very little you can do about the back button. Imagine the user has just opened the current page in a new window then clicked the logOut button, that page appears to log out but it will not immediately affect the content of the other window.
Only when they attempt to navigate somewhere in that window will it become apparent that their session is gone.
Many browsers implement the back button in a similar (although not identical) way. Going back to the previous page is not necessarily a navigation for a HTML/HTTP point of view.
This is a solution for this problem that works in IE6 and higher.
<asp:LinkButton ID="LinkButton1" runat="server" OnClientClick="logout();">LinkButton</asp:LinkButton>
<script>
function logout()
{
document.execCommand("ClearAuthenticationCache",false);
}
</script>
Found this from
http://msdn.microsoft.com/en-us/library/bb250510%28VS.85%29.aspx
Web Team in Short
Your Credentials, Please
Q: Jerry B. writes, "After the user has validated and processed his request, I now want to invalidate him. Assuming this machine is in an open environment where anyone could walk up and us it, I want to throw a new challenge each time a user accesses a particular module on the Web."
A: This is a frequently requested feature of the Internet Explorer team and the good people over there have given us a way to do it in Internet Explorer 6.0 SP1. All you need to do is call the execCommand method on the document, passing in ClearAuthenticationCache as the command parameter, like this:
document.execCommand("ClearAuthenticationCache");
This command flushes all credentials in the cache, such that if the user requests a resource that needs authentication, the prompt for authentication occurs again.
I put this on my logout link button and it works in IE6 sp1 and higher:
OnClientClick="document.execCommand('ClearAuthenticationCache');"

Resources