Author Archives: Tobint

ASP.NET 2.0 Quickstarts Available

For those of you that don’t know, the ASP.NET 2.0 SDK quickstarts are available.  Obviously, these are just an overview, but it helps to get yourself up and running fairly quickly with features new and old.

Check them out at http://quickstarts.asp.net/QuickStartv20

File uploading in a web environment

A recent question was asked on the ASP.NET forums:

“i’m building a page to let people upload images to my site. they are supposed to see the images after uploading them.
i wondered if somebody can take ane “exe” file, change the extension to “jpg”, upload it, and then run it by pressing the “view picture” button. will my server run this exe file? if yes, how can i check if it image (“jpg” and “gif”) or something else?
great thanks…”

The question actually encompasses a very frequent request that users have. The fact that someone knew to ask about this before just implementing the upload feature proves that the mentality toward securing applications has been changed slightly from “Lets implement as many features as we can” to “How will implementing this feature affect the security of my application”.  This mentality, I feel, is spurred by several factors such as Microsoft’s increased Trustworthy Compupting initiative.

Since I feel its good to reward people for thinking about security first, I will do my best to answer this question for the user here on my blog. In the next few days, I will be launching a series of posts relating to uploading files in a web environment, the security issues, and better ways to implement the feature.  I’ll start by defining the functionality that is ultimately wanted, provide some insight into the various ways to implement this functionality and the security issues surrounding each approach, and then move on to designing a solution and perhaps even provide some sample code.

For now, let’s focus on the functionality and delve a bit into some various ways to implement this feature.

In general, the developer wants users to be able to upload image files to a website, and let someone or several people view the images after they are uploaded. This feature is implemented in the very software that is used to run this blog — Community Server.  Over the years, this feature has been implemented in more ways than I care to count.  Some folks store the uploaded file as is to the file system.  Others have stored the binary data as a BLOB in a database.  Others have used hybrids of this mechanism.  For this portion of the article, we will focus on a file-based approach and follow up with a database approach.

Storing in the File System

The most logical way to store files, it would seem, is in a file system.  From a public internet standpoint, however, one has to consider the trade offs of this approach.  The first problem is that your web user account (most likely the ASPNET account) has to have permission to write to the file system in order to pull this off.  The second issue is that if you write to a file within the scope of your web’s root folder, those files can most likely be accessed through IIS as well (and since this particular user desires for the images to be available to the public, they almost have to be available).  The security concerns are massive.  A user could upload a web-executable script to the server that they could then use as a trojan to gain access to the rest of the server. More advanced hacks could be used to compromise memory buffers and cause an executable to run in the server process (one of the main resons behind the new aspnet_wp running under the context of a low-privileged user).  There are some ways to decrease the risk involved in this method, however.  Some of them involve security through obscurity (not sufficient by itself).  Some of them involve coupling the best of OS security, web security and application security. 

Directory Structure

For starters, consider the fact that you do not want any files that are uploaded to be scriptable on the server side.  So lets set up a directory structure and security for our saved files. Start by creating your main upload directory outside of the web root.  For example, if your web root is found at C:inetpubwwwroot , create your image directory at C:inetpubuploadroot.  So why did we do this?  This prevents anyone from uploading malicious scriptable code to your server that can be executed on the server.  Once you create your directory, make sure you grant read and write permission to ASPNET user (if you are not using impersonation)  or to the Groups and Users which you will allow to upload files.  In my case, I granted the following permissions:

Administrators      Full Control
ASPNET             List Folder Contents, Read, Write
Network Service  List Folder Contents, Read, Write
System                 Full Control

Uploading your File

Once you have set up your directory structure, you’ll need to create your upload page. You only need an HTML file control and a submit button. Once you add your HTML controls, make sure you run them at the server side.

screenshot

Once you’ve set up the page, add the following code to save the file:

