Why you should care about password length

Jeff Atwood shows us why we should consider better password policies when developing applications or setting company policy.  

As we know, the biggest threat to security is not hackers, but the users themselves making it easy for someone to gain access to protected resources by having ridiculously easy to guess passwords. As developers we are as much at fault for building applications that allow this behavior.  Jeff recommends using pass phrases instead of passwords. A phrase is longer (and thus more resistant to brute force) and easier to remember than a mixed up jumble of nonsensical characters. By adding an unusual word or character pass phrases are very difficult to break with dictionary attacks as well.  Pass phrases are controversial as well, see:

The Great Debates: Pass Phrases vs. Passwords. Part 1 of 3

The Great Debates: Pass Phrases vs. Passwords. Part 2 of 3

The Great Debates: Pass Phrases vs. Passwords. Part 3 of 3

Personally, I think the hard part is convincing users and business owners of an application that longer or more complicated is better. From my own experience I understand users want the simplest password policy possible. Often the business owners of an app don't feel the information being protected is all that important to justify such an imposition for the users, or feel that it becomes a support expense because users can't manage their own data or password very well (a great argument for using something like Windows CardSpace). I think they forget that users re-use the same password everywhere possible: a free e-mail account, network access at work, bank web sites, a blog, a MySpace account, etc. I would not want to be responsible for a malicious person to gain a password from my system and then use that password to systematically destroy someone else's life. Be strong, insist on good password policy.

Posted: Thursday, October 25, 2007 7:50:50 PM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
Security

Web Services Authentication Gotcha

We had code in an ASP.NET page trying to call the Commerce Server Profiles web service that resides on the same physical box. The credentials we used were appropriately configured for Commerce Server using AzMan. For some reason, the code was failing with a 401: Unauthorized error. No matter what credentials we used, no luck. But if you ran the code from another box, it worked fine. Same credentials pointing to the service on that box, no errors.

Turns out the hosts file had an entry for the DNS name we were using, and mapped that name to 127.0.0.1, the loopback address. This was the gotcha. Apparently there is a loopback security feature that causes this behavior. There is a support article describing the effect. Essentially it is a security check to keep certain kinds of attacks at bay. The article suggests registry changes to disable it, but we took a different route.  In the short term, if the calling code accessed the web service via IP address (NOT 127.0.0.1) instead of DNS name the problem was circumvented. Meanwhile the network guru is working to get the actual DNS resolution to work.

Posted: Tuesday, July 03, 2007 11:45:21 PM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
ASP.NET | Commerce Server | Security

More SelfSSL Issues

I blogged previously about some issues with SelfSSL and multiple web sites. A colleague of mine, Charles Medcoff, blogs about a related problem with SelfSSL and SQL Server.
Posted: Wednesday, March 28, 2007 4:39:17 AM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
Security | SQL Server

ASP.Net Single Sign On - Same Domain

This post in the ASP.Net forums has been the best method for me to make a single-sign on work across different sites in the same domain.

You have to set the machine key in the web.config of all sites even on the same physical box.

Posted: Wednesday, October 11, 2006 6:11:18 PM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
ASP.NET | Security

Don't Re-Invent the Wheel - The .NET Developer's Guide to Identity

Learn how to leverage Active Directory in your .Net apps:

The .NET Developer's Guide to Identity

Posted: Monday, June 26, 2006 7:08:41 AM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
Security

ASP.Net Windows Authentication and 401.2 Errors

I am working on an ASP.Net app that usesWindows authentication for users. I have a certain section of the app, the "Administration" set of pages that I want to exclude from certain roles of users. This is easy using a web.config file, but the unauthorized users get an ugly default 401.2 error page. I would like to have a custom page for that, and surpisingly there was not a ton of information out there on how to do it. In fact, more often than not the answer was "It can't be done."

I did find an acceptable answer in the forums at aspfree.com. Essentially the solution is to handle the Application_EndRequest event in the global.asax and check the status code and authentication of the user. Here is my version:

void Application_EndRequest(object sender, EventArgs e)
{
    if (Response.StatusCode == 401 && Request.IsAuthenticated && Request.Url.AbsoluteUri.Contains("Administration"))
    {
        Response.ClearContent();
        Server.Execute("../NoAccess.aspx?id=Administration");
    }
}

 

I don't believe this method will work with Forms Authentication, I ran across plenty of posts saying that it works differently.

Posted: Tuesday, April 04, 2006 7:28:29 PM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
ASP.NET | Security

