Thursday, January 27, 2005

Keeping Attackers Out of the Control Channel

As a rule for writing secure code, you should always keep any potential attackers in the data channel and out of the control channel. I learned that a long time ago, but didn't pay much attention until I went to Keith Brown's talk at Applied XML Developers Conference 5 on 10/21/2004. The following is an example given in Keith's book.

// this code has a really nasty security flaw
void LogUserName(SqlConnection conn, string userName)
{
string sqlText = "insert user_names values('" + userName + "')";
SqlCommand cmd = new SqlCommand(sqlText, conn);
cmd.ExecuteNonQuery();
}

// much more secure code
void LogUserName(SqlConnection conn, string userName)
{
string sqlText = "insert user_names values(@n)";
SqlCommand cmd = new SqlCommand(sqlText, conn);
SqlParameter p = cmd.Parameters.Add("@n", SqlDbType.VarChar, userName.Length); p.Value = userName;
cmd.ExecuteNonQuery();
}

Here is another example.

string cmdToExecute = “search.exe “ + userInput;

Normal users would pass benign strings like “butterfly”, while a malicious user could pass a string that would cause you to launch another program, " net user hacker P@ssw0rd /add". There is a pipe symbol at the beginning of this malicious input.

To keeping attackers out of the control channel, you use the System.Diagnostics.Process class as follows.

Process p = new Process();
p.StartInfo.FileName = @"c:\legacy\search.exe";
p.StartInfo.Arguments = filteredUserInput;
p.Start();

Wednesday, January 26, 2005

Where to store data files?

You should separate program files (executables, DLLs, etc.) from data files! Normal users don't have write permission under the Program Files section of the file system, which means that your program won't be able to write here either.

Then where to store data files? In .NET, you can use the Environment.SpecialFolder enum or the Application class to get directories easily. For examples,
Environment.GetFolderPath( Environment.SpecialFolder.CommonApplicationData) and Application.CommonAppDataPath give you the folder C:\Documents and Settings\All Users\Application Data if you don't provide any info about company, product, and version. You should always provide such infos so that your app can build approriate subfolders.

I learned this from Keith Brown's book.

How To Develop Code As A Non Admin

Developers should develop code as a non-admin. That's because the best way to build software that can be run by nonprivileged users is to run as a nonprivileged user while you write and test the code. I learned that more than three years ago from Keith Brown's column: Security Briefs. But I didn't develop code as a non-admin until recently. In Keith Brown's book "The .NET Developer's Guide to Windows Security", there is a section detailed on how to develop code as a non admin. Here is a short summary on how I do following his suggestions.
  • Create two normal user accounts on Win2k3: WinUser and WebUser.
  • Add both accounts to the Debugger Users group. This will allow me to run the debugging mode using VS.NET if I log in as either account.
  • Add the WebUser account to the VS Developers group. This will grants me write access to \inetpub\wwwroot if I use the WebUser account.
  • I log in my system using the WinUser account if I develop a WinForm app and the WebUser account if I develop a Web app
  • Then I run mstsc to bring up the remote desktop and log in it using my domain account. I minimize this window normally. If I need to do something with the admin privilege, then I bring up this window and do things inside the window.

I like Keith Brown's book very much and take it as my bible on security.


Tuesday, January 25, 2005

You can't directly change boxed values in an array list

Again the following message was one of Ian Griffiths's posts on discuss.develop.com.

Your original code is this:

> ((Parameter)(Parameters[ Pos ])).Length = Length;

and as you observe, this is effectively equivalent to this:

> Parameter p = (Parameter)Parameters[ Pos ];
> p.Length = Length;

But think about what happens on this first line:

> Parameter p = (Parameter)Parameters[ Pos ];

We can expand this some more - this is really equivalent to this:

object boxedCopyInArraylist = Parameters[ Pos ];
Parameter unboxedLocalCopyOfParameter =
(Parameter)boxedCopyInArraylist;

I've chosen my variable names carefully here to make explicit what's going on. Parameters[Pos] will return the object from the ArrayList. Because ArrayList only knows how to store object references, and Parameter is a struct, this will be a reference to a box.

So boxedCopyInArraylist is a reference to a boxed struct. This is the
same box that the ArrayList refers to. However, consider the second line:

Parameter unboxedLocalCopyOfParameter =
(Parameter)boxedCopyInArraylist;

This is where we unbox. unboxedLocalCopyOfParameter is a local variable of type Parameter. Since it's a value type, we are asking to store the whole instance on the stack. Unboxing involves copying the values out of the boxed version and into the instance on the stack. So we end up
with a copy. If we do anything to unboxedLocalCopyOfParameter, we are doing it to that copy, and not to the box.