private void btnSubmit_Click(object sender, System.EventArgs e) {
 HttpPostedFile file = fleUpload.PostedFile;
 if( file != null ) {
     string serverFilePath = String.Format(   
        @"C:domainstitus.touploadroot{0}",
        file.FileName.Substring( 
        file.FileName.LastIndexOf(@"") ) ); 
        // TODO: Write file validation routine.
        if( ValidateIsJpeg( file ) ) {
           file.SaveAs( serverFilePath );
        }
  }
}

Validating The File

This get’s the job done for uploading, but it still isn’t secure and we haven’t given the user any way to retreive the file.  Now, I’m not an expert in image file types, but I know that each has a format.  I would HIGHLY recommend that you learn the proper methods to validate each file type you intend to accept and write a routine to test the uploaded file against the expected format.  For JPEG files, you can read an online FAQ at http://www.faqs.org/faqs/jpeg-faq/ that will explain the format and give you clues on how to validate this file.   Remember that ALL INPUT IS EVIL and with file uploading, this is particularly important.  However, I’ll leave this implementation up to you since this can get rather complex and will change based on each file type you want to accept. 

In Part #2, we’ll discuss how to retreive images that are stored on the file server using an HttpHandler.

Minutemen Incident — So funny!

msn.com is still set as my home page. This morning there was an article posted that had me chuckling to myself because of the picture at the top of the article.  It was a picture of an ILLEGAL IMIGRANT holding up a T-Shirt. I will never call these people “undocumented workers” so people can help you forget the first thing they do is disrespect our country by breaking the law to get here and disrespecting the many people who stand in line to come here the legal way.

In any case, the funny part was what the T-Shirt said:  “Bryan Barton caught an illegal alien and all I got was this lousy T-shirt.”

I don’t know why it made me laugh so much, but I thought I would share it.

Forms Authentication Cookies in the QueryString

Most folks don’t like their authentication data appearing in the query string, and with good reason. However, one does have to consider some trade offs when enabling cookieless sessions.

A user recently posted the following in an ASP.NET security forum.:

I use Forms Authentication technique in my Web application interactive with mobile devices. The configuration is like the following:

 < authentication mode="Forms" >
   < forms loginUrl="login.aspx" timeout="30" protection="All" path="/" />
 </ authentication >
 < authorization >
   < deny users="?" />
 < /authorization >
 < sessionState mode="InProc" 
      stateConnectionString="tcpip=127.0.0.1:42424" 
      sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes" 
      cookieless="true" timeout="20" />

Mangled URLs are used during sessions due to the cookieless=true setting. But why is the authentication cookie (in my case, its name is ASPXAUTH) also carried in the URIs? I know that this cookies is needed to be present in HTTP headers, but what configuration has defined this cookie is embedded in the query string of the URL like this?

http://localhost/myapp/(wcaz3svlxsdfinygyttuiu45)/default.aspx?__ufps=594900&.ASPXAUTH=887134660EC8D9CE8D72

The answer is simple but again requires you to consider the trade-offs when using cookieless sessions. This behavior is largely in part because the SessionStateModule class writes data to the cookies collection using HttpRequest.AddResponseCookie()

The AddResponseCookie() method looks to see if the cookie collection is null (and it will be if you are using cookieless sessions). If it is null, it will then append the asp.net auth cookie to an internal HttpValueCollection. These values are then written to the QueryString when the handler writes the response back to the user.

The fact that this is an cookie doesn’t go away because it’s a “special cookie”. In fact, what good would your cookie do if it was, in fact, written back in the header? The whole reason behind cookieless sessions is to allow sites to work that don’t support client-side cookies. If someone didn’t support cookies, and your authentication cookie was written back in the header instead of the QueryString, your cookie-based forms authentication cookie wouldn’t work either.

Keep this in mind when enabling cookieless sessions and forms authentication together.

String.Format vs StringBuilder.AppendFormat

So here’s a question, what’s the difference between String.Format( string, object[]) and StringBuilder.AppendFormat( string, object[] ) ?

For those of you thate don’t know, String.Format allows you to parameterize your strings, by placing replacement tokens througout a string template.  You can later fill in those tokens with parameterized data by passing it in as an array. Here is an example:

