Saturday, April 30, 2011

Book Review: The Agile Samurai

I really believe that being well-rounded is the key to success in the development world (or in any world for that matter).  I have been in and around Agile methodologies for a while now, but have never really spent the time to read up a book about how the pros do it.  This book, although not really an introduction, covers a lot of the basics.  In addition to that, it gives some useful tips on how Agile is really done in the field.  It covers some concepts to help deal with unreasonable (read stupid) product owners.  Although probably meant more for project managers, all the information is good to know for any project members.

The pro to this book is the discussion about the inception deck.  I think that the one thing projects in general (software or not) miss is the fact of momentum.  Watch any sports game, and you will notice that momentum is everything.  You can either start your project off by setting it up to succeed, or start it off setting it up to fail.  Does it cost money? Of course.  Does it cost time? For sure... Do you accomplish great things with momentum on your side? You bet.

The book talks about the concept on an inception deck.  Awesome idea for any (read any) project.  Here is a summary:

1) Asky why we are here
2) Create an elevator pitch
3) Design a product box
4) Create a NOT list
5) Meet your neighbors
6) Show the solution
7) Ask what keeps us up at night
8) Size it up
9) Be clear on what's going to give
10) Show what it's going to take

This list is a great way to start the project, make sure everyone knows what is going on, and hit the ground running.  In my current project, I was the resident "expert" on the existing system.  I know that had we started off creating this inception deck, more people would have been on board quicker.  The project team would have had a better idea of what they are trying to deliver.

The con to this book was it's focus on the people aspect of projects and specifically agile projects.  I have another post in the works that will better describe what I am talking about, but in Agile projects, you really need good, well-rounded people on your team.  Go getters.  People who are willing to step out of their comfort zone to get the job done.  Another thing is about how to deal with the client.  At the end of the day, presentation and ethos are the main factors in how a project is received by the product owner.  In my most recent project, we had an incident in our first demo.  The BA who was showing off our work was quick to point out that the the website "looks" were not up to par.  It turned out near the end of the demo, that the customer actually "liked" what we had done so far.  Of course there was room for improvement, but it wasn't all bad.  However, after that meeting, the project team was on the look for a design company to work on the UI for the project.  Not the wrong decision by any means, but the presentation could have been done differently.  We could have asked opinions, rather than forcing ours onto our client. 

In any event, this was a great read to get some basic + advanced knowledge of the Agile process.  I'd recommend it for anyone who wants to get a better understanding of how things should work in Agile projects.  I'd also recommend it for any project managers out there running Agile projects.

MVC3 Validation Oddities

I had created a post to demonstrate an example for how to do validation in MVC 3. I worked off of an assumption that is now proving to be false.

1) All validation attributes are run, even if one of them fails.

My initial assumption was that if one of the validation attributes were to fail (say Required) that no other attributes would run. In my post, I didn't add a null check to my custom validator based on this assumption. In fact, according to the debugger, all validation attributes are run.

I decided to play around with this a bit to see what the logic was behind this. My colleague mentioned that when you validate, you would probably want to get all the errors back at once, as opposed to only one. This made sense at the time, but was still a little big confusing. Obviously, if you enter a null value for something like username, you probably only want the one error message (User name is required). I can understand where my colleague is coming from , however. Lets say that the username is not null. You would probably want an error message if the length is too small, or doesn't contain the correct characters.

The first thing I tried was to add two custom validators, and see what would happen. It turns out that although both attributes are run, only the error message from one is actually displayed.

[Address]
        [Address2]
        public string Address { get; set; }

It seems (at least for me) that Address2 was the error message that always came up. It did not matter on ordering. I found that one of the methods you can override is IsDefaultAttribute. I found that even setting that didn't change which message gets sent back to the client.


public class AddressAttribute : ValidationAttribute
    {
        public AddressAttribute()
        {
            ErrorMessage = "Address attribute failed";
        }

        public override bool IsDefaultAttribute()
        {
            return true;
        }

        public override bool IsValid(object value)
        {
           
            var address = value as string;

            return false;
        }
    }

I even tried this using the built in validators that come with MVC2. Same result, only one error message made it back to the form.

