Logoff button IIS6 ASP.NET Basic Authentication - asp.net

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');"

Related

Security considerations for an ASP.Net web application that will be used on a public computer or kiosk

I have an application that can be used without authentication on computers in public locations. It's a simple four page application that allows users to apply for a marriage license. Some offices will have a public computer kiosk where applicants can fill out their own information before proceeding to the clerk. They can also do so at home before visiting the office. What considerations should I take to make sure that a user cannot get access to the previous user's input? Some form data will contain sensitive info such as DOB, SSN and Mother's Maiden Name.
1. Disable AutoComplete
So far, I've set autocomplete=false in my Master page form tag.
<form id="frmMain" runat="server" autocomplete="false">
2. Disable Page Caching
I've also been able to disable page caching in IE and FF, but cannot do so in Safari and Chrome. Anybody know the trick? Hitting the back button still shows the form-filled data in Safari and Chrome.
// Disables page-caching in IE
Response.Cache.SetAllowResponseInBrowserHistory(false);
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetNoStore();
Response.Expires = 0;
// HACK: fixes Firefoxes cache issue
Response.AddHeader("ETag", new Random().Next(1111111, 9999999).ToString());
3. Manage the session
I've also implemented a timer on each page that will kill the session after n number of minutes. The session holds the current application ID with which the pages use to load previously entered data. They can get more time by clicking a button. When the timer is up, it redirects back to the main page where I kill the session in Page_Load. I also redirect to this page when the users click the "Finished/Submit" button. Once the session is killed, navigating to the pages by URL will never load the previous application. It'll be treated as a new one.
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
Session.Abandon();
}
4. what else should I do?
Your awesome suggestions/tips here
Since this is a Kiosk app, you'd want to make sure that the browser is configured to honor requests to not cache anything.
Last time I researched the effectiveness of server side no-cache headers, I realized that any one using customized, buggy or uncommon browser might not be honor requests to not cache documents.
You may also want to add javascript back-button breakers on some pages (e.g. some end of session page) and a history navigation deterrent, but not all pages because no one like the back button to be broken.
I think you have the right idea. Killing the session on "finish/submit" is what I would have recommender. Still read over the owasp top 10 and keep your usual vulnerabilities in mind.
1)Make sure you use HTTPS.
2) Always always always test your application for vulnerabilities before rolling it out. I recommend using Wapiti(free), Acunetix($) or NTOSpider($$$$).
3) Keep your server up to date, make sure you run OpenVAS to make sure your server is secure.
Here you are: What should a developer know before building a public web site
Use JavaScript. You will have to capture and prevent each form's submit event, grab the data, submit it via ajax, then use the form's native reset() method. From there you can navigate elsewhere or show validation errors depending on the ajax result. It's easy with jQuery.

asp:Login control, remember me is not remembering me

I have an ASP.NET login control on a page, with the "Remember Me" checkbox displayed. I have checked in trace and the authentication cookie is being created, I have sliding expiration set and a timeout of 60000, yet when I return to the website the login is not being remembered.
Any ideas where else I can check?
Thanks,
Darryl
Correct! The Remember Me checkbox doesn't do anything for you and why should it?
After succesful login; you could create the cookie from code and (when entering the page or masterpage or whatever) attempt to read the previously made cookie to get your credentials.
Or you could use the SetAuthCookie when using FormsAuthentication; reference: http://msdn.microsoft.com/en-us/library/sxb3b282(vs.71).aspx
I've found that whenever any problems are potentially related to cookies, that Firecookie is an invaluable tool for finding out what is actually going on...

After a few window.open calls my ASP.NET session times out