string.Format("I own a {0} and {1} name is '{2}'", 
        "cat", "her", "Ellie" );

Of course this would output the sentence: “I own a cat and her name is ‘Ellie'”.  You can also achieve the same thing by calling StringBuilder.AppendFormat much like the following example:

StringBuilder sb = new StringBuilder();
sb.AppendFormat( "I own a {0} and {1} name is {2}", 
        "cat", "her", "Ellie" );

At first glance, you may be thinking that these are somewhat interchangable with the exception of performance. By now, we all know StringBuilder is usually faster for excessive string manipulation. What you may not know is that string.format calls the StringBuilder.AppendFormat method under the hood.  Additionally, StringBuilder will throw an exception if the number of parameters does not match the number of tokens found in the template string.  Try compiling and running a program that executes the following statement:

[STAThread]
static void Main(string[] args) {
  string x = string.Format(
    "{4} owns a {0} and {1} name is {2}.", "cat", "her", "Ellie" ); 
  Console.WriteLine( x );
  // For those of you that know WriteLine takes format strings... shhhhh
  // I'm trying to make a point here!
}

You will receive the following exception.

An unhandled exception of type 'System.FormatException' 
occurred in mscorlib.dll

Additional information: Index (zero based) must be greater 
than or equal to zero and less than the size of the argument 
list.

This exception is actually thrown by StringBuilder.AppendFormat and the String.Format method bubbles the exception up without providing the consumer with any recourse if the parameters dont’ match up.  However, if you call StringBuilder.AppendFormat yourself, you can place the code in a try catch block, and reap the benefits of a string that has been formatted as best as it can be with the parameters provided. Take the following code, for instance:

[STAThread]
static void Main(string[] args) { 
  StringBuilder sb = new StringBuilder();
  try {
    sb.AppendFormat( "{0} owns a {1} and {2} name is {3}.",
        new object[] {"Tobin", "cat", "her"} );
  }
  catch(FormatException ex) {
    Console.WriteLine("An exception occurred: {0}", ex.Message ); 
  }
  finally { 
    Console.WriteLine( sb.ToString() ); 
  } 
  Console.ReadLine();
}

Notice here that we have caught the exception, reported on it, but can still write the string builder’s text to the screen — or at least the part that was parsed.

Now here’s the questions I pose for all of you:

  1. Since you now know that you can bypass the token-count to parameter-count validation check by using StringBuilder, should you incorporate this into your applications in instances where you don’t know how many parameters you are going to have?
  2. Would you consider this to be a bug, or a reasonable feature and why?

Resume building: An organized approach

Running a retail store from a high-level is a fairly simple concept. As an owner you keep an inventory of your products and you take note of what is selling, and what is not. You may watch for emerging trends and buy new products that relate. When you notice that a product doesn’t sell well, it might be wise not to buy more of that product. When you notice a product is selling off your shelves quickly, you could increase your profitability by stocking up on that item. Trying to “specialize” in too many products can often times cause your business to fail. You end up with too much stock in products that don’t sell, and not enough stock in products that do. This happens mostly because you can only track so many products effectively.

Running your own career should be very similar to running a business. As owner and operator of your career, you should keep track of the skill set you have — taking note of what is needed in the industry and what is not. You watch for emerging technologies and perhaps learn a little about those skills. When you notice a skill is not in demand, perhaps its time to stop “perfecting” that skill. If a skill is high in demand, you would be wise to learn something about that technology. You should pick an area that you like and are comfortable with and stick with it. Trying to keep track of too many skills at once could leave your knowledge a bit too broad in areas where clients and hiring managers want depth. While each person has a different tolerance level, an individual can keep in-depth knowledge with so many technologies at once.

Assessing your Current Inventory


