Archives

Archives / 2004 / April
  • Writing Secure ASP.NET Session - Dutch

    It has been a long time since I posted something, but here I am again. It's a very busy time right now, some exams, loads of school tasks, some websites, etc..

    And also, a talk I had to prepare for class. One that I'm going to share with you.

    I'll have to dissapoint non-Dutch readers though, the slides are writting in Dutch, as it was a local session. You could always look at the code though.

    The subject was 'Writing Secure ASP.NET'. Covering :

    • Cross-site Scripting
    • SQL Injection
    • Hashing passwords
    • IOPermissions by default
    • Unsafe DSN (DSN with password included)
    The first three demo's code should be obvious. Regarding IOPermissions I showed a file browser that could browse trough the system in default ASP.NET installation. And for the Unsafe DSN, I listed system DSNs, or used a demo DSN, showed the tables in it (MySQL only) and executed a query against it.

    You can find all files here: SecureASPNET.ppt (227k) and Demo.zip (205k).

  • Codezone Magazine

    I just received the 01/2004 edition of the Codezone magazine.

    If you aren't subscribed yet, go get it now! (yes, it's free)

    It's written in English. And I believe it comes from Microsoft Germany (at least, that was where it came from on the enveloppe).

  • Error Reporting To The EventLog - NUnit

    For this article, we're going to write a class to write to the EventLog. To allow us for easy error logging.

    I'm going to use NUnit as well to test our class. You can get NUnint at http://www.nunit.org/. Install it.

    Start by creating a new project called 'EventLogTests', this is a class library. Add a reference to nunit.framework.dll located in the NUnit bin directory.

    Throw out the constructor and add the attribute TestFixture to the class. This will tell NUnit about a new set of tests.

    1namespace EventLogTests {
    
    2 using System;
    3 using NUnit.Framework;
    4 using CumpsD.Tools;
    5 using System.Diagnostics;
    6
    7 [TestFixture()]
    8 public class EventLogTests {
    9
    10 } /* EventLogTests */
    11} /* EventLogTests */
    Now we'll add a method called Initialise, which we mark with the SetUp attribute. This method will be run at the beginning of each test. In here we will create our EventLogger object (which doesn't exist yet).
    1private EventLogger _ErrorLog;
    
    2
    3[SetUp]
    4public void Initialise() {
    5 this._ErrorLog = new EventLogger("MyCatastrophicError");
    6}
    Next thing is setting up NUnit. You can find Visual Studio add-ins vor NUnit, but as I'm having some problems with getting them to work properly I'm using an alternate method. Go to the project properties, configuration properties, debugging. And set Debug Mode to Program, and Start Application to nunit-gui.exe, each time we'll press F5 NUnit will now launch.

    The way of test driven development is to first write a test that fails and then add some code to make the test pass. We have already written a failing SetUp, because the EventLogger class doesn't exist yet, this counts as a failed test as well. So, let's make it pass.

    Create a new class library called EventLogger and create the constructor.
    1namespace CumpsD.Tools {
    
    2 using System;
    3 using System.Diagnostics;
    4 using System.Runtime.Serialization;
    5 using System.Runtime.Serialization.Formatters.Binary;
    6 using System.Security;
    7 using System.Security.Permissions;
    8 using System.Globalization;
    9
    10 public class EventLogger {
    11 private string _ApplicationName;
    12 private EventLog _Log;
    13
    14 public string ApplicationName {
    15 get { return this._ApplicationName; }
    16 } /* ApplicationName */
    17
    18 private EventLog Log {
    19 get { return this._Log; }
    20 } /* Log */
    21
    22 public EventLogger(string applicationName) {
    23 this._ApplicationName = applicationName;
    24 this._Log = new EventLog();
    25 this.Log.Source = this.ApplicationName;
    26 } /* EventLogger */
    27 } /* EventLogger */
    28} /* CumpsD.Tools */
    Let's create our first test. We want to read an EventLog.
    1[Test]
    
    2[ExpectedException(typeof(InvalidEventLogException))]
    3public void ReadLog1() {
    4 EventLogEntry[] EventLogs = this._ErrorLog.ReadLog(this._BadLog);
    5}
    We mark our method with the Test attribute, along with the ExcpectedException, because this._BadLog contains a non-existant logfile, and we want our class to throw an exception when trying that.

    This test fails, because the ReadLog method doesn't exist yet. Let's create it, this requires some more coding, we'll have some private helper methods. SetLog to specify the EventLog we want to read from, and IsLog to check if the EventLog actually exists.
    1private bool IsLog(string logName) {
    
    2 return EventLog.Exists(logName);
    3} /* IsLog */
    4
    5private void SetLog(string logName) {
    6 if (this.IsLog(logName)) {
    7 this._Log.Log = logName;
    8 } else {
    9 throw new InvalidEventLogException("Invalid Logfile.");
    10 }
    11} /* SetLog */
    12
    13public EventLogEntry[] ReadLog(string logName) {
    14 this.SetLog(logName);
    15 EventLogEntry[] EventLogs = new EventLogEntry[this.Log.Entries.Count];
    16 this.Log.Entries.CopyTo(EventLogs, 0);
    17 return EventLogs;
    18} /* ReadLog */
    This code on it's own will still fail, because there is no InvalidEventLogException! Let's add a class in the same file defining the Exception.
    1[Serializable()]
    
    2public class InvalidEventLogException: Exception, ISerializable {
    3 public InvalidEventLogException(): base() { }
    4
    5 public InvalidEventLogException(string message): base(message) { }
    6
    7 public InvalidEventLogException(string message, Exception innerException): base (message, innerException) { }
    8
    9 protected InvalidEventLogException(SerializationInfo info, StreamingContext context): base(info, context) { }
    10
    11 [SecurityPermissionAttribute(SecurityAction.Demand,SerializationFormatter=true)]
    12 public new void GetObjectData(SerializationInfo info, StreamingContext context) {
    13 base.GetObjectData(info, context);
    14 }
    15} /* InvalidEventLogException */
    When we run our test now, the EventLogger will throw an Exception and our test will pass, because we were expecting an exception.

    Write a test with a valid EventLog name as well, and make it pass, the code shown above will work.

    We also want a WriteLog method, to actually log our errors, so let's make a test for that.
    1[Test]
    
    2[ExpectedException(typeof(InvalidEventLogException))]
    3public void WriteLog1() {
    4 this._ErrorLog.WriteLog(this._BadLog, "This is a test entry");
    5}
    6
    7[Test]
    8public void WriteLog2() {
    9 string ErrorMessage = this._ErrorLog.WriteLog(this._GoodLog, "I have encountered a catastrophic error!");
    10 EventLogEntry[] EventLogs = this._ErrorLog.ReadLog(this._GoodLog);
    11 Assert.AreEqual(ErrorMessage, EventLogs[EventLogs.Length-1].Message, "Wrong Error.");
    12}
    The WriteLog1 method is similar to the ReadLog1 method, it tries to write to an invalid EventLog and will fail. The WriteLog2 method however tries to write to a valid EventLog , and checks if the error is actually written afterwards.

    Both tests will fail, because we'll write the methods now.

    I have created an enum for the three types of EventLogEntries, Information , Warning and Error. Along with an overload for WriteLog so it would write an Error by default.
    1public enum ErrorType { Information, Warning, Error }
    
    2
    3public string WriteLog(string logName, string errorMessage) {
    4 return this.WriteLog(logName, errorMessage, ErrorType.Error);
    5} /* WriteLog */
    Our real WriteLog method will check for a valid EventLog and then write the Entry to the EventLog and return the error message it has written, so we can compare in our test.
    1public string WriteLog(string logName, string errorMessage, ErrorType errorType) {
    
    2 this.SetLog(logName);
    3 EventLogEntryType LogType;
    4 switch (errorType) {
    5 case ErrorType.Information: LogType = EventLogEntryType.Information; break;
    6 case ErrorType.Warning: LogType = EventLogEntryType.Warning; break;
    7 case ErrorType.Error: LogType = EventLogEntryType.Error; break;
    8 default: LogType = EventLogEntryType.Error; break;
    9 }
    10 this.Log.WriteEntry(String.Format(CultureInfo.InvariantCulture, "{0} caused the following error:\n{1}", this.ApplicationName, errorMessage), LogType);
    11 return String.Format(CultureInfo.InvariantCulture, "{0} caused the following error:\n{1}", this.ApplicationName, errorMessage);
    12} /* WriteLog */
    If we run our tests now, we'll see they succeed. I have added some more tests to check if the Entry type was written correctly.

    At the end you should have something like this:



    And when you check eventvwr.msc you will see something like:



    As always, I've uploaded the sources so you can check them on your own.

  • FrontPage Server Extensions - IIS Metabase

    Currently I'm playing around with IIS and C#, and something I discovered is the following:

    First, take a look at the FrontPageWeb property available in the IIS Metabase.

    This says 'Setting FrontPageWeb to true causes FrontPage Manager to create the files required for FrontPage Server Extensions. Setting FrontPageWeb to false causes these files to be deleted.'.

    Everything seems allright, just like every other property I set this to true and except it to work. Like this:

    1// First we get the AD object representing our webserver
    
    2DirectoryEntry iisServerRoot = new DirectoryEntry("IIS://localhost/W3SVC");
    3
    4// We create a new site on the specified siteId
    5DirectoryEntry deNewWwwSite = (DirectoryEntry)iisServerRoot.Invoke("Create", "IIsWebServer", 10);
    6
    7// Takes care of FrontPage Manager providing files for FrontPage Extensions
    8deNewWwwSite.Properties["FrontPageWeb"][0] = true;
    9
    10deNewWwwSite.Invoke("SetInfo");
    11deNewWwwSite.CommitChanges();
    12
    13deNewWwwSite.Close();
    14deNewWwwSite.Dispose();
    (Most stuff left out)

    Well, it didn't work. In IIS it would still say FrontPage Extensions were not present, and the directories didn't get made.

    I looked everywhere to find something else involving FrontPage, without any luck.

    But then I found this KB article (300543). And althou it's talking about IIS 4.0, 5.0 and 5.1, it does work on IIS 6.0 as well.

    So here you go, to install FrontPage Extensions you have to run:
    "C:\Program Files\Common Files\Microsoft Shared\web server extensions\50\bin\owsadm.exe" -o install -p /LM/W3SVC/SITEID -u USERNAME -sp publish

    And to uninstall them:
    "C:\Program Files\Common Files\Microsoft Shared\web server extensions\50\bin\owsadm.exe" -o fulluninstall -p /LM/W3SVC/SITEID -u USERNAME

  • Importance of Error Messages

    .NET gave me an error... A 'Catastrophic failure'.

    What's this? Did somebody ran out of inspiration? Every failure is bad! Should I now throw error messages at users stating:

    • Disastrous failure.
    • Terrible failure.
    • Awful failure.
    • Dreaded failure.
    One of my hard disks crashed two days ago. That is a catastrophic failure!

    To read more on error messages, check this: A Review of Error Messages. Make sure to think about your error messages you're giving your users!

  • Parameterized Queries - MySQL

    Today I was looking over a project I'm working on currently, more specifically, at the SQL queries in it.

    I come from a PHP background, where there is no such thing as parameterized queries. You simply build your own SQL string and make sure it doesn't contain anything harmful.

    So, not having heard of such thing as parameterized queries, I created my SQL statements the same way in C#, until I read about this practice being "not done". So, I wanted to fix it.

    I'm using MySQL with the MyODBC driver. But MySQL is tricky, it doesn't support named parameters, so you have to use a question mark and add parameters in the right order.

    No problem I thought, this would be a one-minute fix.

    This is what I had (I returned an SQL query string at first):

    1return String.Format("INSERT INTO zosa_Users(UserVNaam, UserNaam, UserKlasNr, UserKlas) VALUES('{0}', '{1}', {2}, {3});", strFName, strGeslacht, intKlas, klKlas.Id);
    And I changed it to:
    1OdbcCommand insertCmd = new OdbcCommand("INSERT INTO zosa_Users(UserVNaam, UserNaam, UserKlasNr, UserKlas) VALUES('?', '?', ?, ?);", zosaDb); 
    
    2insertCmd.Parameters.Add(new OdbcParameter("", strFName));
    3insertCmd.Parameters.Add(new OdbcParameter("", strGeslacht));
    4insertCmd.Parameters.Add(new OdbcParameter("", intKlas));
    5insertCmd.Parameters.Add(new OdbcParameter("", klKlas.Id));
    6return insertCmd;
    What did this insert in my database? Well it added a question mark ;)

    So, I went looking for what was wrong... Did I add my parameters in a wrong way? Is there something wrong with MyODBC? After having done about everything I could think of, it was in the middle of the night and I went to bed. But today I tried something else, remove the single quotes. And it worked!
    1OdbcCommand insertCmd = new OdbcCommand("INSERT INTO zosa_Users(UserVNaam, UserNaam, UserKlasNr, UserKlas) VALUES(?, ?, ?, ?);", zosaDb); 
    
    2insertCmd.Parameters.Add(new OdbcParameter("", strFName));
    3insertCmd.Parameters.Add(new OdbcParameter("", strGeslacht));
    4insertCmd.Parameters.Add(new OdbcParameter("", intKlas));
    5insertCmd.Parameters.Add(new OdbcParameter("", klKlas.Id));
    6return insertCmd;
    Such a small thing, but nowhere I managed to find this, nobody ever posted to watch out for this. Having no previous experiences with parameters and the question mark, I simply thought it would safely replace the ? with my value, but still would require the quotes for string values.

    Don't make the same mistake! It's a stupid one ;)

  • Visual Basic 6 - DBGrid, Empty Cells AllowSizing Bug?

    Run your code, and this is what it should look like:



    Now, go to the Custom properties of the DBGrid, to the Layout tab and uncheck 'AllowSizing'.



    Run your program again, and now your DBGrid will indicate there are results, but there will be no text, like this:



    Why is it doing this? I really have no idea. But the best part is, when you check the AllowSizing property again, it isn't back to normal. It stays broken.

    This 'bug' (don't know if it's a bug) was encountered some days ago, I reproduced it this afternoon, and now I installed VS6 SP6, but the bug remains.

    If anyone wants a project which has the bug in it, I uploaded something small (30Kb) that got destroyed by this.

    Anyone who has encountered this as well? And perhaps has an explenation of why it's doing this.

    Update: Just when I posted this and looked at my post again, I noticed something, the second screenshot only had 2 columns, so I realised it did fetch the records, but didn't knew where to display the data. And when you right click and choose 'Clear Fields' it works again. But the AllowSizing is automatically checked on again. To add some value to this post, maybe anyone knows how to uncheck AllowSizing without the grid resetting it's own columns?