I know for a fact that when client side validation is turned on, you seem to get all the error messages displayed back. With that being said, it is interesting that you don't get all the error messages displayed if you are just doing simple, no js dependent, error checking. What is also interesting, is that you have to do things like a null check in all of your custom validators, otherwise they will blow up.

I decided as one last final step, to go take a look at some of the source code to see if I could make sense of all of this. Without resharper (or a a full VS at home) it was pretty hard to piece things together. What I did find was the RegularExpressionValidator in Sys.Mvc.

2) Included Validators seem to be dependent on each other.

I'm not sure where this is used, but the implementation of this seems to depend on the the RequiredValidator. A quick test of this yields that a null will pass through the regular expression attribute no problem!

namespace Sys.Mvc {
    using System;

    public sealed class RegularExpressionValidator {

        private readonly string _pattern;

        public RegularExpressionValidator(string pattern) {
            _pattern = pattern;
        }

        public static Validator Create(JsonValidationRule rule) {
            string pattern = (string)rule.ValidationParameters["pattern"];
            return new RegularExpressionValidator(pattern).Validate;
        }

        public object Validate(string value, ValidationContext context) {
            if (ValidationUtil.StringIsNullOrEmpty(value)) {
                return true; // let the RequiredValidator handle this case
            }

            RegularExpression regExp = new RegularExpression(_pattern);
            string[] matches = regExp.Exec(value);
            return (!ValidationUtil.ArrayIsNullOrEmpty(matches) && matches[0].Length == value.Length);
        }

    }
}

I'm sorry this post was a little bit of a ramble, I guess I am just confused on the implementation of validation in MVC 3.

Sunday, April 24, 2011

HackThisSite - Realistic 5 Solution

This was a pretty fun exercise, albeit pretty simple.

1) Recon
The first thing you should always do is have a look around. With HackThisSite, it is very very very important that you read the descriptions. You'll note a couple things.

- "Everything they use is 10 years old"
- "new password seems to be a 'message digest'"

With that, you should have a look around. You will notice that you have a lot of email addresses on the pages. These are good to keep in case you need to start guessing usernames (you don't, but just saying). On the news page you will notice something about google finding links that it shouldn't. Immediately, you should think to take a look at the robots.txt file.

In the robots.txt file, you will notice a few directories that they don't want you looking into.

2) Discovery

You will start poking around in the directories that you found in the robots.txt file. In there, you will find copies of php files, etc. Start clicking on them. You will notice that one of them displays a hash that it is trying to match. If you take a look at the lib directory, you will have access to a "hash" library. You can download that and just open it up in notepad. You will notice from it the hashing algorithm to use to try and break the password.

3) Exploitation

Using a program like mdcrack, you will be able to very very very quickly get a collision that produces the correct hash (really that is all you need, the original password is irrelevant).

Enter said password into the database page, and you have completed level 5!

Monday, April 18, 2011

c#: Custom Validation Example

Validation is a big thing for any application.  I am currently working on implementing validation in my WCF layer that doesn't rely on me checking each operation and then hardcoding validation logic into a gigantic class.  I really like the way WCF does model validation, so I decided to start trying to reproduce it to figure out how they did it.

It turns out that it is pretty simple as the following code suggests.  I created a base attribute called Validation Attribute.  I created a BaseModel that has a validate method on it.  That method does some simple reflection to get all the attributes for all the properties in the given class.  It just calls IsValid on those attributes to run the specified logic. 

Check it out.


    public class BaseModel
    {
        public bool Validate()
        {
            var result = true;

            foreach (var property in this.GetType().GetProperties())
            {
                foreach (var attribute in property.GetCustomAttributes(true))
                {
                    if (attribute is ValidationAttribute)
                    {
                        try
                        {
                            var attr = (ValidationAttribute)attribute;
                            result = result && attr.IsValid(property.GetValue(this, null));
                        }
                        catch (Exception)
                        {
                            result = false;
                        }
                    }
                }
            }

            return result;
        }
    }


    public class LoginModel : BaseModel
    {
        [UserNameValidation]
        public string UserName { get; set; }
    }

    [System.AttributeUsage(System.AttributeTargets.Property)]
    public class ValidationAttribute : Attribute
    {
        public virtual bool IsValid(object obj)
        {
            return false;
        }
    }

    public class UserNameValidationAttribute : ValidationAttribute
    {
        private const string USER_NAME_REGEX = @"^\w+$";

        public override bool IsValid(object obj)
        {
            if (obj == null)
            {
                return false;
            }

            var value = obj as string;
            
            if (Regex.IsMatch(value, USER_NAME_REGEX))
            {
                return true;
            }

            return false;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var loginModel = new LoginModel();
            loginModel.UserName = "UserName";
            Console.WriteLine(loginModel.Validate());
        }
    }