If you are considering taking another position in the near future step back and start your resume from scratch. Take a completely honest assessment of your skills. Put each skill area you have in a list. One-by-one, add your personal skill level assessment beside the skill using one of the following descriptions: Novice, Intermediate, Advanced, and Expert. Use novice only when you feel you have an understanding of the skill but would have to consistently access a resource if you were asked to do a project with that skill. Use intermediate if you know most of a product and rarely have to look for references. Assign yourself a level of advanced if you know the product inside and out but may not understand all of the underlying architecture. Place yourself as an expert if you push the limits of a technology, know how it works under the covers, and could write a book on the topic if asked to.

Determine Market Trends for your Skills


Once you have your list, set it to the side. Start looking for skills that are hot on the market. Check out monster.com in your area, and others across the nation or the world. Determine what companies are looking for. Pour through each job listing and add skills to a list. When you come across a skill that you have already listed, start counting how many times you found it. Look at the dates of the ads to determine if they are still relevant. If you are a Microsoft developer, you could probably get some assistance by looking at the Microsoft Career Center or even at the Microsoft Job’s Blog.

Determine Your Career Specialty


We often get side-tracked in our careers. We are forced to learn things to fill a job duty and we start picking up more and more knowledge in areas that may not be marketable. We tend to stray away from marketable specialties. Should an unfortunate situation arise and you find the need to look for employment again, you may have a skill specialty that is not high in demand. You would then be forced to take yet another position that isn’t optimal for you and you’ll be right back where you started. As an example, I started a dead-end job learning all about printers, printer drivers and printer languages from a small company in Charlotte, NC. I was actually starting to enjoy writing parsers and tools to make development on the company’s product line better. When I finally decided to leave the company to re-align my career, I found that I had lucked out. I wrote my tools in .NET and gained valuable knowledge and skills, otherwise I would have no marketable skills at all. Look at the specialty and determine what skills are core in that area. List those items and your specialty on a piece of paper and keep it near your computer or on the fridge. Look at it every day to help keep you focused on your goal.

Stock Up!


Once you have a list of your skills and a self-assessment of your skill level, compare it with the list you made of the hot, marketable skills needed to get into your specialty. What are you missing? What are you deficient in? What level of skill do you feel you need to be effective in specializing in that skill area? It should be pretty obvious where you fall short, and where you have unneeded skills. Start finding resources to research and learn everything you can about a subject. Set agressive goals to learn about the details of your specialty. Make sure you learn about the skills that are most important to your specialty and you are deficient first.

Keep your goals in mind and try not to wander off target too far. It’s easy to get side-tracked. If you find yourself reading a lot about a different topic consistently, you might consider switching your specialty to that topic or even positioning yourself under both skill sets. For instance, if you decided to specialize in data access and communications, but often find yourself reading about the compact framework, you might consider specializing in data and communications on the compact framework.

Set aside some time each day to pursue these goals. Make it a part of your every day tasks. 30 minutes to an hour a day should keep you on pace. Of course, if you are more aggressive, you can adjust and plan for as much time as you can spare. Don’t spread your learning plan out too thin though. Your skill marketability may be dwindling as you read. It is important that you invest the time to make sure you stock up on this skill properly. Doing this half-heartedly will do you no good.

Use any valuable resources you can get. There are many sites now that offer blogs owned by Microsoft employees. You can search through many of them at the Microsoft Community Blogs Portal. These can be valuable or a waste of time, check out some of these blog lists and look for employees who talk about the topics you want to know about. Get a news aggregator like NewsGator or SharpReader and subscribe to those blogs. It keeps you from having to click on every link every day to see if something new is available. Sometimes the blogs are broken down into categories too. Consider subscribing to only the categories the blogger offers on your specialty. This will keep you from getting caught up in a ton of personal opinions tossed around every day on blogging sites. Search some popular sites with information on your skills. Participate on community forums. Sometimes helping others with a problem will net you some knowledge in the end. Try to use other’s experience and headaches with a technology as your stepping stone to becoming an expert in your area.

Advertise and Market to your Target Audience


