Friday, July 03, 2009

Much to my disappointment PHP installs with developer settings by default. This means that the default installation has some potential security holes that need to be tightened after the install.

Any security person will tell you that an application should install in a minimal and locked down  state. I would say 95% of people don’t look to secure something after they install it, they expect it to be secure out of the box. This is what IIS now does and you have to enable any features over the baseline you want.

Doing some simple lockdowns are not hard in PHP though. I am not going to talk about every security feature in the config file, just the defaults that I feel should be changed:

safe_mode=On [Default=Off]
Turning this on makes it so that any file your php file attempts to open MUST have the same UID as the php file that is executing. It also disables or restricts many methods that access or manipulate the filesystem.

safe_mode_gid=Off [Default=Off]
Same as safe_mode but checks the GID instead of the UID. I keep this setting at its default Off state as I want to keep the access restricted to only a user.

open_basedir=[path] [Default=blank]
Restricts PHP to only access files and folders within that path. If all your sites exist in /usr/home/web then I would set open_basedir=/usr/home/web

expose_php=Off [Default=On]
PHP will not write information about itself to HTTP headers. This can help prevent a vulnerable version from being discovered by automatic scripts.

display_errors=Off [Default=On]
By turning this off error messages are not returned to the browser. This prevents information disclosure which is often a precursor to an attack.

log_errors=On [Default=Off]
turning this on logs all the errors to a file or syslog (as specified in the error_log variable)

disabled_functions=show_source, system, shell_exec, passthru, exec, phpinfo, popen, proc_open  [Default=Blank]
This allows you to completely disable certain functions in the PHP runtime that could be potentially used to exploit your system.

enable_dl=Off [Default=On]
Disables the loading of a PHP extension at runtime (i.e. dl('myexploit.so');).

allow_url_fopen=Off [Default=On]
Disables using fopen to open a URL. When left on it is possible it could be exploited to download exploit code from a remote server.

upload_tmp_dir=/var/tmp/php/tmp  [Default=/var/tmp]
I change this so that automated attacks can not find any uploaded files in the default directory. It also enables you to add customized security around the directory that is restricted to its purpose.

session.save_path=/var/tmp/php/sessions [Default=/var/tmp]
Whenever a session is created it is saved to the disk. This could potentially expose the session IDs of all current sessions if an attacker can enumerate them. Changing the folder that the session files are saved to can reduce this risk.

There are also a few limits that you may want to adjust to suit your environment. I find the default memory limit quite high (128MB) but this will differ from environment to environment:

max_execution_time = 30     ; Maximum execution time of each script, in seconds
max_input_time = 60     ; Maximum amount of time each script may spend parsing request data
memory_limit = 128M      ; Maximum amount of memory a script may consume (128MB)

Using Apache to provide additional security

Many php systems ship with files that are used by the application but should never be served out to the application. The common ones are .inc, .sql, and .conf (or .config) files. Also some editors create temp files that end in a ~ and may not get cleaned up properly. We can change our Apache config to deny these files from ever being served:

<FilesMatch "\.(inc|sql|config|conf |.*~)$">
  Order allow,deny
  Deny from all
</FilesMatch>

One of the issues is that with safe_mode set to on an attacker could still write to all files that are owned by that user. Lets take the following example


/usr/home/web/user1/index.php   Owner: nobody
/usr/home/web/user2/index.php   Owner: nobody
/usr/home/web/user3/attack.php  Owner: nobody

Even with safe_mode=On and open_basedir=/usr/home/web, running attack.php could alter index.php in user1 or user2’s directory. I know it is not common to have this kind of scenario where the same user owns all the files but it is quite possible.

I saw a nice workaround somewhere that used Apache to set the open_basedir for each virtual host that looked something like this:

<VirtualHost www.user1.com:80>
  <Location />
    php_admin_value open_basedir "/usr/home/web/user1"
  </Location>
</VirtualHost>


This would basically lock every user into their own home directory which is exactly what you would want in a shared environment.

Suhosin

Suhosin is a two part hardening add-on to PHP. One part patches PHP to help prevent buffer overflows or format string vulnerabilities. The second part is a PHP extension that adds a host of other protections and features. More info on Suhosin can be found on their website.

Wednesday, June 24, 2009

One of the key things in any application is to have an exception handler that logs any unhandled exception so that the application can be debugged in the future.