I have an ASP.NET application that uses StateServer session mode with cookieless set to false. In a few places, there is a link that pops up a window to another application (which happens to reside on the same domain, but in a different virtual directory). The following steps give me grief...
Launch popup
Close popup
Launch popup to same app as before with a couple different parameters
Close popup
Next request = session timeout on the "parent" window.
Using cookieless sessions fixes the problem, so somehow my cookie is getting whiped out by the browser. Aside from using cookieless sessions, how can this be resolved? For what it's worth, I am developing/testing with IE8.
EDIT
It seems the problem only occurs when the popup resides on the same domain. If I popup a page elsewhere, there is no problem.
Is it possible the other app (on the same domain) is setting its own cookie, overwriting that of your primary app? Can you use fiddler (or similar tool) to see which cookies are being set by which apps?
Check all instances of your
Session.Clear();
Session.Abandon();
If you aren't using those at all, then its likely the case that your browser windows are set to NOT share sessions between. So the new instance gets a NEW session cookie (since its the same cookie name as the prior one, it could possibly kill the existing session cookie)- as in a play on:
http://geekswithblogs.net/ranganh/archive/2009/04/17/asp.net-session-state-shared-between-ie-tabs-and-ie8.aspx
Ideally track down in which page the Set-Cookie header is coming across. Look then at the request going INTO that response and see if your current ASP.NET_SESSIONID cookie is sent over. (fiddler is indeed the best tool for this)
Anyway - its a start to try.
edit Apparently it's not your cookie name, so...
Perhaps you should have an AJAX call on your master page that pings a service (or generic handler) on your web app to keep the session alive.
JavaScript
window.setInterval(function() {
$.get('ping.ashx?nocache=' + (new Date()).getTime(), function() {
return true;
})
}, 30000);
In the Generic Handler, make sure to add the IRequiresSessionState marker interface.
Perhaps your session cookie names are the same.
In your web.config (for one of the applications) change the session cookie name.
<sessionState
mode="StateServer"
timeout="20"
cookieName="DifferentASP.NET_SessionId"

Avoid losing PostBack user input after Auth Session has timed out in ASP.NET

I have a form that sits behind ASP.NET forms authentication. So far, the implementation follows a typical "out of the box" type configuration.
One page allows users to post messages. If the user sits on that page for a long time to compose the message, it may run past the auth session expiration. In that case, the post does not get recorded... they are just redirected to the login page.
What approach should I take to prevent the frustrating event of a long message being lost?
Obviously I could just make the auth session really long, but there are other factors in the system which discourage that approach. Is there a way I could make an exception for this particular page so that it will never redirect to the Login so long as its a postback?
My coworker came up with a general solution to this kind of problem using an HttpModule.
Keep in mind he decided to to handle his own authentication in this particular application.
Here goes:
He created an HttpModule that detected when a user was no longer logged in. If the user was no longer logged in he took the ViewState of that page along with all the form variables and stored it into a collection. After that the user gets redirected to the login page with the form variables of the previous page and the ViewState information encoded in a hidden field.
After the user successfully reauthenticates, there is a check for the hidden field. If that hidden field is available, a HTML form is populated with the old post's form variables and viewstate. Javascript was then used auto submit this form to the server.
See this related question, where the answers are all pretty much themes on the same concept of keeping values around after login:
Login page POSTS username, password, and previous POST variables to referring page. Referring page logs in user and performs action.
Login page writes out the form variables and Javascript submits to the referring page after successful login
AJAX login
If you don't care if they're logged in or not when they POST (seems a little iffy security-wise to me...) then hooking HttpContext.PostAuthenticateRequest in an IHttpModule would give you a chance to relogin using FormsAuthentication.SetAuthCookie. The FormsAuthenticationModule.Authenticate event could be used similarly by setting an HttpContext.User:
// Global.asax
void FormsAuthentication_OnAuthenticate(object sender, FormsAuthenticationEventArgs e) {
// check for postback somehow
if (Request.Url == "MyPage.aspx" && Request.Form["MySuperSecret"] == "123") {
e.User = new GenericPrincipal(new GenericIdentity(), new string[] { });
}
}
When the session timeout happens the user's session (and page information) get disposed, which would mean the eventual postback would fail. As the others have suggested there are some work arounds, but they all assume you don't care about authentication and security on that particular page.
I would recommend using Ajax to post back silently every 10 mins or so to keep it alive, or increase the timeout of the session as you suggest. You could try to make a page specific section in your web config and include in there a longer timeout.
I handled this once by adding the form value to the database, identified by the remote IP instead of user ID.
( HttpContext.Request.UserHostAddress )
Then, after login, you can check to see if the current user's IP address has a row in the database, and perform the required action.
Michael

Is there a browser equivalent to IE's ClearAuthenticationCache?

