C# Tutorials and offshore development in India
    Tutorials   Resources   Forum   Reviews   Communities   Interview   Jobs   Projects   Training   Your Ad Here    
Silverlight Games | Mentor | Code Converter | Articles | Code Factory | Computer Jokes | Members | Peer Appraisal | IT Companies | Bookmarks | Polls | Revenue Sharing | Lobby | Gift Shop |


Prizes & Awards
My Profile



Active Members
TodayLast 7 Days more...






Resources » Articles » .NET Framework »

Securing Remoting Calls and Validating Client


Posted Date: 17 Oct 2004    Resource Type: Articles    Category: .NET Framework
Author: N.T.GopalakrishnanMember Level: Gold    
Rating: 1 out of 5Points: 10



Click here to download

Introduction



This happened in my project. We were making a smart-client application, where the assemblies will be installed to a central, Remoting server. The client, when it connects to the server, will download the assemblies that are not there already or those assemblies that have been updated on the server. And we are making it like a framework and so authorized third-party vendors can also come in to the picture. They can also make their own assemblies, which should be part of the server and then downloaded to the client. Also, much application-specific information, including the SQL connection information, will be downloaded via an XML “catalog”.

The Risk



And there comes a risk. The risk of “somebody else” (in other words, any “un-authorized application) trying to connect to our Remoting server and downloads the information. Or it can be such that those “un-authorized” applications, referencing our assemblies and then trying to download the information through the back-door entry. We needed a way to prevent anything of this kind happening.

Thoughts on different security aspects