SelfSSL and Site ID

SelfSSL is a tool found in the IIS 6.0 Resource Kit. It allows you to generate SSL certificates for a development environment. In all the instructions for using SelfSSL, it describes one of the parameters as "Site ID", where the default value=1, which is the default web site installed on the computer. The Site Id parameter is essentially telling SelfSSL which web site to install the certificate into. Well, if you have multiple web sites, then the default site id is useless. You need the Site Id of the web site where you want the certificate installed. Of course the documentation does not spell this out, and as a non-Admin the Site Id was not an intuitive term for me. But I found that there is a script you can run from the command-line called iisweb.vbs using the /query switch. That will tell you the Site Id. Seeing that, then I realized that the IIS log file folders (in windir\System32\logfiles\) are named according to the Site Id.

Anyway, creating a second certificate for a different site on the same IIS using SelfSSL messes up the SSL cert of first site. This is a known issue apparently, and David Wang has a great post on this problem. The comment further down by Paul Carrig is most useful, as he points out there is a workaround for the SelfSSL and multiple site issue. So I actually found two workarounds:

  1. The technique described by in the aforementioned post:
    1. Install the cert in the first site
    2. Export it to a .pfx file
    3. Install the cert in the second site
    4. Remove the cert from the first site
    5. Re-Import the cert to the first site using the .pfx file

      or
  2. Install the cert in the first site, and export it to a .pfx file. Then import that to the other sites. The down side to this is that the certificate is even less valid for the second sites as now it has an untrusted publisher (me!) and the site name is not a match. The prompt is essentially the same, but in our case one site contains web services which will throw an error if the prompt comes up at all (as it should). The workaround for that is to install the certificate on the client computers as well, which is an acceptable problem for a development enviroment.
Posted: Monday, August 08, 2005 8:27:20 PM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
IIS | Security

Securing the Connection String with the Machine Key

d.code asks about securing connection strings. If you are willing to deal with a little unmanaged code, you can use the machine key or a user key via Data Protection API (DPAPI) functions instead of hiding your key somewhere. I first heard about the machine key at a Microsoft Security Summit that was touring around the country last spring. I based my work on this example, and a relevant MSDN article. The upside is that you do not need to maintain your own key somewhere, the downside is that any application run on the computer could decrypt your string, and that an encrypted string cannot be passed between computers (or users if you go that route), so you have to create the encrypted strings during deployment and have access to run an executeable on the production computer during deployment.

I created a small Winforms program that I run during deployment to encrypt my connection strings using the machine key. It just has two text boxes and two buttons for encrypting and decrypting strings. Once the deployment is done the exe is removed from the production machine. If someone compromised the box, they would have to know you used DPAPI (which they could only determine by spending the time to decompile your assembly) and have their own exe ready or create one to decrypt the strings. A little obfuscation on your code would contribute to the security in this situation.

Posted: Friday, November 12, 2004 1:26:46 PM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
ASP.NET | Security | Winforms

Custom Text File Publisher for Exception Management Application Block

I needed to create a publisher for exceptions to a text file (XML would be better but the requirement was for text...). I based my publisher on this article I found on C# Corner. But it has one problem associated with using files, that unfortunately loomed large. Concurrency. To a certain extent the code handled the problem by tossing the error into the Event Log if the provider threw an error, but this was not acceptable for my requriement. So I needed to modify the code to handle the issue. Essentially, I modified the overriden Publish procedure to trap the error related to the StreamWriter and then sleep for a set amount of time and try again. After too many failures at writing to the file the error eventually gets written to the event log (so it is not lost).

privateconst int WriteAttempts = 5;
private const int SleepTime = 500;

void IExceptionPublisher.Publish(Exception exception, NameValueCollection additionalInfo, NameValueCollection configSettings)
{

    // Read and set up configuration
    SetConfig(configSettings);

    // Create fileName
    string logFilePath = CreateLogFilePath();

    // Create Message
    string logMessage = CreateLogMessage(exception, additionalInfo);

    int attempts = 0;
    bool written = false;

    // Write the entry to the log file.
    while(!written && attempts <= WriteAttempts)
    {
       
try
       
{
            // Append to file if exists or create new file
           
using ( FileStream fs = File.Open(logFilePath, FileMode.Append,FileAccess.Write))
            {
               
using (StreamWriter sw = new StreamWriter(fs))
                {
                    sw.Write(logMessage);
                    written =
true;
                }
            }
        }
       
catch
       
{
            attempts++;
            Thread.Sleep(SleepTime);
         }
    }
    if(attempts > WriteAttempts)
    {
       
throw(exception);
    }

}

