Click to See Complete Forum and Search --> : Cookieless stateful web-sessions.


voidinit
11-02-2004, 03:57 PM
Howdy all, long time no see. I'm not sure if anyone around here remembers me, but I use to be kind of a regular before my reserve unit got deployed, but I haven't been back much since then.

That said, I'll get on with the question.

I'm working on a project I just started a while back on sourceforge. Basically, I'm writing a web based j2ee app. This question has very little to do with j2ee. It has more to do with web application session/persistence security in general.

Actually, let me describe the session model I want to implement. I'm looking for the holes that are there that I'm just not seeing.

When a user logs in and authenticates successfully, a session ID is generated for that user by making a digest out of their SSL Client fingerprint and the time they logged in expressed in mills. This digest will then be truncated/or padded to an arbitrary size. The time used for digesting will be stored in a database.

For persistance this session id (SID) will be pasted into every html page (it's all dynamic anyway) that the user requests, and then passed back to the server every time a new http request is made. This application is designed soley for SSL use. That will greatly reduce the risk of a man in the middle or a promiscuous sniff picking up the live SID.

That leaves brute forcing. Say, I truncate/pad the SIDs to a size of 32 bits, and an installation has say 900 active, already authenticated users. The attacker shouldn't have a problem spewing requests with random, or incremented SIDs, once he knows the format of the URL query String and the name of the variables. It probably won't take him long to find an active session and spoof it.


I'm thinking of having the application track requests that ask for bogus or timed out SIDs. When a threshold is reached (Hopefully before the attacker has found a live SID and spoofed it). The application will go into an alert mode and sacrifice speed for security. Basically will re-digest the clients SSL fingerprint and the stored time the client logged in each time a page is requested. If a duplicate is found (i.e. same SID but different SSL fingerprints) the application will invalidate that session ID, thus logging off both the "real" user and the spoofer. After a period of time with no dupes and no requests containing an invalid SID, normal operation woudl resume.

I know that an attacker could spoof an active ID on his first try or on a try less than the threshold, and thus be undetected, but he would have to be extremely, extremely lucky for that to happen. (Like he should have already won the lottery....twice).

Authentication and permissions aside, do any of you see any holes in this method of session management/security that I'm not seeing?

knute
11-02-2004, 04:44 PM
Why not add origionating IP to into the mix as well? That way if you get an SID from a differing IP, it will be flagged right away.

voidinit
11-02-2004, 05:04 PM
Originally posted by knute
Why not add origionating IP to into the mix as well? That way if you get an SID from a differing IP, it will be flagged right away.

Yeah, I thought of this, and I may well code it is an option. However there is one thing that kills this idea every time with a web-based application. That device is a masquerading firewall. It's possible to have two legit users behind the same firewall. To the application it will look like to different SSL fingerprints, usernames, passwords, but one source IP and only one source IP.

If the application implementer knows that all clients should be on the same net, VPNed or whatever, and no one should be behind a firwall, I will most definately give them the option of enforcing that security constraint then.

knute
11-02-2004, 05:10 PM
I've set up a masqing IP Net, and am actually administering one now, but that's not the point.

Let's say that you have 10 connections, and 4 of them are from behind the same firewall.
These 4 connections must have different ssl fingerprints, even though they all have the same IP.

So what I'm thinking is not to use a unique IP address per connection, but rather use the IP address as more of a validation that it's the same client. That way if these 4 connections have IP x.x.x.x and suddenly you get an ip of x.x.y.y with one of those 4 SID's then you KNOW that something is amiss.

Does that make sense or am I missing something?

voidinit
11-02-2004, 05:20 PM
Originally posted by knute
I've set up a masqing IP Net, and am actually administering one now, but that's not the point.

Let's say that you have 10 connections, and 4 of them are from behind the same firewall.
These 4 connections must have different ssl fingerprints, even though they all have the same IP.

So what I'm thinking is not to use a unique IP address per connection, but rather use the IP address as more of a validation that it's the same client. That way if these 4 connections have IP x.x.x.x and suddenly you get an ip of x.x.y.y with one of those 4 SID's then you KNOW that something is amiss.

Does that make sense or am I missing something?

Oh, I get where you are coming from now. I completely misunderstood you the first time. Yes, that is a very good idea. It will be very difficult for an attacker to spoof a three way crosscheck like SIP+SID+SSLFP, not impossible, but difficult enough to convince an attacker to try another avenue of approach. Plus, I think one could match up the SIP and the SID every request with very little overhead, and a check for certain userid's being allowed to login from multiple locations won't be very difficult at all.

bwkaz
11-02-2004, 08:08 PM
Why not just use SHA-512 for the digest?

Then your session IDs are going to be 512 bits long, and there will be more possible distinct session IDs than there are particles in the universe (2 to the 512th session IDs, or approx. 10 to the 170th, and about 10 to the 80th particles, last estimate that I saw). The attacker has to generate a valid 512-bit session ID (for example), when there are only 900 (for example) session IDs that are valid.

That's dang near impossible.

voidinit
11-02-2004, 11:49 PM
Originally posted by bwkaz
Why not just use SHA-512 for the digest?

Then your session IDs are going to be 512 bits long, and there will be more possible distinct session IDs than there are particles in the universe (2 to the 512th session IDs, or approx. 10 to the 170th, and about 10 to the 80th particles, last estimate that I saw). The attacker has to generate a valid 512-bit session ID (for example), when there are only 900 (for example) session IDs that are valid.

That's dang near impossible.

Another excellent idea. Unfortunately I have no idea how to create a SHA-512 in Java.....yet. I'm sure it won't take very long to learn and I'm more than sure that there's a nice little class somewhere out there that does just this.

Every digest needs a seed or a source and I think time of login is a good seed. After that I can still track source IP's and see if one SIP is posing as SID after SID, or if one SID is coming from multiple IP's without explicit permission.

I thought chunking around a 512 bit number would be a bit much, but then HELLO! hex string! All in all I think this is a great start to a decently secure web application.

bwkaz
11-03-2004, 08:14 PM
Originally posted by voidinit
Every digest needs a seed or a source Err? Not all of them do. SHA and MD5 hashes do not require a seed, for example -- they're just a function that operates on the data that you want to hash, and the result of the function is the hash value. The function has no inputs except the message to hash -- that's why you can use md5sum to create a checksum of a file, and then use md5sum again on another machine to check that checksum (same with sha1sum).

If you're using a hash function to store a password, then some password hashing functions do take a seed. But most of the time this seed is just appended (or prepended) to the password, and the result is hashed -- which means that in effect, the seed isn't required.

I think doing SHA-512 on the client fingerprint, current time (or logout time), source IP, and session ID (concatenat all of them, then do the hash) would work fairly well. Unless somebody hits the site from a dial-up link, where the link may have gone down and come back up (thus giving them a new IP address) between hits... Or unless somebody hits the site from a machine with some other kind of dynamic IP address scheme, where they lose their public IP and need to get another one between page hits...

voidinit
11-04-2004, 04:31 PM
Well, I took the SHA512 advice to heart, and did a little research. Thanks to the guys over at Gnu who put together a truly awesome Crypto API for Java, I was able to do this with only a little pain.

At first I had this whole 1 byte = 1 int thing going on in my brain that had me spewing out 380 character Session ID's. Then it hit me..4 bytes = 1 int, and the rest was pretty easy.


import gnu.crypto.hash.HashFactory;
import gnu.crypto.hash.IMessageDigest;

public class HashNames{
public HashNames(){
super();
printDigest();
}
private void printDigest(){
String seed = "jsmith" + "11235897569" + "127.0.0.1";
byte[] input = seed.getBytes();
IMessageDigest md = HashFactory.getInstance("SHA-512");
md.update(input,0,input.length);
byte[] output = md.digest();
String digest4 = new String();
for(int i=0; i<output.length; i=i+4){
int ibyte1 = new Byte(output[i]).intValue();
int ibyte2 = new Byte(output[i+1]).intValue();
int ibyte3 = new Byte(output[i+2]).intValue();
int ibyte4 = new Byte(output[i+3]).intValue();
int piggy = (int)(ibyte4 << 24) + (ibyte3 << 16) + (ibyte2 << 8) + ibyte1;
digest4 += Integer.toHexString(piggy);
}
System.out.println(digest4);
System.out.println(digest4.length());
}
public static void main(String args[]){
HashNames hn = new HashNames();
}
}