IIS Conditional authentication with the Windows Authentication module - asp.net

I have an unusual situation in which authentication isn't necessary but where learning the user-id via windows authentication under certain conditions would be useful.
To give some context, I want to be able to require windows authentication when the user-agent matches certain conditions, but not require authentication in other conditions. With only some familiarity with asp.net and iis I suspect I am missing an easy way of accomplishing this. So far I've looked into writing a module that checks the user-agent and then adds the WindowsAuthenticationModule if the conditions are met - but I can't figure out how to do this.
Any suggestions the best way to auth or not auth on the value of the user-agent?

If you setup IIS to use windows authentication, you should be able to do something like the following code snippet.
However, as you may guess from the comments in the code, I would advise against it. The User Agent is easily spoofed - so any authentication checks you do based on it can also easily be bypassed. The same holds true for pretty much anything that comes across in an http header (e.g., basing authentication on http referrer is also a bad idea).
string windowsUserName = null;
var currentContext = System.Web.HttpContext.Current;
//NOT SECURE - easily spoofed!
if (currentContext.Request.UserAgent == "Some special user agent")
{
if (!currentContext.User.Identity.IsAuthenticated
|| currentContext.User.Identity.AuthenticationType != "Windows")
{
throw new SecurityException(#"You are not authorized, but you can easily
hack this application by modifying the user agent that you send to the server.")
}
windowsUserName = User.Identity.Name;
}
So in short, even if the above works, don't do it. You really need to completely rethink how you are authenticating your application.
If, as you seem to indicate in the first sentence of your question, this is purely informational, then it may be ok (e.g. if it is just for debugging purposes). However, it would not be suitable e.g. for auditing or restricting access to any resources, and you must be extremely careful that this code doesn't get reused in any real security context.

Related

Implement a Simple Authorization Function in ASP.NET Without Using ASP.NET Identity

I'm building a simple CMS using ASP.NET MVC 5 and Entity Framework 6. I have 2 sites: Public and Admin. Public site to diplay all the content and Admin site to manage all the content.
I only need a single Admin account to handle all the content in the Admin site.
I'm thinking to use a session to keep the logged in user data and check for the session details when accessing an authorized page.
Keep the user data in a session.
var obj = db.UserProfiles.Where(a => a.UserName.Equals(objUser.UserName) && a.Password.Equals(objUser.Password)).FirstOrDefault();
if (obj != null)
{
Session["UserID"] = obj.UserId.ToString();
Session["UserName"] = obj.UserName.ToString();
return RedirectToAction("UserDashBoard");
}
Check before accessing an authorized page.
public ActionResult UserDashBoard()
{
if (Session["UserID"] != null)
{
return View();
} else
{
return RedirectToAction("Login");
}
}
So with this approach I wouldn't need to implement advance ASP Identity functions for the authorization.
Is this approach correct and would there be any downsides using this approach?
NEVER EVER EVER EVER EVER use session for authentication. It's insecure for starters, and it won't survive a loss of session (which IIS can kill at any time, for any reason). Session cookies are not encrypted, so they can be grabbed and used easily (assuming a non-encrypted link, even if you use HTTPS for authentication pages).
Another issue is that you are doing your authentication way too late in the pipeline. OnAuthenticate runs at the very beginning of the pipeline, while you action methods are towards the end. This means that the site is doing a lot of work it doesn't have to do if the user is not authorized.
I'm not sure why you are so against using Identity, the MVC basic templates already roll a full identity implementation for you. You don't have to do much.
The downside is that you have to write it all yourself anyway. You already need role-based authorisation and have to write cludges. Identity already have this implemented and tested for you. Also keeping information in session is not very secure.
And you don't need to implement much yourself anyway. Yes, there are lot of functionality that you'll probably won't need, but just don't use it.
Don't build your own authorisation system. Since you ask this question, you are probably not qualified enough to make it secure.

Is Request.IsLocal secure or can it be spoofed?

I have a webpage which checks for an encrypted cookie on page load to determine user identity. However, when I'm testing the page locally on my development box, I don't have access to that cookie.
Previously I used an appsetting to tell the page whether it was in development mode or not, and when in dev-mode it would load a fixed user identity. Then I discovered Request.IsLocal
I can simply check like this:
if(Request.IsLocal){
FormsAuthentication.SetAuthCookie("testUser", false);
}else{
FormsAuthentication.SetAuthCookie(/*EncryptedCookieValue*/, false);
}
Is this secure? Is there any way a malicious user could spoof IsLocal?
I think your actual question is, how do you have development only functionality?
You could you use: Environment.UserInteractive
http://msdn.microsoft.com/en-us/library/system.environment.userinteractive.aspx
It returns false when running in IIS or a Windows Service, true when their is a user interface i.e. Visual Studio when your developing.
I think this is better than a DEBUG pre processor variable because the behaviour is more consistent, you could accidentally upload a DEBUG version of your dll to your live environment unless you have a very tight build/release process.
As a rule of thumb it's not a good idea to trust anything from the client.
I'd also be pragmatic, what are you protecting and how much effort would someone go to hack in?
The below SO post goes into some of the reasons why you shouldn't trust it:
Can I fool HttpRequest.Current.Request.IsLocal?
Reference
You can view the source at http://referencesource.microsoft.com
public bool IsLocal {
get {
String remoteAddress = UserHostAddress;
// if unknown, assume not local
if (String.IsNullOrEmpty(remoteAddress))
return false;
// check if localhost
if (remoteAddress == "127.0.0.1" || remoteAddress == "::1")
return true;
// compare with local address
if (remoteAddress == LocalAddress)
return true;
return false;
}
The code for IsLocal appears to be robust - I can't see any flaws in its logic so for your purposes it should be fine.
However, you should be aware that if your application (or any other application running on the same server) makes any HTTP requests whose destination can be influenced by the end user then you should add an extra layer of security such as a secret/expiring key or token to your request or you could secure the HTTP request when made so that it is not possible to request a local resource.
e.g. Say your website has an end point such as http://www.example.com/DeleteAllUsers and in the code that handles this request you are checking IsLocal to make sure that users can only be deleted if it is a local, trusted request.
Now let's say you have a function on your website Enter a web address to view headers: and the user enters http://www.example.com/DeleteAllUsers in this text box, causing your application to request DeleteAllUsers and satisfy the IsLocal security check because the HTTP request is made from your app. This is how IsLocal can be exploited, and I realise it is a contrived example to prove the point, but lots of websites do similar things such as grabbing a preview image of a URL to display. If nothing on your server can be made to make a local HTTP request you should be good to go.
You should not put this code on a production server, for the reasons mentioned in the other answers.
However, you could do
#if DEBUG
if (Request.IsLocal)
{
FormsAuthentication.SetAuthCookie("testUser", false);
}
else
{
#endif
FormsAuthentication.SetAuthCookie(/*EncryptedCookieValue*/, false);
#if DEBUG
}
#endif
On your development box, run a Debug build. In production, deploy a Release build.
Determining the remote IP is tricky and depends on configuring the server correctly.
For example a misconfigured server might use X-Forwarded-For to determine the IP, but it can be chosen by the client. But when using a reverse proxy that sets it to its own IP, this is the correct way to determine the IP.
Using the IP from the socket can be wrong as well, consider a reverse proxy running on the machine as the webserver.
=> If possible use a different authentication mechanism

ASP.NET authentication

when developing a login page i'm using the following method
protected void btnLogin_Click(object sender, EventArgs e)
{
if (Validateuser())
{
GetUserRoles();
Response.Redirect("Default.aspx");
lblMsg.Text = string.Empty;
}
else
{
lblMsg.Text = "Invalid User!";
}
}
just check if the user is valid.if valid redirect to a page else display a message.so why we have to use asp.net authentication types?
i've heard about windows,forms and passport authentication types.why we have to use them over the above method and whats the advantage of it.if possible please provide me some sample applications
The basic idea is that rather than you rolling your own security for a website, you should use established, generally accepted techniques and libraries. This allows you to take advantage of the work of security experts who would have been involved in the design and implementation of such authentication & authorization systems. Additionally, there will be a number of features that are already or will be available over time (e.g. support for Active Directory / LDAP, organizational units (OU)). You can take advantage of all of that will modifications to your code, rather than having to implement those features when your users demand them.
Over and above all this, publicly available implementations get used and penetration tested by a wide audience which will report bugs and weaknesses. These will typically get fixed quickly and patches will be issued on a regular basis.
You can read this article from 4GuysFromRolla.com that will give you a good understanding of ASP.NET security options.
One thing to keep in mind - Passport authentication is no longer available to the general public. It's for user by Microsoft only.
The code you shown is an old way of doing authentication. What if the user types the url of default.aspx directly ? How would you protect that ?
You need to learn latest ASP.NET 2.0 authentication basics:
http://www.eggheadcafe.com/tutorials/aspnet/009e2e5e-5a44-4050-8233-59a0d69844e8/basics-forms-authentication-in-aspnet-20.aspx

validating fb cookie using md5 hash

I am trying to incorporate facebook login in my ASP.NET web app and came across the following article which has a code sample for the same.
http://ntotten.com/2010/04/new-facebook-connect-in-csharp/
The following is from the article.
Next, and most importantly, the class
validates the cookie. This validation
uses MD5 hashing to compare the
contents of key appended to the app
secret to the signature that comes in
with the cookie. If these values match
we know the key is valid.we know the key is valid.
Why is Md5 hashing being used for that? Why not SHA or some other algo?
What happens if I don't validate the cookie? Can invalid cookies be sent to the server?
In the article, he throws a new security exception if cookie is invalid? What should the user do in such a case?
I have never really worked with cookies, so I am trying to get the basics right here.
Thanks.
Ok, after some more searching and going through the code, I finally got it.
http://developers.facebook.com/docs/authentication/fb_sig
I recommend you just use the SDK I made to do the verification. http://facebooksdk.codeplex.com. That article was basically the first code I wrote when starting that SDK. The sdk will handle pretty much everything you will need to do to develop facebook app on .Net. We use it where I work on some very large facebook apps hosted on windows azure.
The SDK will handle all the hashing/validating for you. All you need to do is this:
var app = new FacebookApp();
var session = app.Session;
if (session != null) {
// Session is valid
} else {
// Session is not valid
}
The session object is validated before it is returned to you.

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