So we now have two instances of Parameter. There's the boxed instance on the heap, which is what the ArrayList and the boxedCopyInArraylist refer to. And there's also the instance in the local variable unboxedLocalCopyOfParameter. So, two copies. Which one will be modified here:

unboxedLocalCopyOfParameter.Length = Length;

It should be fairly clear that you're modifying the local unboxed copy. You're obviously not modifying the boxed copy that the ArrayList is using. So the effects of this assignment are purely local - this line of code won't change the copy that the ArrayList refers to.

So lets now wind back to your code:

> Parameter p = (Parameter)Parameters[ Pos ];
> p.Length = Length;

What does the second line of code modify here? The boxed copy on the heap or the unboxed local variable? Well again it should be fairly clear that you're modifying 'p', which is a local variable. So this won't have any impact on the boxed copy that the ArrayList refers to.

So finally, consider this:

> ((Parameter)(Parameters[ Pos ])).Length = Length;

What are you asking it to modify here? The boxed copy on the heap, or the unboxed local copy? Well the ".Length" applies to the ((Parameter)(Parameters[Pos])) - so clearly you're modifying the unboxed local copy. The interesting thing about this is that that local unboxed copy doesn't
have a name here. It still exists - you told the compiler to unbox what came back from the indexer, so it'll unbox it. But since you've not told it where to put the result, it'll just allocate an unnamed temporary variable to hold it.

The C# compiler has noticed that you then attempt to set a field on this unnamed temporary variable. While there's nothing strictly wrong with doing that, there's also no point in doing that - you've got no way of getting hold of that local temporary variable after setting the field. So in essence you have said:

(1) Unbox this value to a local temp
(2) Change this local temp value's Length field
(3) Discard this local temp value

It can see that because of step (3), there's no point in performing step (2) because it will have no observable effect. You're changing a field in a value that you have no way of using! So why did it give you that error:

"The left-hand side of an assignment must be a variable, property or
indexer"

Well it's saying that if you were assigning into a named variable, that would be OK. It's also saying that had the assignment been into a property or indexer, it would have honoured it because those are essentially function calls, and it might be that you care about the side effects those calls might have. But since all you were doing is assigning a field, an operation that has no side effects beyond changing the value of the field, and since you have no way of accessing the value in question afterwards, it reckons you probably made a mistake here. Presumably what you were hoping to say was:

(1) Change the Length value on this boxed instance

C# doesn't actually provide a way of doing this. It doesn't have any syntax for operating directly on boxed values. Whenever you try to do something to a value, you always do it either to a local copy of that value in C#, or via a ref. Never to a box.

So what it boils down to is this: you can't directly change boxed values in an array list.

There is a horrible hack that can be used to work around this - the value can implement an interface. This provides you with a way of calling methods and properties directly on the boxed copy without having to unbox it. But this is almost invariably a bad idea. The fact is, if you need to change the value of some specific instance of some type, then you probably don't want to use value types...

Appdix:

private struct Parameter
{
public string Name;
public object Value;
public ParameterType Type;
public int Length;
}

class MyClass
{
private ArrayList Parameters;
//...
void AddBlob(string Column, int Length)
{
//just add new parameter and get his Index
int Pos = AddParameter(Column);

// this gives compiler error
((Parameter)(Parameters[ Pos ])).Length = Length;

// this works fine
Parameter p = (Parameter)Parameters[ Pos ];
p.Length = Length;
}
}

Wednesday, January 19, 2005

Ian Griffiths on UI Thread

The following message was one of Ian Griffiths's posts on discuss.develop.com.

Alois Reisinger wrote:
> Once again some ui thread question.
> Does all the WinForms have to be on the same thread? (i think no).

No - each top level form is allowed to be on its own thread. While people often use the term "The UI thread" as a convenient shorthand, it's slightly misleading, as a Windows Forms application can in fact have several UI threads. (Although in practice a lot of Windows Forms applications only use one thread as a UI thread. In these cases, it makes perfect sense to refer to "the UI thread.")

Note that it's only with top-level windows that you can do this. Everything inside a particular top-level window has to live on the same thread as that top-level window.

Which leads us onto your next question:
> Could there be a problem, if i have a newly created form that
> should be inserted as a child into a mdi parent if they (parent
> and child) were created on different threads?

Yes, that would be a problem.
Here's why. When you add a form as an MDI child of another form, you are effectively doing two things: you are adding the child to the parent's MdiChildren collection, and you are also setting the child's MdiParent property. Doing one of these implicitly does the other for you. If you write this:

child.MdiParent = parent;

then this has the implicit side effect of adding the child to the parent's MdiChildren. Or if you do this:

parent.MdiChildren.Add(child);

then that has the implicit side effect of setting the child's MdiParent property to refer to the parent.

If these two forms have different UI threads, then whichever thread you choose to set up the parent/child association on, it'll be the wrong thread for one or other of them.

And the same problem applies for normal non-MDI parenting too. (Both for Forms and for any other control. And yes, you can nest a form inside another form without resorting to MDI.)

Friday, January 07, 2005

Types of DNS Zones

There are several ways of analyzing DNS zones.

Method a) - There are 3 types (scopes) of DNS Zone
  • Primary - Read and Write copy of all resource records
  • Secondary - Read only copy, gets updates from the primary
  • Stub - New in Windows 2003, just has pointers to another domain. For example NS and SOA and A record of the main server in that Stub domain.

Method b) - There are two types (directions) of DNS Zone

  • Forward Lookup - You know the hostname, DNS tells you the IP.
  • Reverse Lookup - You know the IP, DNS gives you the hostname.

Method c) - There are Active Directory Zones and Secure Zones

  • The advantage of Active Directory Zones is that replication is reduced and is simply added to the regular active directory update traffic. The disadvantage is that this replication only works if the DNS server is also a domain controller. Not a severe limitation.
  • Secure Zones means that only machines with computer records in active directory can update their Host (A) records with DNS servers. With secure zones you avoid lots of rogue records cluttering your DNS records. This can happen if you get visiting laptops which pick up an IP address from DHCP but do not release it because they do not disconnect gracefully from the network.

The contents of this post is copied from

Types of DNS Zones


Export ASP.NET Data to Microsoft Office

Steve Orr gave a talk on Export ASP.NET Data to Microsoft Office at the DotNetUsers group meeting on 01/06/05. Here is a recap from Steve's talk:
  • COM Automation is often the best choice for Windows Formsapplications, but not ASP.NET.
  • HTML output is the simplest approach if you don't need rich clientside support, and it's reasonably scalable too.
  • Steve Orr's Free ExportPanel Custom Web Control is cool.
  • If rich client side support is required (such as VBA functions, interactive charts, multiple sheets) and scalability is a top priority then 3rd party components are often the best choice.

You can get the source code and the pdf file from

http://SteveOrr.net/export.asp

3rd party components can be found at

http://www.aspose.com/

http://officewriter.softartisans.com/

http://www.carlosag.net/


Sunday, January 02, 2005

Three DNS Server Configuration Roles

There are three DNS server configuration roles:
  • Caching-only server
  • Primary server
  • Secondary server

A single DNS server can play multiple roles.

All DNS servers maintain a cache.dns file that contains a list of all Internet root server. Any time a DNS server resolves a hostname to an IP address, the info is added to the cache file.

Caching-only server. Caching-only servers do not contain any zone info. The main purpose of a caching-only server (other than providing name resolution) is to build the cache file as names are resolved. So either hostnames are resolved from the cache or else another DNS server is required to resolve them. Caching-only servers are useful when there are remote locations that have slow-WAN links.

Primary server. A primary DNS server hosts a working (writable) copy of a zone file. A single DNS server can be the primary DNS server for multiple zones.

Secondary server. A secondary DNS server gets its zone info from a master DNS server. The secondary DNS server hosts a read-only copy of the zone file, which it gets from the primary server or another secondary server. Both Win2k and Win2003 support incremental zone transfers. A server can be both a primary and a secondary server at the same time. Secondary servers provide the following benefits:

  • Fault tolerance
  • Reduction in name-resolution traffic
  • Load balancing

Notes are taken from the following book

Implementing, Managing, and Maintaining a Windows Server 2003 Network Infrastructure

Saturday, January 01, 2005

How does DNS resolve FQDNs to IP addresses?

The following process occurs:
  • A DNS request is sent to a local DNS server.
  • Before forwarding the request to a root server, the DNS server checks its local cache to determine whether the name has recently resolved. If there is an entry in the local cache, the IP address is returned to the client.
  • If no entry exists in the local cache, the request is sent by the DNS server to a root name server.
  • The root name server refers the DNS server to a name server responsible for the first-level domain within the hostname.
  • The original DNS server is referred to second-level DNS servers, and then third-level DNS servers, until one of them can resolve the hostname to an IP address and return the results back to the client.

I didn't know the process until now.