Friday, August 13, 2004 6:52 AM
bart
Securing FTP on IIS 6
The machine where my websites are hosted, hosts a bunch of other sites as well (now on Windows Server 2003 finally :-)). In fact every user has his/her own user account to log in to the server using FPSE or FTP to modify the site. However, when using the default website with virtual directories that match the user's names, this seems to work correctly (the user is entering the right folder after the login) but in fact the users are still able to cd .. out of their directory and then cd into another user's directory (only with "list folder contents" rights fortunately since the security on the folder was set tight during the FPSE configuration for the user's site). Nevertheless, this is still not secure enough for our server so I started to read pages 797 to 809 of the IIS 6.0 Resource Kit which was lying on my shelf for quite some time now :-). The good news is that IIS 6.0 supports a concept called "User Isolation" which allows you to set up the FTP site so that users can't see each other's folders (as a result, each user thinks he/she's alone on the box after a log in since cd .. can't go higher in the hierarchy than the user's root folder). When creating a new FTP site, you can specify the isolation mode:
The last option was my choice (since we have AD on the server's network and of course since AD is my big love for the moment). The basics of this isolation mode are rather easy: the user's root folder is retrieved from Active Directory when the user has logged on to the system. Let's take a look at the process:
- user logs in to the server (using ftp.exe for example)
- the system connects to the Active Directory domain on the network (which is specified during the creation of the FTP site using inetmgr.exe or using script) to retrieve attributes of the specified user (and to check the credentials of course)
- the msIIS-FTPRoot and msIIS-FTPDir properties of the user are retrieved and concatenated to form the path to the folder that needs to be opened (this can be a UNC path as well) - see further for an example
- the user is now living in a sandbox and can't leave this folder
By using this technology, it's possible to configure a user to have his folders on a separate machine using a UNC path to another server, just by changing the user's properties in the directory. Furthermore, when you install a new member server with IIS as a front-end webserver, you just need to set up the Active Directory FTP link (by creating a new FTP Site) and off you go.
You can set the user's FTP properties in AD using the iisftp.vbs script (from %windir%\System32):
iisftp.vbs /SetADProp bart FTPRoot D:\Web
iisftp.vbs /SetADProp bart FTPDir \bartdesmet.net
Which will cause the directory to refer to d:\web\bartdesmet.net. If I decide to put the files on another machine, I just need to change the FTPRoot now. Another advantage of this approach is that you can point to whatever path you want for a particular user, so you don't need to have a strict hierarchy of folders (such as ftproot\thedomain\theuser being the FTP folder for the user "thedomain\theuser") as this is the case with the "Isolate users" (without AD) option.
The vbs-script is nice, but System.DirectoryServices is much cuter and this really has become routine for me right now to write code for AD manipulations. First of all, I have a query tool:
using System;
using System.DirectoryServices;
class FtpAdQuery
{
public static void Main(string[] args)
{
if (args.Length == 0)
return;
string ldap = args[0];
DirectoryEntry e = new DirectoryEntry(ldap);
DirectorySearcher src = new DirectorySearcher(e, "(objectClass=user)");
SearchResultCollection res = src.FindAll();
foreach (SearchResult r in res)
{
DirectoryEntry f = r.GetDirectoryEntry();
Console.WriteLine(f.Name + "\t" + f.Properties["msIIS-FTPRoot"].Value + f.Properties["msIIS-FTPDir"].Value);
}
}
}
and secondly I have a manipulation tool as well to set the root for every entry in the directory (in fact, I just need to specify the LDAP path to the location in AD where I'm storing the web users, in my case this is a root-level OU called "Web Users"):
using System;
using System.DirectoryServices;
class FtpAd
{
public static void Main(string[] args)
{
if (args.Length == 0)
return;
string ldap = args[0];
string root = (args.Length >= 2 ? args[1] : null);
DirectoryEntry e = new DirectoryEntry(ldap);
DirectorySearcher src = new DirectorySearcher(e, "(objectClass=user)");
SearchResultCollection res = src.FindAll();
foreach (SearchResult r in res)
{
DirectoryEntry f = r.GetDirectoryEntry();
Console.WriteLine(f.Name);
if (root != null)
{
f.Properties["msIIS-FTPRoot"].Value = root;
f.CommitChanges();
}
}
}
}
All this code was editor-free and built through notepad.exe and csc.exe (without compilation errors :-)). That was it for today (in fact, two days seem to be merged again due to overnight work) on the field of System.DirectoryServices. More to follow later. My bed is waiting now...
Del.icio.us |
Digg It |
Technorati |
Blinklist |
Furl |
reddit |
DotNetKicks
Filed under: Microsoft