In many applications I see this done by wrapping every external method in a try / catch block. While this works it has several drawbacks. First of all it is a pain to type the same code over and over again. It is easy to forget to add the try / catch / log block one one method. The biggest pain is if you need to change the way you log you have to change every single instance of that code.

In WCF there is an easy way to intercept all exceptions and log them via adding in by implementing a few simple interfaces that extend WCF.

The first one is the IErrorHandler interface:

 public class ErrorHandler : IErrorHandler
    {
        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
          
        }

        public bool HandleError(Exception error)
        {
            if (!EventLog.SourceExists("Operations")) EventLog.CreateEventSource("Operations", "Application");
            EventLog.WriteEntry("Operations", error.ToString());
            return false;
        }
    }

The HandleError() method will be called whenever an exception occurs. Here we log to the event log and then return false so the error can continue to propagate up the chain. The ProvideFault() method can be used to transform exceptions into faults but for this example we are not going to do any rewriting of the fault message that is to be returned and will leave the method blank.

Next we have to write a service behaviour that will allow us to add our custom error handler for each channel we have a service running on. This is done by implementing the IServiceBehavior interface.

public class ErrorServiceBehavior : IServiceBehavior 
    {
        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
           
        }

        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {
            
        }

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            ErrorHandler handler = new ErrorHandler();
            foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
            {
                dispatcher.ErrorHandlers.Add(handler);
            }
        }
    }

Here we are enumerating all channels and adding the error handler to the collection. We do not need to change anything in the other methods of the interface.

Now we need to do is create a simple behaviour extension element so that we can use the error service behaviour in our config.

 public class ErrorHandlerBehavior : BehaviorExtensionElement
    {
        protected override object CreateBehavior()
        {
            return new ErrorServiceBehavior();
        }

        public override Type BehaviorType
        {
            get { return typeof(ErrorServiceBehavior); }
        }
    }

Lastly we can put the behaviour in the config file for our service.

 <system.serviceModel>
    <extensions>
      <behaviorExtensions>
<!—Add in our custom error handler -->
<add name="ErrorLogging" type="Dispatch.Service.ErrorHandlerBehavior, Dispatch.Service, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c62bf877ee633f38" /> </behaviorExtensions> </extensions> <services> <service name="Dispatch.Service.DispatchService" behaviorConfiguration="Dispatch.Service.Service1Behavior"> <endpoint address="" binding="wsHttpBinding" contract="Dispatch.Service.IDispatchService" /> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> </service> </services> <behaviors> <serviceBehaviors> <behavior name="Dispatch.Service.Service1Behavior"> <serviceMetadata httpGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="false"/> <ErrorLogging /> <!—Name from behaviorExtensions Element --> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel>

As you can see I added the extension to the Extensions element and then placed the name in the behaviour. My assembly is strong named but it should not be required to implement this behaviour (you should just be able to use PublicKeyToken=null if it is not strong named).

Sunday, May 31, 2009

Often you will have tests written that hit a service that is going to be hosted via IIS. On our development box we will probably be using the development webserver that ships with Visual Studio. Often the development webserver is not running when we start our tests which causes a failure. To combat that we have all our service tests inherit from a base class that starts up the webserver if it is not already running. This gives us consistent testability:

    [TestFixture]
    public class ServiceTestBase
    {
        private Process process;
 
        [TestFixtureSetUp]
        public void Start()
        {
            if (!IsWebServerAlreadyRunning())
            {
                const string x86Location = @"C:\Program Files (x86)\Common Files\microsoft shared\DevServer\9.0\WebDev.WebServer.Exe";
                const string non64BitSystemLocation = @"C:\Program Files\Common Files\microsoft shared\DevServer\9.0\WebDev.WebServer.Exe";
 
                //create a normalized path (Path.GetFullPath() will remove our ..\ characters
                string physicalPath = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, "..\\..\\..\\Dispatch.Service\\"));
 
                process = new Process();
                if (File.Exists(x86Location))
                    process.StartInfo.FileName = x86Location;
                else if (File.Exists(non64BitSystemLocation))
                    process.StartInfo.FileName = non64BitSystemLocation;
                else
                    throw new FileNotFoundException("Could not find WebDev.WebServer.Exe");
                
 
                process.StartInfo.Arguments = string.Format("/port:{0} /virtual:\"\" /path:\"{1}\\\"", 50256, physicalPath);
                process.StartInfo.CreateNoWindow = true;
                process.StartInfo.UseShellExecute = false;
 
                // start the web server
                process.Start();
            }
        }
 
        private static bool IsWebServerAlreadyRunning()
        {
            Process[] processes = Process.GetProcessesByName("WebDev.WebServer.Exe");
            if (processes.Length > 1)
                return true;
            return false;
        }
 
        //if you want to stop the webserver after each test fixture is run then 
        //uncomment the following 
 
        //[TestFixtureTearDown]
        //public void TearDown()
        //{
        //  if (process != null)  
        //      process.Kill();
        //}
    }