I have a few internal .net web application here that require users to "log out" of them. I know this may seem moot on an Intranet application, but nonetheless it is there.
We are using Windows authentication for our Intranet apps, so we tie in to our Active Directory with Basic Authentication and the credentials get stored in the browser cache, as opposed to a cookie when using .net forms authentication.
In IE6+ you can leverage a special JavaScript function they created by doing the following:
document.execCommand("ClearAuthenticationCache", "false")
However, for the other browsers that are to be supported (namely Firefox at the moment, but I strive for multi-browser support), I simply display message to the user that they need to close their browser to log out of the application, which effectively flushes the application cache.
Does anybody know of some commands/hacks/etc. that I can use in other browsers to flush the authentication cache?
I've come up with a fix that seems fairly consistent but is hacky and I'm still not happy with it.
It does work though :-)
1) Redirect them to a Logoff page
2) On that page fire a script to ajax load another page with dummy credentials (sample in jQuery):
$j.ajax({
url: '<%:Url.Action("LogOff401", new { id = random })%>',
type: 'POST',
username: '<%:random%>',
password: '<%:random%>',
success: function () { alert('logged off'); }
});
3) That should always return 401 the first time (to force the new credentials to be passed) and then only accept the dummy credentials (sample in MVC):
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult LogOff401(string id)
{
// if we've been passed HTTP authorisation
string httpAuth = this.Request.Headers["Authorization"];
if (!string.IsNullOrEmpty(httpAuth) &&
httpAuth.StartsWith("basic", StringComparison.OrdinalIgnoreCase))
{
// build the string we expect - don't allow regular users to pass
byte[] enc = Encoding.UTF8.GetBytes(id + ':' + id);
string expected = "basic " + Convert.ToBase64String(enc);
if (string.Equals(httpAuth, expected, StringComparison.OrdinalIgnoreCase))
{
return Content("You are logged out.");
}
}
// return a request for an HTTP basic auth token, this will cause XmlHttp to pass the new header
this.Response.StatusCode = 401;
this.Response.StatusDescription = "Unauthorized";
this.Response.AppendHeader("WWW-Authenticate", "basic realm=\"My Realm\"");
return Content("Force AJAX component to sent header");
}
4) Now the random string credentials have been accepted and cached by the browser instead. When they visit another page it will try to use them, fail, and then prompt for the right ones.
A couple of notes. A few people have said that you need to fire off a ajax request with invalid credentials to get the browser to drop it's own credentials.
This is true but as Keith pointed out, it is essential that the server page claims to accept these credentials for this method to work consistently.
On a similar note: It is NOT good enough for your page to just bring up the login dialog via a 401 error. If the user cancels out of the dialog then their cached credentials are also unaffected.
Also if you can please poke MOZILLA at https://bugzilla.mozilla.org/show_bug.cgi?id=287957 to add a proper fix for FireFox. A webkit bug was logged at https://bugs.webkit.org/show_bug.cgi?id=44823. IE implements a poor but functional solution with the method:
document.execCommand("ClearAuthenticationCache", "false");
It is unfortunate that we need to go to these lengths just to log out a user.
Mozilla implemented the crypto object, available via the DOM window object, which has the logout function (Firefox 1.5 upward) to clear the SSL session state at the browser level so that "the next private operation on any token will require the user password again" (see this).
The crypto object seems to be an implementation of the Web Crypto API, and according to this document, the DOMCrypt API will add even more functions.
As stated above Microsoft IE (6 upward) has:
document.execCommand("ClearAuthenticationCache", "false")
I have found no way of clearing the SLL cache in Chrome (see this and this bug reports).
In case the browser does not offer any API to do this, I think the better we can do is to instruct the user to close the browser.
Here's what I do:
var agt=navigator.userAgent.toLowerCase();
if (agt.indexOf("msie") !== -1) {
document.execCommand("ClearAuthenticationCache","false");
}
//window.crypto is defined in Chrome, but it has no logout function
else if (window.crypto && typeof window.crypto.logout === "function"){
window.crypto.logout();
}
else{
window.location = "/page/to/instruct/the/user/to/close/the/browser";
}
I've been searching for a similar solution and came across a patch for Trac (an issue management system) that does this.
I've looked through the code (and I'm tired, so I'm not explaining everything); basically you need to do an AJAX call with guaranteed invalid credentials to your login page. The browser will get a 401 and know it needs to ask you for the right credentials next time you go there. You use AJAX instead of a redirect so that you can specify incorrect credentials and the browser doesn't popup a dialog.
On the patch (http://trac-hacks.org/wiki/TrueHttpLogoutPatch) page they use very rudimentary AJAX; something better like jQuery or Prototype, etc. is probably better, although this gets the job done.
Why not use FormsAuth, but against ActiveDirectory instead as per the info in this thread. It's just as (in)secure as Basic Auth, but logging out is simply a matter of blanking a cookie (or rather, calling FormsAuthentication.SignOut)
Well, I've been browsing around Bugzilla for a bit now and seemingly the best way you can go for clearing the authentication would be to send non-existant credentials.
Read more here: https://bugzilla.mozilla.org/show_bug.cgi?id=287957
Hopefully this will be useful until someone actually comes along with an explicit answer - this issue was discussed two years ago on a message board.
HTH

Resources