Monday, April 11, 2011

HackThisSite - Realistic 4 Solution

This was a pretty fun little exercise.  It really got me thinking about where my skill set is these days.  It is one thing to know that SQL Injection exists, and another to be really good at crafting queries to use it to your advantage.  Here are the steps to follow to solve this one.

1)  Recon
In the recon phase, you must do the basic things.  Take a look at the source.  Click around on the links and see where this takes you.  In real life you would spider, but for this you will have to just see what you can see.  What you will notice is that there are two "input points".  The first is a small form asking for you to enter your email.  The second is the link to the products pages.  If you notice you have a products.php?category=1.  As you know, any input can be fuzzed.


2)  Discovery
In this phase, we start trying to play around to see what we can see.  The first step is to work at the email form.  There are many places this email could be being stored.  Most commonly, however, it is stored into a sql database.  A quick sql injection attempt here will yield some interesting results.  The developers of the site have not bothered to mask their error messages (quite common in real life) and you get that the name of the email table is email.  Clearly the sql injection attempt is being blocked.  There is no way to do blind sql injection at this point since we don't have a way to view the information. (Yes you could try pinging and stuff, but this is just a test).


The next step is to see if the other inputs on the page have any problems. A quick sql injection attack via firebug yields that there is no sql protection on link to the product pages.


products.php?category=1 or 1=1


Produces a page with all products on it.  Further more, if you put in a sql statement that generates an error, you get a nice little blank page.


3)  Exploitation
Now that we know the basics of what we can do, it is time to exploit it.  Sql has a command that is called Union All.  Basically, this command allows you to combine the results from two select statements.  The key is that the column numbers have to match.  By looking at the product page, you can try and guess how many columns are being returned in the original query.  There seems to be a link to an image, a description, and a price.  There is probably also an id of some kind.  That makes 4.

Since description is the field that seems to print out a string, we will use it for our query.

products.php?category=1 UNION ALL SELECT null, *, null, null FROM email;

The only reason why this works is because * means everything, and email probably only has 1 column.  At least that is my understanding of the above sql query.

Running that produces a list of all the email addresses currently in the system.  To finish off the challenge, use the HTS Message Center to send the list to SaveTheWhales.

Enjoy.
 

Sunday, April 10, 2011

Self Updating WCF Service

Recently I was in a meeting where my idea of a self-updating WCF service was laughed at. This post will contain a very rough proof of concept that the idea is possible. The solution is pretty simple.

1) Self hosted WCF service has a file watcher looking for a file to be created.
2) WCF service has an "update" method where it creates a file to trigger an update
3) Self hosted service reloads the new assembly by way of reflection.

I have skipped over a lot of the details in this proof of concept. Things to look at would be:

1) How does the update file get there (could be via WCF Service)
2) File watcher is not the only way to do this. Maybe nServiceBus? I would have to look into it more.
3) DLL Needs to be verified somehow before it is just loaded automatically. Could be done via signed dll's, or another method? Open to suggestions.

Anyways, here is the code.

WCF Service
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.IO;

namespace WCFSelfUpdater
{
    public class Service1 : IService1
    {
        private string versionNumber = "1.1";

        /// 
        /// Version number in original program is 1.0.  Changed to 1.1
        /// If you want to reproduce this, you need to create 2 dll's each with a different 
        /// version number.
        /// 
        /// 
        public string GetVersionNumber()
        {
            return versionNumber;
        }