Wednesday, May 20, 2009

That’s right! After a great event last year we are doing ALT.NET Canada again. This year it will be taking place in Vancouver, B.C. on June 12-14 which is right after DevTeach! In fact we are in the same location as DevTeach so it makes for a great week of training and discussions of some of the best techniques and tools in the industry

Registration is limited to 100 people so get in quick. More info and registration can be found on the ALT.NET Canada Website

Thursday, May 14, 2009

The big talk lately seems to be about parallelism and writing multithreaded code to take advantage of multi-core/threaded processors. While this is a great way to do more tasks at once it is not usually required for the common line of business apps most of us are writing.

Multi-threading is great when you have a big job that can be split appart into chunks for processing on multiple threads. Gaming for instance can benefit a lot from this as gaming is usually a CPU intensive activity. If you are writing a simple app to get things from a database and display it on the screen, multithreading will probably not make a difference in the speed of your app. In fact multithreading may slow down your application as you now have to dedicate CPU resources to creating, managing, and monitoring of threads and that is not free.

Where I love multi-core machines is on boxes that are doing more than one thing. If I am running four non-threaded CPU applications on a four core box then they should perform almost like they were on their own CPU. I almost view having multicore boxes as freeing us from having to write multithreaded code as we are only consuming one core with our apps which leaves cores for other applications. Now I am not saying write sloppy code, just trying to frame what this multicore movement in the industry does for us.

The other thing to realize is that writing multithreaded applications is hard. Worrying about locking, syncing, and race conditions are something I would rather do without. It takes a lot of carefull thought and planning to do it right, and even when you do, missing something can have some drastic consequences. Multi-threaded code is not only hard to design, but hard to debug and test as well.

If you think that you need a multithreaded app then really think about it as it can be a tough road to walk.

Thursday, April 23, 2009

A lot of times we need to know how long a process takes. The simple way to do this is

dim startDate as DateTime = DateTime.Now 

' do work 

dim elapsed as TimeSpan = startDate.Subtract(DateTime.Now) 
Console.WriteLine(elapsed.TotalMilliseconds)

For a general sense of time this works fine but this is not entirely accurate. DateTime.Now pulls from a lower frequency clock and can be off by milliseconds (or more).

To use a highly accurate timing MS introduced the stopwatch  class in .NET 2.0. This class polls the high frequency clock to get accurate timings:

dim timer as Stopwatch = Stopwatch.StartNew

'do work

timer.Stop()
console.WriteLine(timer.ElapsedMilliseconds)

Another thing you can do is call Start() and Stop() on the timer multiple times and it will still keep summing up the time elapsed (just like a regular stopwatch).

 

*DISCLAIMER: This is only a theoretical idea. I have not confirmed that this could increase security of an iterative hash. Please take that into account when reading this.

I was explaining iterative hashing the other day and came up with an interesting theory: Using a weak algorithm may result in a stronger hash. The reason for this is collisions that can happen in algorithms like SHA0, SHA1, and MD5 (a collision is when two separate strings yield the exact same hash). By using a collisionable algorithm in an iterative hash we could potentially throw an attacker way off.

  Valid Attacker
Original Data HelloIAmData 56r335u8425
iteration 1 dfti34548247 fskwrtujrwf
iteration 2 est84354u544 rtietyrt3487
iteration 700 er54djrt5ejh 458432423uitd
iteration 701 dfsujweru5 6483247435u
iteration 702 ase6ae4rha ase6ae4rha
iteration 1000 a473uj4w5h a473uj4w5h

Iteration 701 is where things break down. The hash we had from iteration 702 (ase6ae4rha) has a collision on it. Both dfsujweru5 and 6483247435u will create that hash. In this case the attacker broke ase6ae4rha with 6483247435u not dfsujweru5. Now the attacker tries to break 6483247435u and the hash that results from that which has now put them on the totally wrong path and they will never crack this hash.