Posted: Thursday, September 09, 2004 4:49:42 PM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
.Net 1.1 | Security

Detroit Security Summit Review

Last week I got to attend the Microsoft Security Summit in Detroit. The event lasted an entire business day, and was broken down into a keynote address followed by four sessions that covered three different tracks: 200 Level Networking, 300 Level Networking and 200 Level Developer. I personally attended all four Developer sessions.

The keynote address was given by Tom Button, VP of the Windows product management group. He gave a dynamic talk and clearly outlined Microsoft's broad range of security efforts. Most of the focus was on XP and Windows 2003 server. During his presentation there was a demo of XP sp2. It looked good, I need to see more so the XP sp2 RC1 CD that every attendee got will come in handy. Tom laid out an excellent view of Microsoft's vision of security as well as an overview of all the current intiatives and their future directions.

Of the four Developer sessions, three were OK and one was terrific. Of the three that were OK, much of the material was an overview or shallow demos (it is a 200 Level track). For instance cryptography and and impersonation were explained in the first session, with a demo of installing a SSL certificate and a demo of the authentication options for a web site. The second session covered different types of exploits like buffer overruns and SQL injection with simple demos. It was better than the first session, the speaker was much more excited about the topics and it came across in the presentation.

The third session was a winner. It covered threat modelling in detail, followed by an extensive demo of securing web.config in ASP.Net. The speaker covered a ton of great material there, information that I had to really dig for when I was first trying to secure web.config for my own projects. On top of that, he covered additional information about machine keys that I could really use. The demos in this session were much more in-depth that the previous two.

The last session fell into the pattern of the first two. Much more theoretical and less code.Some of the topics covered included .Net Code security, using the GAC, and using identity and principal objects. The session was better than the first two, but not as in-depth as the third.

Overall, I think Microsoft did an excellent job of presenting a wide range of material at the Summit. Since there was only one Developer track advertised at a 200 level, most of the information was somewhat basic, but if you were new to developing or to .Net it was certainly worthwhile. The speakers included enough advanced material to keep more experienced developers from losing out as well. It's a difficult balance to strike. For what was promised up front, the Summit delivered.

Posted: Wednesday, May 19, 2004 1:22:08 PM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
Security

Forms Authentication Problem

An ASP.Net site we created is having infrequent problems with logins using forms authentication. Essentially what happens is that the user attempts to login and is successful, but then is redirected back to the login page immediately. So it looks like an infinite loop of logins. We have been able to deduce that the cookie is related to the problem. If the user deletes their cookies in IE the problem goes away. The problem is very intermittent, so it is very difficult to reproduce. It is not generating 500 errors or errors in the logs. From extensive Googling, the best I can come up with is the fact that we allowed the cookie to persist across sessions, and the problem is related to that. So I changed the createPersistentCookie parameter to false:

FormsAuthentication.SetAuthCookie(nResult.ToString, False)

Of course, solving the problem is only a wait-and-see in this case, since I can't reproduce the problem directly. I thought our login code was pretty straightforward, letting ASP.Net do as much of the work as possible.


Imports System.Web.Security.FormsAuthentication
....
.... 'txtEmail, txtPassword are textboxes on the form, lblMessage is a label control Public Sub Login_Click(ByVal snd As System.Object, ByVal e As System.EventArgs) _
Handles LoginButton.Click
Dim NotRegistered As String = " is not a registered email address. “ & _
“Please use the Create A Profile link to register." Dim nResult As Integer
If Page.IsValid Then Dim sPassword As String





sPassword = HashPasswordForStoringInConfigFile(txtPassword.Text, "sha1") nResult = LoginResult(txtEmail.Text, sPassword) 'Validate against the database If nResult = -1 Then 'Not a registered user, display error message lblMessage.Text = txtEmail.Text & NotRegistered ElseIf nResult = -2 Then 'Bad password, set error message lblMessage.Text = "The password for " & txtEmail.Text & _
" is incorrect" ElseIf nResult > 0 Then 'Registered user, nResult is their ID number If Request.QueryString("ReturnUrl") <> "" Then 'Redirect to requsted page RedirectFromLoginPage(nResult.ToString, False) Else 'Go to My Jobs by default SetAuthCookie(nResult.ToString, False) Response.Redirect("../MyJobs/My_Jobs.aspx") End If
End if End If End Sub
Posted: Wednesday, January 07, 2004 1:36:54 PM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
.Net 1.1 | ASP.NET | Security | Strange Problems