        /// 
        /// Method could write the stream out to the disk and then move it (atomic operation)
        /// to where it needs to be.  In this case I just skipped over all of the implementation'
        /// details to just show that the idea was possible.
        /// 
        ///         /// 
        public bool Update(Stream stream)
        {
            try
            {
                using (TextWriter writer = new StreamWriter(@"c:\temp\shamir.dll"))
                {
                    writer.WriteLine("PLEASE UPDATE");
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("ERROR" + e.Message);
            }

            return false;

        }
    }
}


Self Hosting Command Line Application
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Reflection;
using System.IO;
using System.Threading;

namespace WCFSelfUpdaterHost
{
    class Program
    {
        static bool NeedsUpdate = false;

        static void Main(string[] args)
        {
            try
            {
                //Step 1, create a file watcher to check for "update.dll" to be placed
                FileSystemWatcher watcher = new FileSystemWatcher(@"c:\temp","shamir.dll");
                watcher.EnableRaisingEvents = true;
                watcher.Changed += new FileSystemEventHandler(watcher_Changed);
                Uri baseAddress = new Uri("http://localhost:9999/hello");
                
                // initial setup of WCF service with version 1.0
                Assembly assem = Assembly.LoadFile(@"D:\work\WCFSelfUpdater\WCFSelfUpdater\bin\WCFSelfUpdater.dll");
                Type serviceType = assem.GetType("WCFSelfUpdater.Service1");

                bool done = false;

                // CAUTION::: Done is never set to true.  I ran this in debug mode so didn't have a problem!!!!
                while (!done)
                {
                    var result = RunService(serviceType, baseAddress);
                    if (result == ResultCode.NeedsUpdate)
                    {
                        // Load new service
                        assem = Assembly.LoadFile(@"D:\work\WCFSelfUpdater\WCFSelfUpdater\bin\WCFSelfUpdater1.dll");
                        serviceType = assem.GetType("WCFSelfUpdater.Service1");

                        // This code simple checks to make sure the version changed.
                        var obj = Activator.CreateInstance(serviceType);
                        MethodInfo me = serviceType.GetMethod("GetVersionNumber");
                        var result1 = me.Invoke(obj, null);
                        Console.WriteLine("NEW VERSION NUMBER:" + result1);

                        // Need this to keep loop below going
                        NeedsUpdate = false;
                    }
                    else
                    {
                        done = true;
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Error received.  Enter to exit." + e.Message, e);
                Console.ReadLine();
            }

            Console.WriteLine("Done execution: enter to exit");
            Console.ReadLine();
        }


        static void watcher_Changed(object sender, FileSystemEventArgs e)
        {
            NeedsUpdate = true;
        }


        static ResultCode RunService(Type type, Uri baseAddress)
        {
            using (ServiceHost host = new ServiceHost(type, baseAddress))
            {
                ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
                smb.HttpGetEnabled = true;
                smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
                host.Description.Behaviors.Add(smb);

                host.Open();

                Console.WriteLine("Enter to stop");
                while (!NeedsUpdate) { Thread.Sleep(100); }

                host.Close();
                return ResultCode.NeedsUpdate;
            }
        }
    }

    enum ResultCode
    {
        Done,
        NeedsUpdate
    }
}


Calling application
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;

namespace WCFClient
{
    class Program
    {
        static void Main(string[] args)
        {
            var client = new ServiceReference1.Service1Client();
            try
            {

                StreamReader reader = new StreamReader(@"c:\temp\WCFSelfUpdater.dll");
                

                client.Open();
                Console.WriteLine(client.GetVersionNumber());
                // doesn't matter what file is being read in as it isn't currently
                // used in the WCF Service
                Console.WriteLine(client.Update(reader.BaseStream));
                // Sleeping to allow time to reload the wcf service.
                Thread.Sleep(10000);
                Console.WriteLine(client.GetVersionNumber());
                Console.ReadLine();
            }
            catch (Exception e)
            {
                Console.WriteLine("Error received.  Enter to exit" + e.Message, e);
                Console.ReadLine();
            }
            finally
            {
                client.Close();
            }
        }
    }
}



In any event, this proof of concept is pretty rough. There is little in the way of security, etc implemented. It is good to know that the idea is possible, and only took about an hour to research and implement.

Resources used:
http://dranaxum.wordpress.com/2008/02/25/dynamic-load-net-dll-files-creating-a-plug-in-system-c/
http://www.c-sharpcorner.com/UploadFile/mokhtarb2005/FSWatcherMB12052005063103AM/FSWatcherMB.aspx
http://www.csharp-examples.net/reflection-examples/

Thursday, April 7, 2011

Adventures in LINQ - Part 2

For this adventure, I have decided to try and simulate an outer join.  Linq does have join method, however, this method by default does an inner join.  There are many many applications where you would want to do an outer join. More specifically, I am doing a left outer join.

On the surface, the solution located at Hooked on LINQ seems a fair bit complex.  I have come up with my own solution instead.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LinqOutterJoin
{
    class Program
    {
        static void Main(string[] args)
        {
            var element1 = new Element() { Id = 1, Name = "Element1"};
            var element2 = new Element() { Id = 2, Name = "Element2"};
            var element3 = new Element() { Id = 2, Name = "Element3"};
            var element4 = new Element() { Id = 4, Name = "Element4"};
            var element1a = new Element() { Id = 1, Name = "Element1a"};


            var elementList1 = new List { element1, element2, element3 };
            var elementList2 = new List { element1a, element4 };

            elementList1 = elementList1.Concat(elementList2.Except(elementList1)).ToList();

            elementList1.ForEach(x => Console.WriteLine(x));

        }
    }

    public class Element
    {
        public int Id { get; set; }
        public string Name { get; set; }

        public override bool Equals(object obj)
        {
            var newObject = obj as Element;

            return this.Id == newObject.Id;
        }

        public override string ToString()
        {
            return this.Id.ToString() + " " + this.Name.ToString();
        }

        public override int GetHashCode()
        {
            return this.Id.GetHashCode();
        }
    }
}
Basically my solution makes use of the Concat and the Except methods.  Concat is pretty simple.  It takes list 2 and adds it to the end of list 1.  The Except method goes through all elements in list 1 and only returns them if they do not exist in list 2.  Sounds like an outer join to me!

Monday, April 4, 2011

MVC3 XSS Protection

I am focusing quite a bit on security in my current project, and so I decided to spend a little time working with the default xss projection in MVC3.

On the surface, it seems as if the default protection against XSS is quite robust in MVC3.  I started off by creating a simple form that took a message input.  This message was added to the ViewData and passed back to another view where it was displayed.  I tried the most basic of XSS attacks at got a nice little error message saying

Server Error in '/' Application.

A potentially dangerous Request.Form value was detected from the client (message="<script>alert("hello...")



Pretty good eh?  Now of course you would want to have a custom error page all set up, but this is quite nice protection to have right out of the box.  MVC3 includes a ValidatinInputAttribute which you can set to false to disable the input validation.  You can set this attribute only on the method or class level, so make sure you know what you are doing.


[ValidateInput(false)]
        public ActionResult Display(string message)
        {
            .....
        }

Adding this attribute on to my method got rid of the nasty error message received before.  I proceeded to add this message directly to the ViewData and outputted it directly on the screen.  To my amazement, it printed the input with the proper escaping!  WOW!  Microsoft finally got something right.  I started to ask myself the question, what if I actually wanted to display HTML on the screen, say for example, rich text input.  It turns out that you have to do a combination of the following.

In you model input, you have to use the AllowHtmlAttribute.  This attribute will ensure that you won't get a nasty message when input validation occurs without having to disable all field validation for that method or class.  This also allows you to still do some sanity checks on the data you are receiving.  In order to get this html to display properly, you have to use the Html.Raw method to output the data.


public class DisplayModel
    {
        [AllowHtml]
        public string Message { get; set; }
    }

Hello, @Html.Raw(Model.Message)

It is good to see that it MVC3 is trying to do protection by default.

Sunday, April 3, 2011

Book Review: Don't Make Me Think 2nd Edition

On my current project, I have been forced to wear many hats. One of those hats is that of lead designer. Sure, putting divs on the page is easy. But how do you actually make something look good? How do you make it usable? How do you design a user experience?

I would call this book a good intro to the world of design. The author sets the expectations of this book at the beginning. It is not an all inclusive book (I don't think one is in existence in the world of design). It is a short primer to get the reader up to speed on some of the biggest design flaws. As the author quotes in his first few pages,
"You don't need to know everything. As with any field, there is a lot that you could learn about usability. But unless you are a usability professional, there is a limit to how much is useful to learn."

I would say that this book is a good intro.  It will give you the skills necessary to take a critical look at your websites design.  It will give you ideas to tweak the design.  It will give you the skills (say if you are a hireing manager) to take a good look at work being present to you.  Most of all, it will force you to think objectively about web usability and design so that you can make better decisions.

I recommend this book to anyone wanting to get a start in web usability.

Friday, April 1, 2011

Validation in MVC3: An Example

[[Update]]
I had to add a null check to my custom validator. You can find out more information in this post.


Validation is a big aspect of security in web applications.  I can't count how many times I have seen blatant ignorance of this simple fact.  Just recently I was browsing an application built by a 3rd party (who probably charged an arm and a leg for their product).  It took about 1 minute to find a huge sql injection flaw in their application.  One of the get parameters that was being passed into their application was being put directly into a database call.  Worse than this, I got an error message telling me that my sql statement had not worked.  This error message told me the following pieces of information.

1)  It returned the actual sql call
2)  It told me the database that it was using along with the version
3)  It told me the web framework that was being used.

The security industry has spent a lot of time trying to educate developers on best practices for building secure applications.  It is unfortunate to see people still do this kinda of sloppy work.  I guess there is a reason why injection attacks are still on the OWASP top 10 list.

In this article I am going to go over making a custom user name validation attribute.

User names are part of most web applications these days.  I want you to note that there are other perfectly valid ways to do what I am doing here.  I have chosen to make a custom attribute because I assume that I will be using this user name validation in other parts of my application.  Following the DRY principals, it is best to create a custom attribute and go from there.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;

namespace MvcApplication2.Attributes
{
    public class UserNameAttribute : ValidationAttribute 
    {
        private const string WHITE_LIST_REGEX = @"^[a-zA-Z0-9]*$";
        private const int MIN_LENGTH = 5;
        private const int MAX_LENGTH = 25;