When you are ready to seek a job as a specialist in the area you have chosen, do not just spam your resume everywhere. You will still find yourself back in that old familiar position of doing something you didn’t want to do. Go back to your job sites and search for jobs in that category. Don’t just jump into the first job that is offered to you. Make sure that the job being offered truly does fit the job specialty you want before you send out your resume. Tailor your resume to the specific job at the specific company you are applying toward. Make sure you highlight the skills you have against the skills they need and describe in your cover letter how you feel you might best help the company with their needs. Do not just give your resume to a recruiter who thinks he or she has a position to fit your skill set. Most head-hunters just want to fill the seat and collect the check; they will not scrutinize the employer before sending your resume to them.

Targeting your job search will more likely get the career you want, not just any career you can get. Just like a retail store, it does no good to advertise your gun shop at the democratic national convention. It just isn’t a good use of your time or resources. Use the same common sense when advertising yourself and marketing your resume.

A Dose of Reality


Just like running a store, there is always a dose of reality to add to the mix. Things sound very simple when laid out properly. But the devil is always in the details. Sometimes there is a place to draw a line between learning for work, and learning for fun. Don’t pick a specialty you don’t enjoy just because it’s hot and marketable. In the end, you’ll be miserable and you won’t make an effective specialist. There is something to be said for being poor and happy over having money and being miserable getting it. You may choose to pick a specialty that isn’t as hot as the next skill, as long as you get fired up about it. Make yourself happy with your skills first or your employer never will be.

On that note, I have some career planning to do. Drop me a line if you found this article helpful in any way.

Canonicalization issues and File Paths

I keep running into code lately that does some pretty elaborate security testing but in the end leaves a very large issue unaddressed — canonicalization errors related to file I/O.

Michael Howard and David LeBlanc dedicated an entire chapter in Writing Secure Codeto the idea that “All Input is Evil“. The concept is that you should not rely on the fact that input coming from any source — trusted or not is going to be in a format that you accept. You should validate, validate, and validate again even if your I/O function isn’t intended to access anything of great importance.

Canonicalization is the process of breaking something down to it’s most simple form. Let’s take a look at an example:

public FileStream OpenFile( string fileName )
{
string fullPath = string.Format(@”C:inetpubwwwroot{0}”, fileName);
return new FileStream(fullPath, FileMode, FileAccess);
}

You may have ony intended to give this function access to code stored in the default web root. But what would happen if someone called your function like this:

File f = OpenFile(”..\..\windows\system32\config\sam”);

The elipsis at the begining of the path would direct the file to go up a directory and doing it twice would put the user at your root directory, giving someone access to your entire file system.

You could use a regular expression to check for this type of thing right? Well, yes, but it wouldn’t be enough. Your regular expression would test for the “..\” sequence, but what happens if someone encodes the path with %2E instead of the “.”. Would your regular expression be smart enough to check for that? Probably not. There are a ton of ways to represent a path differently and you should use many different forms of validation. However, one of my favorite is to use the DirectoryInfo and FileInfoFullName” property. Creating a new FileInfo instance passing it your intended path will break the path down into it’s actual meaning. Once this is done, you can use the FullName member to obtain the canonicalized path. As a matter of completion, here is some sample code to get you started:

public FileStream OpenFile( string fileName )
{
string fullPath = string.Format(@”C:inetpubwwwroot{0}”, fileName);
string canonicalizedPath = new FileInfo(fullPath).FullName;
return new FileStream(canonicalizedPath, FileMode, FileAccess);
}

Another option available is to use the Path class as follows:

public FileStream OpenFile( string fileName )
{
string fullPath = string.Format(@”C:inetpubwwwroot{0}”, fileName);
string canonicalizedPath = Path.GetFullPath(fullPath);
return new FileStream(canonicalizedPath, FileMode, FileAccess);
}

This performs the same work under the covers without creating a FileInfo instance.

This example does not explain everything that a dilligent coder worried about security should do to secure this method, but it should demonstrate the usefulness of the FullName member in validating file paths.

Universal Identity a Bad Idea