Query a Novell LDAP server with VB.Net

Once again, I am amazed at how simple tasks have become using .Net. Something I thought would be complex turns out to be completely handled by the framework. Kudos to the .Net team.

For my current project, I need to validate that a person is an internal employee before allowing them continued acccess to the web site. My company uses a Novell infrastructure, and luckily has an LDAP server that I can access for employee validation.

Luckily, Novell provides a resource for developers to begin working with LDAP at the Novell Developer Labs. You can create an account and query their server for free. So that is where I started, but eventually the Novell network admins in my company got around to my request and I was able to use the code almost without modification against our internal server.

Here is my quick console application I created to test against the Novell Developer Lab LDAP site (my container name is Fender and my login is admin.  The only modifications I had to do to get it to work with my company's LDAP server was to learn the container names and the fields I could query.  

Imports System.DirectoryServices

Sub Main()
Dim
ds As New DirectorySearcher
Dim resultset As SearchResultCollection
Dim result As SearchResult
'Return the securityEquals field and the cn field
Dim ResultFields() As String = {"securityEquals", "cn"}

With ds
    'Set the container I want to search (.admin.Fender.user.novell)
    .SearchRoot = New DirectoryEntry(
LDAP://192.108.102.215/ou=Fender,ou=user,o=novell)
    'Use the array set above for return fields
    .PropertiesToLoad.AddRange(ResultFields)
   
'Set a filter/query
    .Filter = "cn=ad*"
End With

Try
  
'Perform the search

   
resultset = ds.FindAll()
    If resultset.Count > 0
Then
       
For Each result In resultset
            Console.WriteLine(result.Properties("securityEquals")(0))
       
Next
    Else
        'No results
       
Console.WriteLine("No Data Found")
    End If

Catch ex As Exception
   Console.WriteLine("Error: ")
   Console.WriteLine(ex.Message)
End Try

End Sub

Posted: Friday, September 12, 2003 2:43:44 PM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
.Net 1.1 | Novell | Security

Impersonation

All right, now that I have done a bunch of talking, how about some code? I stumbled across this recently while pouring through MSDN. The code lets you impersonate any other user, provided you know the credentials. In our case we needed to become the IIS user so we could access files on a remote file server. In our situation, there are multiple web applications within our domain, so the network admin has set up the IIS sites to all use a common domain-wide anonymous user, so it is easier for him to manage permissions. As we are the first .Net project, the ASPNet user has no rights whatsoever on the network. We talked with the admin and he was not interested in giving the ASPNet users from a bunch of different web servers rights to other network resources. We looked at changing the ASPNet user credentials Machine.config, but this broke debugging locally immediately. So I looked into impersonation and found out how to impersonate the IIS user in code:

Imports System.Security.Principal

Function impersonateAnonymous() As WindowsImpersonationContext

     'Grab the current Http context
    
Dim context As HttpContext = HttpContext.Current

    'Set up a Service Provider based on this context
     Dim
iServiceProvider As iServiceProvider = CType(context, iServiceProvider)

     'Create a type which represents an HTTPContext
     Dim
httpWorkerRequestType As Type = GetType(HttpWorkerRequest)

     'Get the HttpWorkerRequest service from the service provider
     Dim
workerRequest As HttpWorkerRequest = _
         
CType(iServiceProvider.GetService(httpWorkerRequestType), HttpWorkerRequest)

     'Get the token passed by IIS from the workerRequest service
     Dim
ptrUserToken As IntPtr = workerRequest.GetUserToken()

     'Create a Windows Identity from the token
     Dim
winIdentity As New WindowsIdentity(ptrUserToken)

    'Send back the IIS identity
     Return
winIdentity.Impersonate

End Function

To use the function, simply call it like so before the code that needs proper permissions:

Dim impContext As WindowsImpersonationContext = impersonateAnonymous()

Now the subsequent lines of code operate in the context of the user assigned to IIS. And then when you are done impersonating:

impContext.Undo()

I based this function on some C# code I found in a Patterns & Practices document on MSDN: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/thcmch10.asp

Posted: Tuesday, September 02, 2003 6:00:54 PM (Eastern Standard Time, UTC-05:00)  #    Comments - Trackback
.Net 1.1 | ASP.NET | Security