        public UserNameAttribute()
        {
            // Set a default error message that does not give any information away
            // We don't want an attacker to gain information as to how we build our user names
            // This is a good security measure in cases when the site is not open to the public
            // registration.
            ErrorMessage = "Please enter a valid user name.";
        }

        public override bool IsValid(object value)
        {
            if (value == null)
            {
               return false;
            }
            // Sanity check 1:  Is it a string?
            if (!(value is string))
            {
                return false;
            }

            var userName = value as string;

            // Sanity check 2:  Is it within acceptible norms?
            if (userName.Length < MIN_LENGTH ||
                userName.Length > MAX_LENGTH)
            {
                return false;
            }

            // White List Check
            if (Regex.IsMatch(userName, WHITE_LIST_REGEX))
            {
                return true;
            }

            return false;
        }
    }
}

In order to do proper input validation you have to follow the following rules.

1)  Input is always invalid by default
2)  Input should conform to a known whitelist
3)  Sanity checks should be done to ensure that you only operate on plausible values
4)  Information leakage should be avoided on unauthorized pages

As you can see from the above code, I return false by default.  I use a generic, standard error message to combat (4).  Building white lists are easy with the use of regular expressions.  You can validate almost any type of input.  In the case above, I use a business rule defined in my application to build my white list.  I know that my user names only have letters and numbers.  I can thus enforce this in a white list as shown in the code.  The last check is the one that tests for min and max length.  Although I should enforce this on the form, we all know that the any client side checking can be disabled very easily.  It is easy to build in a check here to make sure that the length of the user name provided meets known business rules.  I could have just as easily incorporated this into the same regular expression that did the character white list.  It would look something like

string fullRegex = @"^[a-zA-Z0-9]{5,15}$";

In this case, my LoginController contains a Login action that takes a LoginModel model.  It is easy to add the above attribute in the LoginModel to provide the necessary protection.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using MvcApplication2.Attributes;

namespace MvcApplication2.Models
{
    public class LoginModel
    {
        [Required]
        [UserName]
        public string UserName { get; set; }
    }
}

Of course, security in layers is the best protection to use.  This example above is just one of the layers that you can use to protect your application.  Now that the input has passed some validation, you can use the user name supplied and check against your database to see if the user actually exists.

Happy validating!