Now don't run out and start using a lesser algorithm based on this information collisions do not happen that often. The collisions in SHA1 are only considered theoretically possible as it would take 2^69 operations to find a collision that matches an existing hash (for SHA0 it would take 2^39 operations).

As I do not have the processing power required to do this I can not calculate the chances of this actually happening. Nor can I vouch for if this is a feasible defence strategy.

Monday, April 13, 2009

Source control is such a crucial tool that I will not develop without that I forgot about it when doing the “Thing’s I Can’t Develop Without” series.

For those of you that have never heard of source control (most people have but just in case you have not). It is a simple tool that allows you to check in code to a central repository that records your changes. This allows for several nice features.

  1. Versioning. You can easily view or rollback to old versions of code. This allows us to change or delete whatever we want knowing we can easily rollback the code to its previous state.
  2. Collaboration. It is really easy for multiple people to work on the same code base as the source control system is our central repository. Users can each work on their own tasks and then commit it to the central repository.
  3. Change Tracking. Comments can be added to checkins so that we can see who changed what and why (if the person who checked in the code actually put a comment in that is)
  4. Backup. The code is not just held on one place anymore. It is at least on the source control server and on one (or more) developers machines.

For me a project can not exist without being under source control. Even at home I have a source control system for my projects. I can not tell you the number of times I have used it’s functionality for even the simplest of projects.

There are lots of choices out there. The most common ones in the .NET community are Visual Source Safe, Team Foundation Server, and Subversion. Subversion is our choice so far as it is free and we find it much easier to work with than VSS or TFS. One that is growing in popularity is Git but I have not had the time to play with it yet.

There are lots of great articles out there on all these source control solutions so I will not repeat them.

Thursday, April 09, 2009

I have created a fluent interface around doing builds, allowing users to write build scripts in a simple and terse manner.

The project is hosted at http://code.google.com/p/fluent-build/

It is just the start of the project but thought I would get it out there and get feedback earlier rather than later.

Here is a sample build class:

internal class MainBuildTask
   
{
       
private string directory_base;
       
private string directory_compile;
       
private string assembly_FluentBuild;
       
private string assembly_FluentBuild_Tests;
       
private string thirdparty_rhino;
       
private string thirdparty_nunit;
       
private string directory_tools;

       
public void Execute()
       
{

            directory_base
= Environment.CurrentDirectory;
            directory_compile
= directory_base.SubFolder("compile");
            directory_tools
= directory_base.SubFolder("tools");
            assembly_FluentBuild
= directory_compile.FileName("FluentBuild.dll");
            assembly_FluentBuild_Tests
= directory_compile.FileName("FluentBuild.Tests.dll");
            thirdparty_nunit
= directory_compile.FileName("nunit.framework.dll");
            thirdparty_rhino
= directory_compile.FileName("rhino.mocks.dll");
           
           
DirectoryUtility.RecreateDirectory(directory_compile);
           
CompileSources();
           
CompileTests();
           
RunTests();
       
}
       
       
private void CompileSources()
       
{
           
FileSet sourceFiles = new FileSet().Include(directory_base.SubFolder("src").RecurseAllSubFolders().FileName("*.cs"));
           
CreateBuildTask.UsingCsc.AddSources(sourceFiles).OutputFileTo(assembly_FluentBuild).Execute();
       
}

       
private void CompileTests()
       
{
           
var tools = new FileSet().Include(directory_tools.RecurseAllSubFolders().FileName("nunit.framework.dll"))
                                    
.Include(directory_tools.RecurseAllSubFolders().FileName("rhino.mocks.dll"));

           
Copy.From(tools).To(directory_compile);
           
FileSet sourceFiles = new FileSet().Include(directory_base.SubFolder("tests").RecurseAllSubFolders().FileName("*.cs"));
           
CreateBuildTask.UsingCsc.AddSources(sourceFiles).AddRefences(thirdparty_rhino, thirdparty_nunit, assembly_FluentBuild).OutputFileTo(assembly_FluentBuild_Tests).Execute();
       
}

       
private void RunTests()
       
{
            
Run.Executeable(directory_tools.SubFolder("nunit").FileName("nunit-console.exe")).WithArguments(assembly_FluentBuild).Execute();
       
}


   
}

Saturday, March 28, 2009

It was great to see you all out. Here are the materials from my talks

Threat Modeling
Slides
Xbox Threat Model - Winnipeg
Xbox Threat Model - Calgary

Passwords Are Dying
Slides & Code