I am creating some web services which I would like to secure using a custom (i.e. NOT WS-Secure, etc) method. Currently my plan is to have a method which takes active directory username & password (over HTTPS, of course) to authenticate the user. This method would then get the account SID for that user and encrypt it using a secure but reversible method and pass this back as a security token.
After this the caller will pass the encrypted token as a parameter to each web method as a means of ensuring the caller is authenticated. The token can then be decrypted and turned back into an directory entry (and so confirm their authenticity) fairly trivially. This has the added bonus of allowing methods to absolutely identify the authenticated caller.
However, using the SID from the account, which is normally internal only, has me a little concerned. Is this secure?
EDIT: As I stated below in a comment, I have realised the token needs to be "sessionised" - i.e. it needs to expire to lessen the possibility of token reuse. This would probably be handled by keeping the client session as part of the token.
Right, here goes - it's a long answer...
The problem with doing this going to be that persisting the SID is not going to be enough to be able to reauthenticate the user if you need to perform an action on their behalf (i.e. impersonate that user) - for that you need a OS-provided security token. If you have just the SID you still need the password in this scenario - unless you use reversible encryption in your AD store, which I seriously doubt is the case - and certainly hope that it's not!
Beyond that, there's also the problem that once you encrypt that SID and send it back, it might be safe over-the-wire (as long as we assume that HTTPS is always secure), but not once it's on the client machine.
Somebody can steal the encrypted SID and start making requests as if they were that user.
In my opinion, if you're using AD as your backend authentication store then you should use Negotiate or Kerberos authentication only. The tickets it produces can then be used to impersonate the user if need be; and I don't believe they can be stolen (although in the security world, almost anything is technically possible).
However you might potentially make your web service very difficult to consume doing this - I certainly wouldn't think of coding my own client for these protocols.
Before I say what I might do if I were faced with this, I'll say first that it's not really secure - it's just a bit trickier for someone to mess with whilst also removing the association of the token from the actual user (patterns behind encrypted information are a hacker's best friend). There are also other caveats that I list afterwards:
Use AD as the authentication method but no more, keep track of authentication sessions separately and give them unique keys that do not relate directly to AD SIDs - guids or something like that. That way each time a user authenticates they would get a different core session ID.
I would stamp each session with the time it was created as well as a cryptographically secure unique random salt (a nonce - although it's not being used here in the same way that wikipedia describes it. Use RNGCryptoServiceProvider for this). I would also incorporate some (but not all) information about the client (ip, user agent) in there as well.
I would then construct a token first as a string combining all this information together and then encrypt it using perhaps at least the Rijndael SymmetricAlgorithm implementation with a 128 bit IV and 256 bit key (both of which must be kept very safe and should be generated randomly again using the RNG!).
You send this back to the client and they use it in their requests from then on (until it expires - which it absolutely must do).
When you receive the token you
Authentication sessions should never be open-ended - they should have expiry times to prevent a very old token being able to be used.
And it goes without saying to use HTTPs all the way of course.
All that said - your choice of authentication etc should be proportional to the kind of data being transmitted and the things that people can do. If a hacker isn't going to be interested in your service; or if the environment is completely internal, then crack on with your original idea.
(that's to the power of infinity there)
Whilst I have suggested this solution, it is not secure for many reasons and if there any real secrets involved I wouldn't use it.
It relies on HTTPS to authenticate the server to the client - which is very important before that client hands over their user name and password combination. Take that away and it breaks and, if you manipulate the certificate chain on the client computer can be completely sidestepped as well. It also relies on the HTTPS channel to protect the username/password combination in transit.
We should be going further and introducing message numbering and signatures on the requests to make sure that a client is still who they present themselves to be because IP addresses and headers are easily spoofed. We should also probably be looking at asymmetric encryption using large primes and all that jazz for the password transfer before even HTTPs is taken into account.
So, basically, if it's security-critical - ignore me and consult an expert - do not try and roll your own because you will get it wrong.
If you're only likely to be hacked by a 12 year old geek for no more reason than because that's what 12 year olds do, then my solution might be too heavy and you might as well go with your idea.
Either way - I make no warranty of what can/might happen and I guess in a way this now very long answer is actually saying that you both listen to me and ignore me at your peril :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With