Archive for October, 2008

Secure XAMPP by only allowing local access

This site and a couple others are served up on a dedicated server. To make it easy to set up Wordpress, I’m using XAMPP. In this post, I’ll give a quick overview of XAMPP, and then also show you how to secure it so that administrative utilities are only available locally.

XAMPP Super-Quick Overview

XAMPP is basically a quick way of setting up MySQL, PHP, Perl, and Apache. You can download it, extract it, and run it from any location. If you’re not experienced Apache/PHP world, this is the easiest way to get something working ASAP. In the next image, you’ll see the directory structure under your XAMPP directory:

image

Here are the key folders you would probably need to worry about:

  • apache – Contains the installation of Apache.
  • htdocs – Contains the folder that is served up by Apache. If you want to install a web application such as Wordpress, you probably want it in here.
  • mysql – Contains the installation of MySql.

Now, if you simply want to install Wordpress on XAMPP, I’m not going to write yet another tutorial. There are plenty out there, most with screenshots of step-by-step instructions, just Google for them.

Securing XAMPP

Once I configured XAMPP, I stupidly assumed that the utility applications like phpmyadmin would not be publicly available. I was very wrong, and was warned before anyone decided to do something bad.

Most of the instructions I found through Google for securing the utility paths seemed kind of weak to me. They basically work by securing those paths with a password. I’m a little paranoid, so I don’t want those paths remotely accessible at all.

The first thing I did was lock down Apache security so that it’s very restrictive by default (apache/httpd.conf):

<Directory />
    Options Indexes FollowSymLinks Includes ExecCGI
    AllowOverride All
    Order deny,allow
    Deny from all
</Directory>

Make sure that you don’t have any other directory directives in your configuration file that may override this.

Next, in the .htaccess file for each Wordpress installation, I added this line: “Allow from all”. This basically tells Apache that this folder is safe to serve up to everyone.

Now, the problem is that XAMPP has a configuration file that overrides the utility paths and allows access for anyone. To fix this, perform a search and replace in the (in Apache/Conf/Extra) “httpd-xampp.conf” file to change “Allow from all” to “Allow from 127.0.0.1″. Now, all of the XAMPP directories will only be served locally.

Conclusion

My background is certainly not Apache/PHP, but I’m still learning. If I made any mistakes in my configuration, please leave a comment or send me an email.

ASP.NET MVC Pro’s and Con’s

In our current iteration of improving our software development strategy, ASP.NET WebForms simply doesn’t fit in with the new demands of being unit testable and flexible. It comes as no surprise that ASP.NET MVC has been getting all the headlines lately. Like many others, I’ve gotten the itch to try it out. In this post I’ll talk about what I believe are the main pro’s and con’s of the new style for building web applications.

Scale

PRO – No ViewState or "surprise crap"

In traditional ASP.NET WebForms, the luxury of pretending to behave like a Windows Form comes at a price. The ViewState is a reliable way of storing all of the state information for the form. Unfortunately, due to the limitations of the web, this data needs to be a giant string inside of a hidden form field. This ends up adding a substantial number of bytes to the page, making it slower and requiring extra bandwidth. Of course the ViewState is controllable, much like the dinosaurs in Jurassic Park.

Not only is the ViewState gone, but "mystery" generated HTML is also gone. You have strict control over the HTML. This gives you great power, but with great power comes great responsibility. Use it wisely, and you will have elegant XHTML output with no surprises. You need to really know your HTML, which in today’s web world is a prerequisite anyway.

PRO – Faster server-side

It’s hard to get any real performance data about MVC, but it’s been suggested that it’s potentially 8000 times faster. Supposedly it’s due to less processing since it simply processes a "template" instead of having to build a complicated control tree. Even if it’s twice as fast, or even marginally faster, that would be significant for popular sites, or give at least a slight boost to smaller sites.

PRO – Simplified model for multiple related views

One thing that I found much easier to do with MVC was to have multiple versions of a page that displayed the same data, but in a slightly different format. For example, on my RSS package tracking website, you can look at your tracking information in a full-featured desktop browser, a mobile browser, or an RSS reader. The data being displayed is always the same, but the actual rendered output was different. If I later want to make an iPhone specific version for example, I would simply make a new view, and use an existing controller action.

PRO – Unit testable