In a day and age when you are either griping about security or banging out articles on how to increase code security, it’s hard to believe what I saw with my own eyes today. A large and well-known website was looking for a developer to create a universal registration and login service much like Microsoft Passport. The specification called for “seamless integration capabilities into any given website.“

On the surface, these types of services seem like a wonderful idea that prevents someone from having to type in their personal data from one site to the next. Instead, the user would click on a “sign in” button very similar to the .NET passport, they would enter their credentials and data you decide to share with a vendor is magically shared with this site. Microsoft passport requires a rather interesting partnering process in order to get passport authentication on your site. This is supposed to prevent malicious sites from just implementing the “sign in” button and taking your data when you don’t know better.

The problem comes with “seamless integration” and forged sites. It should come as no surprise that Microsoft also has methods that allow passport screens to be thrown into your website’s layout making the login process seem more seamless than redirecting to the passport website itself. This is a very dangerous idea, however. Think about the scenario where you find a gadget you just have to have and, guess what, it’s on clearance for 25% off on this site. You decide to “register” on this site by clicking the login button. The familiar login screen pops up and you enter you r login information.

Have you spotted the problem yet? A crafty individual could create this site that has the same look and feel as the login website. Instead of allowing you to log in as you thought you might, the malware could display an error that would have you believe the site just isn’t working at the moment. No big deal, you go to another site and forget all about this site. The problem is that you have already transmitted your username and login information to this site and that information is now in the hands of an identity thief, and gives a stranger access to any site that uses your login information.

I remember watching a movie (I think it was “xXx“ with Vin Diesel) where a guy drives up to valet parking and hands over his keys. The valet then proceeded to steel the guy’s car. When it comes to embedding a universal login “block” into any page, it just isn’t safe. Anyone can mock up the interface and make it look identical to the login pages that you know and trust. Before you realize what you’ve done, you’ve given someone the “keys“ to any site that uses your login. Personally, I don’t use the same password in any two places. I certainly don’t like the idea of logging into a website just because their login block looks like something I trust.

Keep this in mind the next time you hit eBay and click the passport “sign in” button.

Thinking outside the box

I hate the term “Thinking outside the box.” I hate it more than I hated “new coke”. I hate it more than Gollum hates the “fat hobbit“. I hate it more than christian rap — or any rap for that matter. I hate it more than Saddam hates the familiar “whistle/bang” sound of bombs dropping all around him. OK, you get the point.

This term implies an infinite amount of space to solve a problem. Obviously, the word “box“ implies that you have a problem and a small amount of space from which to solve it. “Thinking outside the box” is stating that you can somehow just ignore the resource boundaries of your problem area. Sure, anyone can solve a problem with an infinite amount of resources “outside of that box“. This is pretty much what big consulting firms do. They can help you shed a million dollars from your corporate budget, but they charge you two million to do it.

This would be like a McGuyver episode where he was trapped in a room full of useless junk and instead of fashioning a device from a shoelace and a candle to open the door he just yelled for help until someone “outside” the room opened the door.

How about changing this term to “solving inside the box”. This is much more important to me. I’d much rather hire someone who can solve a problem given only the resources given to him over someone who can “think outside the box” and require additional resources to complete a task.

Microsoft Calling For Opinions on Dev Certs

Some time ago, I contacted Microsoft and rather rudely voiced my dismay about developer certification. It’s too easy to get, and doesn’t really provide any value as far as an indication of your skill level. The guys in charge of Microsoft Learning have finally given us the opportunity to weigh in on what we feel should be included in the Whidbey certification exams and how they should be changed to reflect today’s developer and hiring manager needs. Additional feedback on what benefits should and should not be included is also welcome!

I’m desperately calling for your help and the help of any developers you may know. Please get the word out about this. Go to [I’ve removed the forums link] and register your opinion! If you would prefer not to join the public debate, please feel free to email your anonymous opinion to tobin@titus.to

I sincerely thank you in advance for your assistance.

Post Navigation