We needed a custom security mechanism to prevent this. Thinking about such a security mechanism and I already had to take care of the following things in my mind.

  • I first thought of using the StrongNameIdentityPermission attribute, given by the .NET framework itself. But the problem is that we are allowing third party vendors to develop around our framework and hence assemblies with different strong-name public key need to call other assemblies. The StrongNameIdentityPermission attribute allows only strong named assemblies with one public key to call the assembly in question.


  • There were already some Remoting objects created. Specifying a security mechanism should be made easily applicable to those and of course to future objects.

  • There should be a centralized way to bring a security mechanism where the Remoting objects should not worry about it, but a layer above it should. So that changes to those security features can be made easily (Remember that the security feature is not complete at any point of time. It is of evolving in nature).


  • And this is how I decided to move on…



    Now, it became clear to me that to secure the Remoting calls, we need to validate the client. There should be some information to be sent from the client, on which the security mechanism has to validate it. And it should be foolproof too. Because I am asking the client itself to tell the truth!! (And which era I am living in, meanwhile?). Also, not all methods of all Remoting objects can worry about calling a method to validate the client (and my colleagues were not ready to change all their code too, to be honest!!). After taking care (read “worrying”) of all these things, I arrived at this kind of a security mechanism.

    The Security Mechanism



    The remoting client, for each call, will set the Stack Trace of the client into a Call Context Data. For more information of what is Call Context Data and why it is used, please refer my earlier articles. The Stack Trace is the one, which the client cannot alter (but can reduce the number of stack frames, which is again a potential risk. We will discuss this later in the article).

    The call context data will get passed to the server for every remoting call. The server, on the other side, will take the stack trace from the call context data. Then, the server will take each assembly of the stack trace, check its public key and verify the same with the server side assembly’s public key. If they are same, the call is allowed (meaning only our assembly has made the remoting call). If the client assembly is not having a public key or it is different from the server side assembly, we assume that something is wrong and we throw a Security Exception to the client. The same is the case if the Stack Trace is not sent at all by the client.

    Well, the approach is OK. But who will take care of the validation done on the server side? Will every method of every Remoting object do that? Or is there a way to commonly tackle this?

    The answer is Yes. The solution is to “Intercept” the Remoting calls that come to the server, before the actual method is called on the Remoting object. We will validate the Stack Trace, decide whether to allow the method to be called or not. If we do not want to, we throw a Security Exception at this point itself. The implementation is done by using DynamicProperty and DynamicSink.

    Intercepting Remoting Calls using Dynamic Property and Sink



    Now, so much explanation have been done in the first half of this article, let’s jump into some technical stuff in the second. If you have decided to go for a sleep by now, please give me a last chance and let me pace up this article by showing the implementation stuff!!

    Dynamic Property



    The System.Runtime.Remoting.Contexts namespace has an interface called IDynamicProperty and IContributeDynamicSink interfaces. While the first one has only one read-only property called Name , the second has also only one method GetDyanmicSink, which returns an instance of IDynamicMessageSink. We will be creating a class that implements both these interfaces. And this is the class that we are going to “Register” for interception. To sum up, our class (called as DynamicProperty) will look like this:


    Imports System.Runtime.Remoting.Contexts
    Imports System.Runtime.Remoting.Messaging
    Imports System.Reflection

    Public Class DynamicProperty
    Implements IDynamicProperty, IContributeDynamicSink

    Private Const SINK_NAME As String = "MyDynamicSink"

    Public ReadOnly Property Name() As String Implements System.Runtime.Remoting.Contexts.IDynamicProperty.Name
    Get
    Return SINK_NAME
    End Get
    End Property

    Public Function GetDynamicSink() As System.Runtime.Remoting.Contexts.IDynamicMessageSink Implements System.Runtime.Remoting.Contexts.IContributeDynamicSink.GetDynamicSink
    Return New DynamicSink
    End Function
    End Class


    Have a look at the GetDynamicSinkmethod. It returns an instance of a class called DynamicSink. But where is it? We will create one now.

    Dynamic Sink



    The DynamicSink class implements an interface called IDynamicMessageSink. This has two methods - ProcessMessageStart and ProcessMessageFinish. If you have guessed correctly, the first method will fire whenever a Remoting method is going to get called. The next method will fire whenever a Remoting method is called and the call is about to get returned to the client.

    Naturally, we need to intercept the call before it is being actually called by the Remoting object itself. So, we will place our code in the ProcessMessageStart method.

    The DynamicSink class will look like this:


    Public Class DynamicSink
    Implements IDynamicMessageSink

    Public Sub ProcessMessageFinish(ByVal replyMsg As System.Runtime.Remoting.Messaging.IMessage, ByVal bCliSide As Boolean, ByVal bAsync As Boolean) Implements System.Runtime.Remoting.Contexts.IDynamicMessageSink.ProcessMessageFinish
    Try

    Catch ex As Exception
    Throw ex
    End Try
    End Sub

    Public Sub ProcessMessageStart(ByVal reqMsg As System.Runtime.Remoting.Messaging.IMessage, ByVal bCliSide As Boolean, ByVal bAsync As Boolean) Implements System.Runtime.Remoting.Contexts.IDynamicMessageSink.ProcessMessageStart
    Try
    ‘----------------- STEP 1 -------------------------------------------
    Dim Props As ArrayList = CType(CType(CType(reqMsg.Properties, System.Collections.IDictionary).Values, System.Collections.ICollection), System.Collections.ArrayList)

    ‘----------------- STEP 2 -------------------------------------------
    Dim i As Int32
    For i = 0 To Props.Count - 1
    If Not Props(i) Is Nothing AndAlso Props(i).GetType Is GetType(LogicalCallContext) Then
    Dim callcontext As LogicalCallContext = CType(Props(i), LogicalCallContext)
    If callcontext Is Nothing Then
    Throw New Security.SecurityException
    Else

    ‘----------------- STEP 3 -------------------------------------------
    Dim ContextData As ICallContextData2 = CType(callcontext.GetData(“UserInfo”), ICallContextData2)
    If ContextData Is Nothing Then
    Throw New Security.SecurityException
    Else

    ‘----------------- STEP 4 -------------------------------------------
    Dim secHlpr As New SecurityHelper
    If Not secHlpr.IsAssemblyCorrect(ContextData.StackTrace) Then
    Throw New Security.SecurityException
    Else
    Exit Sub
    End If
    End If
    End If
    End If
    Next
    Throw New Security.SecurityException
    Catch ex As Exception
    Throw ex
    End Try
    End Sub

    End Class


    I know I just can’t win your hearts if I don’t explain the things. Just have a look at the ProcessMessageStart method carefully. For a better understanding, I have split up the logic into 4 steps.

    Step 1:

    The ProcessMessageStart method contains an IMessage component. This contains details about the current method call. The IMessage interface has a property called Properties (IMessage.Properties), which is a Dictionary object. This Dictonary object’s “Values” property is an ArrayList of different information. One of them (and presumably last of them) is the LogicalCallContext.

    Step 2:

    So, we are just looping through the properties until we find the LogicalCallContext in the ArrayList. In case we are unable to find one, we just throw a Security Exception from here, which prevents the actual method being called on the Remoting object.

    Step 3:

    Once we find the LogicalCallContext, we are getting the actual data by using the LogicalCallContext.GetData() method. We are just type casting to an instance of ICallContextData2 interface (which is created by us and that contains a property called StackTrace, which contains the client Stack Trace. You can find this file in the downloaded zip file) In case the GetData method returns Nothing, we are again throwing a Security Exception.

    Step 4:

    If we have found one, we are passing this stack trace to a method called IsAssemblyCorrect which loops through the stack trace and check against the same assembly in the server side to see whether both have the same public keys are not. This method exists in a class called SecurityHelper, designed primarily to take care of these things. You can find the class in the downloaded zip file.

    Register the Remoting object for Interception



    Now we have our Interception classes ready, we need to make a small change in our Remoting object’s constructor for this to work. In the constructor of the Remoting object, call the RegisterDynamicProperty method of the Context object. Assume that you have a Remoting object called MyRemotingObject, you would write the following code in the constructor:


    Public Sub New()
    Context.RegisterDynamicProperty(New DynamicProperty(),Me,Nothing)
    End Sub


    And this is all that you need to do for intercepting all the Remoting calls for your Remoting object, MyRemotingObject.

    The Client Side Implementation



    The client side implementation is very simple. Before initiating a call to the MyRemotingObject class, you need to set the Call Context Data. Setting the Call Context Data is very simple. Here is how you should do:


    MyObj = CType(Activator.GetObject(GetType(MyRemotingObject), remotingUrl), MyRemotingObject)

    Dim CallCtxt As ICallContextData2 = MyRemotingObject.CallContextData
    ‘This property will expose the ICallContextData2 interface from your ‘Remoting object.

    CallCtxt.StackTrace = New StackTrace
    ‘Set the client’s Stack Trace to the property

    CallContext.SetData(“UserInfo”,CallCtxt)
    ‘Name should be same as that of the server.

    MyRemotingObject.HelloWorld()

    ‘Calling this method will pass on the stack trace to the server. You
    ‘need to have all the assemblies in the stack trace on the server side
    ‘also. This constraint itself prevents “un-authorized” or Non-Server
    ‘assemblies from calling your code!!




    Stack Trace – A caution



    If the client decides to shave off a part of the stack trace (by using the SkipFrames parameter of the StackTrace constructor, this means that the stack trace may not have the “un-authorized” assembly’s information and therefore, the server would validate fine. The Security Helper class will try to avoid checking for .NET related assemblies (like System.Windows.Forms.dll etc). But what happens if the Stack Trace contains only .NET assemblies? Because the client has “intelligently” taken some frames out, this is another potential risk. Therefore, the Security Helper class, which I have given, will return true only if there is at least one assembly, which is other than the .NET, related assemblies.

    Files For Download



    This article accompanies some files put into a zip file. This zip file contains the following classes:

    SecurityHelper – Which takes care of mapping client and server side assemblies and their public keys respectively.

    CallContextData – Which Implements ICallContextData2 interface

    ICallContextData2 – Interface, which has a property for getting the Stack Trace.

    DynamicProperty – The one responsible for registering ContextBoundObjects.

    DynamicSink – The one where we actually validate the stack Trace.

    Conclusion



    This is one of the most difficult articles I have found to explain. And I know that I may not be convincing in bits and pieces, but I believe that I had done a honest attempt to explain of the difficult parts of Remoting. As usual, I am open to your suggestions and I will do my best to come up with some better approach next time. But until then, bye, bye, folks!!

    Click here to download




    Responses

    Author: Anitha    26 Oct 2004Member Level: Bronze   Points : 0
    Good job at explaining such a complicated topic in so simple terms.....

    Thanks


    Author: Rilov Paloly Kulangara    11 Feb 2005Member Level: Bronze   Points : 0
    My Name is Rilov . I had an opportunity to work in that project which you have mentioned .
    But certain thing i was not able to digest
    Like the application always connecting to the server and updating the components Imagine the condition if you are deploying the same application in a Wide area Net work with lot of clients running.

    Is there any alternative for this

    i was experiementing with the updater.exe codes down loaded from the microsoft site.

    and regarding the deployment of the same in internet
    can u sujest an architecture for deploying the smart client over intranet

    Regards

    Rilov P.K
    Software Engineer
    Larsen and Toubro Infotech
    Mumbai







    Feedbacks      
    Popular Tags   What are tags ?   Search Tags  
    Sign In to add tags.
    (No tags found.)

    Post Feedback


    This is a strictly moderated forum. Only approved messages will appear in the site. Please use 'Spell Check' in Google toolbar before you submit.
    You must Sign In to post a response.
    Next Resource: Coloring Console Window and changing Title of console
    Previous Resource: A glance to C# - What, When, How
    Return to Discussion Resource Index
    Post New Resource
    Category: .NET Framework


    Post resources and earn money!
     
    Related Resources



    dotNet Slackers

    About Us    Contact Us    Privacy Policy    Terms Of Use