views:

1358

answers:

4

For my web app security I'm using FormsAuthentication / MembershipProvider with a non persistant cookie.

My application interacts with some web services, these also use the Membership providers.

User passwords are hashed in the database.

The problem is the person logged into application the web service needs to authenticate with the web service using his username and password every time a page is loaded. BUT once the user has logged in his password is not retreivable as it is hashed.

I was wondering if the password could be stored securley in the Authentication cookie so that the user can authenticate with the web service.

Or a better idea!

EDIT I LIKE JOHNS IDEA BELOW BUT HAVE 4 COMMENTS ON THE MECHANICS THAT I WANT TO RESOLVE BEFORE GOING DOWN THAT ROUTE...

+5  A: 

The best practice would be to not require the user to authenticate with his username and password on every request.

Instead, on the first authentication, the web service should return some kind of authentication token. This is what should be stored somewhere. I would recommend storing it in Session state, rather than in the forms authentication ticket.

When the ticket from the web service expires, you might consider expiring the Forms Authentication ticket as well, which would cause the user to need to log in to your site again, providing username and password, which you would validate, and then use to authenticate to the web service again, storing the ticket from the web service, etc.

John Saunders
Please state the reason for the downvote. It's not possible to learn from mistakes, if nobody says what the mistakes are.
John Saunders
The approach you suggest sounds ideal for my situation, but I'm unclear on the specifics of how to implement this: 1) Should the WCF service should implement an explicit Login method to authenticate the user name and password and return the authentication token?2)What should the client credential type be?3) What is the recommended mechanism for passing the authentication token in subsequent requests (e.g. as an explicit parameter to each service method, or “behind-the-scenes” like the user name and password would be when using UserName authentication).
AJM
Also 4) Do I need to create a custom security token (http://msdn.microsoft.com/en-us/library/ms731872.aspx) to achieve this?Thanks
AJM
I don't have anything specific in mind. Whatever you want to use as a security token should be fine. A GUID, for instance, might be secure enough, though you might need encryption. I was only trying to address the issue of passing the password back and forth.
John Saunders
I don't know who downvoted, and I don't care. I wanted to know the reason.
John Saunders
+5  A: 

I agree with @John's answer that using throwaway token is better than storing the credentials.

For the token you could generate some random GUIDs and store it in the database.

As an alternative that does not require coordination between your ASP.NET application and the WCF service, you could send a signed document as token.

  1. create an XML or JSON document with signed time, user name, and signer's name (ASP.NET app).
  2. generate a hash of the above document.
  3. sign the hash using asymmetric encryption (use private key).

All WCF has to do is validate the hash and the signature. So this does not involve hitting the same database. Using the signed time, you can expire the token in fixed time.

Edit: The idea is based on public-key cryptography (also known as asymmetric key algorithm, public/private key). If you encrypt something with a private key you can decrypt it back only using the corresponding public key; and if you encrypt something with a public key you can decrypt it only using the corresponding private key. See Implementing RSA in C# for how code would look like in C#. Why is this useful? Because we can use this to implement digital signatures. A digital signature is a way to prove that I and only I wrote something, and no one else.

Following the above mentioned step generates a signature. You first need to define a canonical form of "let this guy in" document. Usually an asymmetric key algorithm can't handle too big input, so you generate a hash out of it, and you encrypt the hash using your ASP.NET application's private key. The resulting signature can only be decrypted using you application's public key. Finally you can package all three components (original document, hash, and signature) into some format like XML or JSON and send it as token.

As an example, let's say you use JSON format for everything. First, the original "let this guy in document":

{"UserName":"Foo","SignedTime":"2009-07-09T00:00:00","Signer":"ASP.NET APP1"}

Next, you generate a SHA-1 hash of the above string, which is byte[] and encode it with modified Base64 encoding or something, which would look something like:

b2YgYW55IGNhcm5hbCBwbGVhc3VyZS4

The above is bogus string, the actual stuff may look longer. You then take the hash byte[] and encrypt it using RSA, which generates another byte[] so encode that too with modified Base64:

mxlIGdlbmVyYXRpb24gb2Yga25vd2xfo34

Finally, you make another JSON document to store all the above.

{"UserName":"Foo","SignedTime":"2009-07-09T00:00:00","Signer":"ASP.NET APP1","Hash":"b2YgYW55IGNhcm5hbCBwbGVhc3VyZS4","Signature":"mxlIGdlbmVyYXRpb24gb2Yga25vd2xfo34"}

The final JSON document becomes your passwordless token. Pass it to WCF service. The WCF service takes the token, construct the original document by removing the hash and signature:

{"UserName":"Foo","SignedTime":"2009-07-09T00:00:00","Signer":"ASP.NET APP1"}

Follow the same algorithm to generate the hash and verify it's the same. Decrypt the Signature using the public key of the ASP.NET app and see if it becomes the hash. At this point, the document is verified to be signed by the signer. Check the current time and the signed time and see if the token is still valid. All you need is a way to distribute public keys between two code base, which could be loaded from XML.

eed3si9n
+1  A: 

On the web application you set up the Authenticate event of the Login control to instantiate a new service proxy and set the username/password in the ClientCredentialsin the proxy.

Now when you make the call to the Service through the proxy WCF will pass these credentials through the secure channel to the service and use them for authentication.

Now you simply need to store the proxy in session and use it for future access to the service as it has the channel state and a private key.

protected void LoginControl_Authenticate(object sender, AuthenticateEventArgs e)
{
    bool Authenticated = false;
    try
    {
        MyServiceClient proxy = new MyServiceClient("MyServiceEndpoint");
        proxy.ClientCredentials.UserName.UserName = LoginControl.UserName;
        proxy.ClientCredentials.UserName.Password = LoginControl.Password;

        //It doesn't really matter what is called or what it does because 
        //Membership Provider for the Service does the authentication.
        string retval = proxy.login("Logging in"); 

        //Now that channel is established the proxy needs to be kept
        //since it contains the channel state which includes a private key
        Session["MyServiceProxy"] = proxy;  
        Authenticated = true;
    }
    catch (Exception ex)
    {
        //Login Error...
    }
    e.Authenticated = Authenticated;
}
RonnBlack
Storing the credentials in the proxy sounds OK but, just being curious, the following would only be true if the web service is accessed using HTTPS, right? *WCF will pass these credentials through the secure channel* and *use it for future access to the service as it has the channel state and a private key*
Arjan
Yes, you need to configure a secure channel between the web tier and the service but it doesn't have to be HTTPS. WCF provides multiple mechanisms for securing this channel. There is a thread discussing these options here: http://stackoverflow.com/questions/232500/how-to-configure-security-when-calling-wcf-service-from-net-2-0-client
RonnBlack
A: 

My knowledge of ASP.NET is close to zero, but this made me wonder if you understand sessions:

I was wondering if the password could be stored securley in the Authentication cookie so that the user can authenticate with the web service.

If you would somehow need to store the plain password (or any other data) for later use during the same user session, then you should store it in the session object. Such session object lives on the server (well, it could live on the client, like in Ruby on Rails, but then the framework will take care of encrypting and decrypting it). A cookie on the other hand lives on the client, and is transferred to the server for each request, which will be plain text unless using HTTPS. In general, storing sensitive data in the cookie is not safe.

To let the server know which session object to use, the session id is often stored in a cookie on the client, but that id is by itself not revealing any sensitive data. Still, storing the password in the session object on the server may be dangerous as well, especially on shared web hosting. Like I said: I don't know ASP.NET, but for example PHP sessions are often stored as plain text files in some temporary folder, which often is easily accessed by any other web site using the very same shared hosting.

(If you still have to implement the web service that you rely on, and if you want the user to actually approve its usage on his/her behalf, then you might want to look at OAuth, though it currently has an unresolved security issue.)

Arjan
Hmmm, to quote John Saunders from this very same topic: *Please state the reason for the downvote. It's not possible to learn from mistakes, if nobody says what the mistakes are.*
Arjan
My question is very specific and you have gone off an a tangent that is not helpfull to me in answering it. So purely on the basis that your response dosn't deal with the specifics of the question I voted it down.Also you said you had close to zero knwledge of ASP.NET but my question requires a knowledge of this to be answered. I have a very good understanding of session state and so on and so forth and wasn't looking for an explanation.Finally I dont think people need to explain why they downvoted or should be asked to.Its nothing personal :-)
AJM
Well, seeing one's effort to help being downvoted, without knowing why, takes the fun out of trying to help people. (And as a sidenote I disagree in this case. I did reply to the single part of your question that you emphasized yourself. I don't think it was off-topic, nor incorrect. In fact your downvote now makes me feel you indeed do not understand how sessions work, and it seems you don't want to learn that either, for otherwise you would have edited your question? But it doesn't matter, as of course there's many more people reading SO, so any answer is not just for the one who asked.)
Arjan
Bottom line: your answer didnt help me, it may help someone else so they can vote it up if so. If you have to give a reason for downvoting it should be built into SO.
AJM
You're right, not every downvote needs an explanation. But not every answer needs a vote (up or down) either. Up to today, you've been helped with as many as 66 questions here at SO, and have answered only 23. Image you were one of those many who are just around trying to help. When you can tell that people have put some effort in helping you, then please only downvote when off-topic or when wrong. When downvoting for another reason, please explain.
Arjan
It dosn't matter if I've got help 10000 times and never answered any questions, I'm free to use the site as a consumer and it's really nobody elses concern. I would love to have the time to contribute more but I don't.I had a look but I couldn't find any guidance on up voting and down voting. As such I think its reasonable to down vote a question of its not helpfull. I felt your answer was off-topic, you may not agree, but that is the beauty of free will and everyones own personal subjective judgement.
AJM
As your reputation is above 500, you won't see the effect of this change, but you might want to read http://meta.stackoverflow.com/questions/135/encouraging-people-to-explain-down-votes/2373#2373 And above all: I am not trying to say that you should answer more questions. I am just asking to consider how those who do spend time trying to be helpful might feel when being downvoted without any explanation. (Especially when in the end the downvote seems to be the result of a badly formulated question.)
Arjan
Fair enough, we will have to agree to differ on several points but I can in the future explaining a downvote will be something I will consider.
AJM