How do I prevent fake credentials when using custom authentication and a desktop application?

How do I prevent fake credentials when using custom authentication and a desktop application?

Old forum URL: forums.lhotka.net/forums/t/8654.aspx


ihate posted on Saturday, March 13, 2010

I have a windows forms application that uses CSLA.net and binary remoting.  Unfortunately I've noticed that a modified client application, or the client application running an a modified environment can have a fake principal/identity.  I would like to solve this using sessions like you would do in asp.net.  

 

Here's an example of what I mean.  

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Reflection;

using System.Text;

using System.Windows.Forms;

using Csla.Security;

using ProjectTracker.Library.Security;

 

namespace FakeAuthentication {

public partial class Form1 : Form {

public Form1() {

InitializeComponent();

}

 

private void Form1_Load(object sender, EventArgs e) {

// Note: I could also call the internal static call PTIdentity.GetIdentity("admin"), but this is more telling:

// Note: can also call (PTIdentity)System.Runtime.Serialization.FormatterServices.GetUninitializedObject(typeof(PTIdentity))

            // as deserialization does, and this doesn't run the constructors

 

var identity = (PTIdentity)Activator.CreateInstance(typeof(PTIdentity), true);

 

// load identity fields:

var propBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance |

                      BindingFlags.FlattenHierarchy;

 

typeof (CslaIdentity).GetProperty("Name", propBindingFlags).SetValue(identity, "Mr. Super Awesome Fake User", null);

typeof(CslaIdentity).GetProperty("IsAuthenticated", propBindingFlags).SetValue(identity, true, null);

var roleList = new Csla.Core.MobileList<string>();

roleList.Add("Administrator");

roleList.Add("ProjectManager");

typeof(CslaIdentity).GetProperty("Roles", propBindingFlags).SetValue(identity, roleList, null);

var principal = (PTPrincipal) typeof (PTPrincipal).GetConstructor(

                              BindingFlags.NonPublic | BindingFlags.Instance,

                              null, new Type[] {typeof (System.Security.Principal.IIdentity)}, null).Invoke(

                              new object[] {identity});

Csla.ApplicationContext.User = principal;

 

 

var form = new PTWin.MainForm();

// remove "show login prompt" check from main form

form.Load -= (EventHandler)Delegate.CreateDelegate(typeof(EventHandler), form, "MainForm_Load");

// call ApplyAuthorizationRules

typeof (PTWin.MainForm).GetMethod("ApplyAuthorizationRules", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(

form, null);

form.ShowDialog(this);

}

}

}

RockfordLhotka replied on Saturday, March 13, 2010

First, if you don't trust the client workstation you should not be using an n-tier architecture, instead you should use a service-oriented architecture.

The web is intrinsically service-oriented - there are two apps - the browser, and the web app on the server. People don't always make that mental separation, but is is very much there. The server never trusts the browser.

This is fundamentally different from an n-tier app, where the tiers are all part of the same application, and thus trust each other to a large degree.

If you don't trust the client, you should make it be a separate app, using services to call another app. Neither app should trust the other, or at the very least the server app shouldn't trust any client app.

The data portal is designed, when running in remote mode, to provide powerful n-tier behaviors, including trust. If you don't trust the client, use the data portal in local mode on the client, and in the DataPortal_XYZ methods have the client app call services to interact with the server app.

This is a major architectural difference, with many ramifications. Not least of which is that the client app needs to authenticate with the server app, and the server will give it an encrypted token, signed and with an expiration. If you want to prevent replay attacks, the server app will provide the client app with a new token on every service call, so any given token is only used exactly once.

Getting real security in a distributed setting is extremely hard. Just ask Valve or any of the other game manufacturers. They fight a non-stop running battle against hackers, because as soon as you think you have all the holes filled a hacker figures out a clever trick.

This is why security is about assessing the threats, the likelihood of those threats, the cost of the threat being exploited and the cost of the threat being mitigated. Only threats with a high enough probability+cost to offset the cost of mitigation are actually mitigated. And that's not a technical descision, it is a business descision, because we're talking real serious money to address anything but the most trivial scenarios.

If you don't trust the client, plan to spend some serious time and money, and hire a security expert - there are only a handful of people in the world actually qualified to combat the hackers, and I'm surely not one of them.

DocJames replied on Sunday, March 14, 2010

Is there a event in the DataPortal where you can check for a condition (e.g. if some custom token / value is available) before doing DataPortal_XYZ?

RockfordLhotka replied on Sunday, March 14, 2010

Yes, there's an authentication hook that is invoked immediately after the client-side request has been deserialized and the server-side context set, but before any non-CSLA code has been invoked (other than the deserialization, which can run custom code if the business class was authored to do so).

I don't remember all the details off the top of my head (I'm on the road), but you implement Csla.Security.I<some interface>, and then set a config file value to tell CSLA the assembly qualified type name of your implementation so it can invoke your code.

This is explained in the last video in the Core 3.8 video series, and I'm pretty sure I discussed it in the Expert 2008 Business Objects book as well.

RockfordLhotka replied on Sunday, March 14, 2010

You might also look into signing your assemblies. The data portal serializes your objects (including your custom principal) between client and server. While not foolproof by any means, you'd certainly make it less convenient for a would-be hacker to alter your code if you sign your assembly, because changing the client-side code would prevent serialization from working between client and server.

ihate replied on Tuesday, March 16, 2010

Thanks everyone for the feedback and suggestions. I'm disappointed that the answer is essentially "Don't use CSLA" mostly because it works quite well otherwise and will be a significant amount of work to change the CSLA or our code.

That said, I don't believe that signing our assemblies will be helpful given the powers of reflection.  For example, I doubt the sample I originally posted would be thwarted by having signed assemblies.  Am I wrong?

 

I imagine the approach I will take will act like web forms, where validation may be done on the client side, but is validated on the server too.  And also in this case the security context will not ever come from the client, but a server-chosen randomly generated session key will be instead.  I'll probably continue to use business objects, but will understand that I can't prevent them from being manipulated in invalid ways on the client (thus, a modified client could read/write any field in a business object... but only business objects they can legitimately access, and only if the changes are otherwise valid).

ajj3085 replied on Wednesday, March 17, 2010

The answer was not "Don't  use Csla," the answer was basically "you need to build two different applications."

Which you would (should) have to do even if you didn't have Csla.

Take Csla out of the mix; you still have the same problem, which is that you can't build an n-tier application because you don't trust the client.  You need to build a client application which communicates with a web service application.  Csla can help you with that.

The suggestion about signing assemblies has nothing to do with reflection; it has to do with the fact that the assembly's full name (which includes its public key) HAS to match on each side, client and server, or serialization will fail.  Its not technically security, but a hacker would be hard pressed to manipulate the client assembly and still have it execute server code.

mbblum replied on Monday, March 15, 2010

CSLA provides the Csla.Server.IAuthorizeRequest. The AppServer's web.config can specify the appsetting key=CslaAuthorizationProvider, which will execute the object specified in Value . It provides an opportunity to refuse the incoming request before the business objects are executed. Look for ServerAuthorizer project in the sample code solutions for an example.

This can provide some protection, though as Rocky notes it has limits.

DocJames replied on Monday, March 15, 2010

Thanks for the info. I will take a look at it.

I'm already signing my assemblies, but thought about adding an extra layer of security. I'm not a security expert either.

Copyright (c) Marimer LLC