One of the biggest challenges with WebForms was that testing was difficult. Not only was the actual output not easy to test, but the code-behind would tend to be a place that would contain important code that would never get unit tested. With both MVC and WebForms, it’s best to keep your logic away from the page, but it’s not always easy or ideal. MVC makes it simple to unit test the logic that is specific to a page. To do so, you simply test the actions in your controllers, which are regular, easy to test classes.

CON – Difficult to convert an existing site

MVC is not only a framework in this case, but a style. It is possible to convert specific pages as needed, but the cost is high. The problem is that MVC is radically different, so the benefit of converting probably isn’t worth it for most of your existing pages.

If you decide to convert your site to MVC, you may also run into issues trying to maintain existing page addresses. The specific issue I’ve ran into is that routes cannot have a trailing slash. If you want to maintain existing URL’s that have trailing slashes, there is no way to have the built-in routing generate URL’s with a trailing slash. You may end up losing one of the big advantages that MVC has to offer.

CON – Not best for SEO out of the box

I’ve mentioned some of the SEO issues before, and all but the trailing slash issue have a reasonable workaround. The routing engine likes to allow multiple addresses to render the same page, instead of enforcing a single address for each page. Luckily, as Scott Hanselman mentions, you can use a URL rewrite engine to bend it to your will. I highly recommend spending some time writing intelligent rules that perform the necessary 301 redirects, because you don’t want to take chances with SEO (Search Engine Optimization).

CON – Challenges if you’re not running IIS7

It’s clear that the last couple of versions of IIS have been major improvements over their predecessors. IIS7 takes .NET integration to an entirely new level. There is already a good page that covers the challenges you’ll face if you’re not running IIS6. I’ll just list them here for brevity:

  • .NET needs to handle all page requests to ensure that the MVC pages will be processed. This leads to bad performance of static files.
  • HTTP Compression through IIS6 doesn’t work, because the MVC pages are dynamic.
  • The homepage gives a 404 when hosted on the root of a domain.

Summary

If I needed to build a new site from scratch, and was able to use IIS7, it would be extremely likely that I would choose ASP.NET MVC. It’s a joy to work with (possibly because it’s "new"), and just makes sense. If I needed to work with an existing site, I would certainly have to consider the pro’s and con’s I mentioned above. ASP.NET MVC gives us an amazing new tool in our huge Microsoft toolbox.

Detecting mobile device user agents in ASP.NET

If you’re developing a mobile version of your website, usability should be one of your top priorities. Most sites will detect if you’re using a mobile device, and automatically redirect you to the mobile version. I’m going to show you how to do this in ASP.NET.

Detecting a mobile device based on user agent

The first issue I ran into was coming up with a reliable way to determine if the device is a mobile device based on its user agent. My first urge was to use the detection built into ASP.NET:

Request.Browser.IsMobileDevice

I immediately lost any trust in this property after it failed to correctly identify Opera Mobile on my Windows Mobile phone. I suspect something similar will happen with the iPhone.

After browsing the dozens of common mobile device user agents, I came up with this method:

public static bool IsMobile(string userAgent)
{
	userAgent = userAgent.ToLower();

	return userAgent.Contains("iphone") |
		 userAgent.Contains("ppc") |
		 userAgent.Contains("windows ce") |
		 userAgent.Contains("blackberry") |
		 userAgent.Contains("opera mini") |
		 userAgent.Contains("mobile") |
		 userAgent.Contains("palm") |
		 userAgent.Contains("portable");
}

I realize this method isn’t perfect, but I believe it will correctly identify 99% of the mobile devices out there. You simply pass in the user agent, which is easy to get:

Request.UserAgent

If you want to be a little more precise, you can come up with your own method by looking at the list of mobile agents, or you can use an updated list of mobile devices with detailed specifications. You can find that type of list here.

Have a better way to do it? Have a common device that my method doesn’t work for? Please let me know in the comments!

Response.Redirect and Output Caching Trouble

I ran into an interesting issue with output caching. If you have a page that uses output caching and that page conditionally sends a redirect response, you need to be careful.

Redirect

Let’s say that you have a page that redirects to the mobile version of your website if they have a mobile browser. Let’s suppose that you’re using a standard, generic output caching directive:

<%@ OutputCache Duration="300" VaryByParam="*" %>

When the page renders, the rendered HTML will be cached. The next incoming request will get the cached HTML, and the page rendering and code execution will be completely avoided. If you get a visitor that is using a mobile device, your code to determine if the request should be redirected will never get executed.

