Showing posts with label Security. Show all posts
Showing posts with label Security. Show all posts

Monday, August 25, 2008

Good Example of How Tricky Security Is - Even for Banks

I signed up for online visa account access today at CIBC, and found a basic security flaw in their registration process.

Here is their form:


The flaw is the last question - the previous balance. The flaw is a simple one - if you call up VISA on the phone and give them the information above, the phone system provides your previous month's balance!

It just goes to show that even a security conscious bank can make easy mistakes when it comes to security and the moral of the story is a simple lesson: make sure you analyze all your access channels for possible leakage of authenticating information before you demand it online.

Friday, July 6, 2007

Creating a Single Sign-On Solution for .NET Part 2

For the past couple days I've been building my single sign-on solution based on my previously posted design.

I built some simple web services that allow for login against a membership profile database using the supplied ASP.NET membership architecture. By registering the membership and logging in, we can provide a token that can be used to represent the logged in user. This token can then be distributed on the URL and passed to partner sites. The partner site can the validate the token and retrieve the membership information through a web service method.

Here is the code:

using System;
using System.Data;
using System.Web;
using System.Web.Caching;
using System.Web.Security;
using System.Collections;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.ComponentModel;
using System.Web.Profile;
using System.Configuration;
using System.Security.Principal;

namespace SingleSignOn.WebService
{

[WebService(Namespace = "http://localhost/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
public class MemberWebService : System.Web.Services.WebService
{
///
/// Logs in a user and provides back a token. Tokens can then be used to regrab the profile data.
///

///
///
///
[WebMethod]
public string registerMember(string userName, string password)
{
if (Membership.ValidateUser(userName, password))
{
Guid token = Guid.NewGuid();
HttpContext.Current.Cache.Insert(token.ToString(), userName, null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(20));
return token.ToString();
}
else
return null;
}

///
/// Validates a token and provides back a membership user in return. If the member isn't found then null is returned.
///

/// Token to validate.
/// MembershipUser object for the mapped user. If token isn't found then null is returned.
[WebMethod]
public MembershipUser validateMember(string token)
{
string userName = (string) HttpContext.Current.Cache[token];
MembershipUser member = Membership.GetUser(userName);
return member;
}

///
/// Returns the current profile object.
///

/// Token to map to a currently logged in user.
/// Array of name value pairs.
[WebMethod]
public object[][] getProfile(string token)
{
string userName = (string)HttpContext.Current.Cache[token];
Hashtable profileHash = new Hashtable();
ProfileBase profile = WebProfile.Create(userName, true);
foreach (SettingsProperty property in WebProfile.Properties)
{
profileHash.Add(property.Name, profile[property.Name]);
}
return toJaggedArray(profileHash);
}

///
/// This doesn't work. I have not yet found a way to update profiles properly in ASP.NET.
///

///
///
///
[WebMethod]
public void updateProfileProperty(string token, string propertyName, string value)
{
try
{
}
catch (Exception e)
{
System.Diagnostics.Debug.Print(e.Message);
}
}

///
/// Invalidate the cache entry containing the token.
///

/// Token representing user
[WebMethod]
public void logout(string token)
{
HttpContext.Current.Cache.Remove(token);
}

private object[][] toJaggedArray(Hashtable ht)
{
object[][] oo = new object[ht.Count][];
int i = 0;
foreach (object key in ht.Keys)
{
oo[i] = new object[] { key, ht[key] };
i++;
}
return oo;
}

private Hashtable toHashtable(object[][] oo)
{
Hashtable ht = new Hashtable(oo.Length);
foreach (object[] pair in oo)
{
object key = pair[0];
object value = pair[1];
ht[key] = value;
}
return ht;
}
}
}


One small technical note - because web services don't support Hashtables, you need to convert these to a more basic array in order to return them. See the getProfile method as an example.

There is one fundamental problem - trying to manage other people's profiles. It seems that the ASP.NET profile management is based on the assumption that you are reading and writing a current logged in user's profile context. However, in this case, we want to be able to proxy the profile data out to the world which means being able to read and write any user's profile data. There doesn't seem to be an easy way to do this in the current profile architecture. You can get a Profile object from the HttpContext, but this is the current logged in user. You can use the ProfileManager class to grab profile objects but it doesn't provide you access to individual properties of the profile. You can load up a profile object using the GetProfile method, but then there is no way to save the profile.

So it seems that if I'm going to use a distributed global profile management system, I'm going to have to build my own. This isn't really a huge problem as the built in profile management system is fairly weak (see my previous post on general problems with the ASP.NET profile) and building a basic profile management system to store name value pairs or serialized objects isn't that difficult.

But the good news is the basic idea of proxying a token across a domain to store a logged in user seems to work in principle. The next challenge is figuring out the best way to secure it so that only valid partner sites can use the service.

Wednesday, July 4, 2007

Creating a Single Sign-On Solution for .NET

We have a basic single sign-on requirement. We need to be able to allow users to login and pass that login to other distributed systems.

Here are the basic requirements:

1. We want to control the master user profile so that we can have access to the data and integrate it into our offline CRM systems.

2. We have a number of partners who provide hosted applications for us that require authentication. We need to provide a mechanism to have a single sign-on for users that can then be passed to to these partners.

3. The partners may have their own profile requirements that are independent of our needs. For example, let's assume we have a partner that provides community forums and saves the user's favourite forums in their profile. Only the partner cares about this information and centralizing it doesn't add any real value.

4. The solution has to work in a distributed, multi-platform environment. The only access to and from the partners and us is through port 80 using either REST or Web Services calls.

5. The domain may not be the same and therefore you cannot share cookies (see http://www.codeproject.com/aspnet/aspnetsinglesignon.asp and www.411asp.net/func/goto?id=5998410 for a solution based on the assumption that you can simply poke the cookie created by ASP.NET)

6. There needs to be a way to transfer state from one server to another in cases where the user is logged in already. If user logs in Site A and then goes to Site B, they should appear to be still logged in.

So here is the basic design:



1. User logs in by calling a login web service method (see this example for a web services method implementation of login). User is now authenticated on the main site.
2. User links to partner site which passes a token representation of the state (we could use the SessionID itself in .NET as a token).
3. The partner site receives the token and calls a ValidateToken web service method. This validates the passed in token and provides back the membership information for the current user.
4. If the partner site collects user information, the site can call the Update web service method to update the master profile.
5. If the user wants to link back from the partner site to the main site, the partner site provides a link back to the main site with the token embedded in the query string.
6. The main site receives the token and calls a ValidateToken web service method. This validates the passed in token and provides back the membership information for the current user.

This basic architecture should work with a couple basic caveats:

1. State needs to be managed centrally with the usual challenges of managing session state in a load balanced environment.
2. There needs to be some security around the token validation service to prevent malicious sites from getting access to the service. There are lots of solutions for this including putting the web services under VPN, including a site authentication mechanism in the web service method, filtering by IP, etc.
3. Each link needs to be dynamically re-written to include the token. If there are lots of existing cross-over points then this could be a challenge.
4. The parsing of the token needs to happen on every page request. In .NET this could be done using an HTTP Module as a central parsing code. Alternatively, you could have a redirect page that all pages link to first with the original target url embedded in a query parameter (this is how typical login pages work for example).
5. There needs to be some mechanism for keeping the state alive so that it doesn't time out. This could again done using an HTTP Module that on every page request does a web service request to validate token to simply keep the state alive.
6. The solution assumes that there is a single backing master profile that distributes profile information. A "peer to peer" type model could be developed but it would be more complicated.

From a look and feel perspective, the solution doesn't require a single login or registration experience but it probably would make sense. Keep the login and registration forms on the main web site and have them redirect back to the partner site if the request is coming from the partner.

Saturday, April 14, 2007

The Biggest Security Threat - Paper and the Front Door

In Information Technology, most of us digital professionals tend to think about security. We spend out energy on making sure that hackers cannot penetrate from the outside, we look at virus/trojan protection and we clamp down on the firewall to make sure data gets in and out. In addition, if we're really effective, we might start to look at internal security such as who has access to data, vendor management, working from home arrangements, etc.

Because we spend most of the time working with technology, many IT folks will forget the most insecure form of data - Paper!

If you want to see what I'm talking about, go in on a Sunday afternoon and walk around the office and snoop on people's desks. See what paper is sitting around their office out in the open. You may be suprised at what's sitting there. There isn't much point in protecting your database if someone in accounting has printed off the data and left it on their desk.

Another basic security problem that no one in IT tends to worry about - the Front Door!

Most companies have a reception area, and if they are really well secured the reception area will act as a gatekeeper to the other floors. However, most receptionists tend to work from 8:30-4:30. In addition, they tend to take lunch breaks and may not have someone to cover them.

So if you want to test your front door, simply go into the office at 8:30, 4:30 or noon and see if you can walk right in. If you can, then you can probably also walk right out with a printer, a laptop, etc. without anyone questioning it. Most workers if they see someone in the office will assume they've been authorized through reception. If you can crack that reception authorization mechanism, you're likely going to get very little resistance from anyone.

So try it out...and if its a problem, shut it down immediately. Laptop thieves for example are in and out in about 5-10 minutes - if they can get through the front door at any time then you're asking for trouble.