Running with Code Like with scissors, only more dangerous

29Jan/080

The Madness of Remoting

My latest project has been pretty much my first real distributed application – it involves securely storing and encrypting credit card data in a system that makes it nigh impossible to access the information.  It’s actually been really fun, delving into the depths of secure programming and trying to come up with security measures to thwart perceived avenues of attack against the system.

Part of the way that this system works is by encrypting sensitive data as soon as it arrives to the application servers.  However, to prevent recovery of the data should the application servers be compromised, we chose to use a public key infrastructure system – a server elsewhere on the network issues public/private key pairs, and only the public key is stored on the application server.  The private key never actually leaves that server, and specialized trust relationships are configured so that when decryption needs to take place, it happens on the server where the private key was stored, and data exchange requires a secure channel.

The fun part about figuring out how all of this was going to work together was determining where the system lived.  One of the kicks about the application is that the encryption keys aren’t allowed to be stored in "plain text" anywhere – they themselves are encrypted, and the encryption key we use to encrypt those is absolutely forbidden from being stored – we keep it in memory throughout the lifetime of the application (it is backed up with a physical backup mechanism that involves division of responsibility).

Well, with the requirement that the key encrypting key could not just disappear, I knew that we couldn’t use ASP.NET to manage it – we’d have a catastrophe in the event that the process recycled.  The obvious solution was to use a Windows Service.  But the only way for a Windows Service to communicate with the outside world (in .NET anyway) is via remoting.

I’d played with remoting a small bit in the past – an app I wrote used remoting to activate objects in another AppDomain so that I could inspect the object for supported interfaces – as far as plugin systems go, it was one of my more in-depth ones.  And I’d achieved my MCTS credential in distributed applications.  But I really had (and I still really don’t have) no idea what I was headed for.

Because I need to manage object lifetime myself, I am unable to use the automatic .NET Remoting configuration scheme; I need to make sure that the server has access to certain services as soon as it starts and until it ends.  I don’t have the luxury of client-activated objects, even singleton ones.  So I need to set up the remoting infrastructure myself; I defined a series of service interfaces in a DLL that will be accessible from both the client and server applications, and then implement the interfaces in the server.  Seems straightforward enough.  Internal to the server-side, I also created an IService interface that defined Start() and Stop() methods – a series of objects that I could control from within the Windows Service and also work with from a factory-style utility class.

Here’s sample code for the Start and Stop methods:

   1:   
   2:          public void Start()
   3:          {
   4:              m_wellKnown = RemotingServices.Marshal(this, string.Format("{0}.svc", m_config.Name), typeof(IEncryptionKeyGeneratorService));
   5:          }
   6:   
   7:          public void Stop()
   8:          {
   9:              if (!RemotingServices.Disconnect(this))
  10:                  throw new InvalidOperationException("Error disconnecting this object.");
  11:              m_wellKnown = null;
  12:          }

In this example, the ObjRef specified by the m_wellKnown field is initialized by the call to RemotingServices.Marshal.  The object actually marshals itself, but limits the type hierarchy by specifying exactly which interface it is casting to.  My current class, EncryptionKeyGeneratorService, inherits MarshalByRefObject and implements IEncryptionKeyGeneratorService and IService.  IEncryptionKeyGeneratorService does not inherit from IService; otherwise I would risk allowing a cast to IService, which could compromise the integrity of the application.

The part that I don’t get, and really the whole purpose of this, is to explain why the call to RemotingServices.Disconnect(this) fails.

I always look at it and wonder, "Why did I get an InvalidOperationException?"  And then I realize: it’s because I threw it.

The RemotingServices class is already obscure enough in that calls to Marshal are paired with calls to Disconnect, and that calls to Connect are paired with calls to Unmarshal (but not always… or something).  What I don’t understand is why Disconnect() would ever return false.  It’s pretty clear: I’m telling you to stop acting as an object that can be accessed elsewhere.  You’re not a two-year-old child; stop telling me no.

The really scary part is that I can close out my client application altogether and still have RemotingServices be stubborn.

WHY?

Comments (0) Trackbacks (0)

No comments yet.


Leave a comment

ERROR: si-captcha.php plugin says GD image support not detected in PHP!

Contact your web host and ask them why GD image support is not enabled for PHP.

ERROR: si-captcha.php plugin says imagepng function not detected in PHP!

Contact your web host and ask them why imagepng function is not enabled for PHP.

No trackbacks yet.