Here is another way to look at this scenario:

  • Request #1: Page makes the decision to redirect to another page.
    • Result: Page not cached.
  • Request #2: Page makes the decision to render HTML.
    • Result: This HTML is now rendered and cached.
  • Request #3: Doesn’t matter.
    • Result: The cached HTML from request #2 is rendered, even if the page should be redirecting.

There are a couple of workarounds to keep your redirects working:

Turn off caching

Of course the simplest option is to simply turn of output caching for the page that needs to perform a conditional redirect. It goes without saying that you’ll lose all the wonderful advantages of output caching.

Use a caching seed

Another option is to write some code in your applications "GetVaryByCustomString" method that determines if it’s a request that will be redirected. If so, a unique value is returned. This forces the page to re-render because it is not found in the page cache. Unfortunately, the code in your custom string method may get complicated very quickly.

If you’re lucky, you’ll be making the redirect decision based on something that can be automatically used to vary the output caching. For example, if your page redirects based on a URL parameter, you can simply use the VaryByParam="*" in your output cache directive (or specify the specific parameter). Keep in mind that each set of parameters supplied to the page will result in a separate cache entry. This could lead to excessive memory usage for some pages.

Use fragment caching

Of course you could avoid using output caching on the page itself. You simply use the page as a place for your redirect logic, not the content generation. Then, put the actual page generation logic and content into a UserControl. When you use output caching on that control, it won’t affect the redirect logic in the page. The disadvantage of this technique is that you may have to do extra work separating your content into controls. You also won’t get the full benefit of caching since some of the control tree still needs to be processed, and some parts of the page such as the MasterPage will not get cached.

Conclusion

Remember, this is only an issue if the page being cached makes a decision to redirect. If the page always performs a redirect, the page will not be cached (why are you using output caching then?). Obviously this issue isn’t unique to Response.Redirect, but it is an issue you should be aware of.

One mischievous aspect of this issue is that if you test your site in a certain order, you won’t see a problem. For example, if you first view the page under the circumstances needed to make it redirect, it will work. You’ll only see the issue if you cause it to not redirect, and then try to get it to redirect.

Removing duplicate page addresses in MVC

As I mentioned before, there are a couple of SEO issues with MVC. I’ll discuss two ways to get around the trailing slash issue. Recall what the issue was. MVC will happily serve up your URL’s both with and without a trailing slash:

  • www.test.com/path
  • www.test.com/path/

Search engines could potentially index both paths, and count them separately in their search results. The first solution is to make one of the versions return a 404 (page not found) response code. Hopefully, this would deter anyone from linking to the non-preferred version. We can do this by creating a custom route constraint, by implementing the IRouteConstraint interface:

public class TrailingSlashConstraint : IRouteConstraint
{
	private readonly bool _trailingSlash;

	public TrailingSlashConstraint(bool trailingSlash)
	{
		_trailingSlash = trailingSlash;
	}

	public bool Match(HttpContextBase httpContext, Route route, string parameterName,
		RouteValueDictionary values, RouteDirection routeDirection)
	{
		return _trailingSlash == httpContext.Request.Url.LocalPath.EndsWith("/");
	}
}

Then, when you define the route, supply an instance of the constraint:

routes.MapRoute("mobileVersion", "m",
	new { controller = "home", action = "mobile", id = "" },
	new TrailingSlashConstraint(false));

The second solution is to redirect the non-preferred version to the preferred version. We can do this by either creating a custom HTTP Module, or by using a canned product like the free UrlRewriter.NET.

Should I use a trailing slash or not?

This is one of the problems with MVC. In ASP.NET webforms, you could use a default page to avoid having to specify a file in the URL. This gets you the nice MVC style paths. The good part was that if someone accessed the version without a trailing slash, it would automatically redirect to the version with the trailing slash. So in ASP.NET WebForms, the trailing slash was obviously preferred since it was the default behavior.

Now, in ASP.NET MVC, they decided to make the default behavior the opposite. It does serve up both versions as I mentioned, but when it generates links, they don’t have a trailing slash.

If you’re long term solution is to use MVC, I recommend dropping the trailing slashes, just to avoid the pain. I’m really hoping that by the time the final version of MVC comes out, they’ll give us an option to define routes that should have a trailing slash.