.NET Forum / ASP.NET / Web Services / February 2005
UserNameToken with SendNone on Password
|
|
Thread rating:  |
James Hancock - 09 Feb 2005 19:43 GMT Ok, so I have been looking and looking for a solution that is simple and eligent and easy to mainatain (see previous post) that replaces the WSE 1.0 shared secret stuff. I have read through the post about using UserNameToken and just not passing the password and thus both sides basically use the password as the shared secret.
However, I cannot get this to work. If I set it to SendNone with the password, then I get an error telling me that the soap message encryption isn't the same (basically that's the message).
What am I doing wrong?
I put the password into the constructor for the UserNameToken, and sendNone and on the other side I've overriden the tolken manager and on authentication I return the real password as plain text.
Thanks!
(Sidd: thanks for your comments, if MS had a nice sample for doing shared secret correctly in the help or online all of this stuff would be solved and I would be happy :)... sounds like there are a lot of others in here with the same problem)
William Stacey [MVP] - 10 Feb 2005 04:27 GMT IMO, you don't want to use UsernameTokens (UT) with send none, send hashed, or send clear - period. What you want to use is SecurityContextTokens (SCT). If you only use UT, you can ~easily figure out the password via the hash or the signature. Get a SCT and sign and encrypt your body with a SCT - you then don't need UTs. Only except soap bodies with signatures in your server methods. Also use a DerivedToken of your SCT to mix it up after each call. You can get a SCT via std WSE HTTP or soap.tcp. I have a blog on getting SCT using soap.tcp using public key at http://spaces.msn.com/members/staceyw/Blog/cns!1pnsZpX0fPvDxLKC6rAAhLsQ!303.entry
 Signature William Stacey, MVP http://mvp.support.microsoft.com
> Ok, so I have been looking and looking for a solution that is simple and > eligent and easy to mainatain (see previous post) that replaces the WSE 1.0 [quoted text clipped - 18 lines] > I would be happy :)... sounds like there are a lot of others in here with > the same problem) SA - 11 Feb 2005 00:59 GMT William:
In WSE 2.0 SP 1, for me, creating a derived key from an SCT based on a UsernameToken fails...
Is this me, or is this indeed a known problem?
 Signature Sven.
> IMO, you don't want to use UsernameTokens (UT) with send none, send hashed, > or send clear - period. What you want to use is SecurityContextTokens [quoted text clipped - 4 lines] > each call. You can get a SCT via std WSE HTTP or soap.tcp. I have a blog > on getting SCT using soap.tcp using public key at http://spaces.msn.com/members/staceyw/Blog/cns!1pnsZpX0fPvDxLKC6rAAhLsQ!303.entry
> > Ok, so I have been looking and looking for a solution that is simple and > > eligent and easy to mainatain (see previous post) that replaces the WSE [quoted text clipped - 22 lines] > > I would be happy :)... sounds like there are a lot of others in here with > > the same problem) William Stacey [MVP] - 11 Feb 2005 05:04 GMT I have SP2 so can't tell if it is a SP1 issue. I would probably just install SP2 so you have less variables to test. Then just sign a message using SCT to see if that works first. If that works, then use a derived token from the SCT to see if that works. If not, please post the error and the client web method code. TIA.
 Signature William Stacey, MVP http://mvp.support.microsoft.com
> William: > [quoted text clipped - 14 lines] > > each call. You can get a SCT via std WSE HTTP or soap.tcp. I have a blog > > on getting SCT using soap.tcp using public key at http://spaces.msn.com/members/staceyw/Blog/cns!1pnsZpX0fPvDxLKC6rAAhLsQ!303.entry
> > > Ok, so I have been looking and looking for a solution that is simple and > > > eligent and easy to mainatain (see previous post) that replaces the WSE [quoted text clipped - 25 lines] > with > > > the same problem) James Hancock - 13 Feb 2005 16:25 GMT William could you do me a favour and post a full sample application with what you've done with the latest code somewhere? Because I'm getting all kinds of compile errors and getting confused as to which version requires which and I can't find the methods like Utils.RijndaelEncrypt in any of the sample stuff you put up etc. This defintely looks like the best possible solution to the problem, I just need a little more help to get it working :)
Thanks!
And MS: Please put something like this directly into WSE as a good replacement for shared secret that you took out of WSE 1.0
Thanks! James Hancock
>I have SP2 so can't tell if it is a SP1 issue. I would probably just > install SP2 so you have less variables to test. [quoted text clipped - 60 lines] >> with >> > > the same problem) William Stacey [MVP] - 14 Feb 2005 04:31 GMT Here are those two methods:
public static byte[] RijndaelEncrypt(ICryptoTransform encryptor, byte[] data) { if ( encryptor == null ) throw new ArgumentNullException("encryptor"); if ( data == null ) throw new ArgumentNullException("data");
//Encrypt the data. using(MemoryStream msEncrypt = new MemoryStream()) using(CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) { //Write all data to the crypto stream and flush it. csEncrypt.Write(data, 0, data.Length); csEncrypt.FlushFinalBlock();
//Get encrypted array of bytes. byte[] encrypted = msEncrypt.ToArray(); return encrypted; } }
public static byte[] RijndaelDecrypt(ICryptoTransform decryptor, byte[] encrypted) { if ( decryptor == null ) throw new ArgumentNullException("decryptor"); if ( encrypted == null ) throw new ArgumentNullException("encrypted");
using(MemoryStream msDecrypt = new MemoryStream(encrypted)) using(CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) { byte[] fromEncrypt = new byte[encrypted.Length];
int read = csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length); if ( read < fromEncrypt.Length ) { byte[] clearBytes = new byte[read]; Buffer.BlockCopy(fromEncrypt, 0, clearBytes, 0, read); return clearBytes; } return fromEncrypt; } }
 Signature William Stacey, MVP http://mvp.support.microsoft.com
> William could you do me a favour and post a full sample application with > what you've done with the latest code somewhere? Because I'm getting all [quoted text clipped - 40 lines] > > blog > >> > on getting SCT using soap.tcp using public key at http://spaces.msn.com/members/staceyw/Blog/cns!1pnsZpX0fPvDxLKC6rAAhLsQ!303.entry
> >> > > Ok, so I have been looking and looking for a solution that is simple > > and [quoted text clipped - 29 lines] > >> with > >> > > the same problem) SA - 14 Feb 2005 20:44 GMT William, others:
I have created a full working sample using the method you described in your blog.
It is available from
http://www.adduxis.com/play/SecureUTSCTSample.zip
To keep everyone happy, it's partially in C# and partially in VB.NET ;o)
Because there is no actual code in my web project, I didn't include it. The only thing I included is the web.config. You can create a web project in the solution and then add a reference to the ServiceInterface project to this new web project. Then replace the web.config with the one included in the sample.
Also, the sample relies on a shared library I developed. The library is included, but I can't distribute the source code. Nothing too fancy anyway, just hashing, Rijndael, and RSA helper classes.
Some changes from William's implementation:
* I use the machine key store to store the RSA key pair. A program is included that will allow you to create an RSA key pair and store it in the machine key store.
* I have split the SCTMessage class in 2: a request class and a response class.
* I include the length of the salt string in the request message.
* In order to keep the code clean, I do not actually verify the username/password against the windows database or any other credential store. There is plenty of info available about those things, I don't see the need to add another example.
An architecture document is available in Visio 2003 format in the sample main folder.
I am looking forward to any feedback this sample generates! Sorry, no blog at this time, please post to this group. Sorry, no docs available at this time, code should be sufficiently commented.
Next, I would like some input on how to actually create a custom TokenIssuer, so that this can be used declaratively. I am assuming I'll need to start by deriving the SctRequestMessage class from XmlToken?
HTH,
 Signature Sven.
> Here are those two methods: > [quoted text clipped - 96 lines] > > > blog > > >> > on getting SCT using soap.tcp using public key at http://spaces.msn.com/members/staceyw/Blog/cns!1pnsZpX0fPvDxLKC6rAAhLsQ!303.entry
> > >> > > Ok, so I have been looking and looking for a solution that is > simple [quoted text clipped - 32 lines] > > >> with > > >> > > the same problem) William Stacey [MVP] - 15 Feb 2005 02:38 GMT > I have created a full working sample using the method you described in your > blog. Great.
> To keep everyone happy, it's partially in C# and partially in VB.NET ;o) I would rather have all in one or the other myself. Or complete projects in each if you wanted to show both.
> Nothing too fancy anyway, just hashing, Rijndael, and RSA helper classes. So why not just include them in your Utils class as static methods? That is what I did, then I don't need another class for those simple methods.
> * I use the machine key store to store the RSA key pair. A program is > included that will allow you to create an RSA key pair and store it in the > machine key store. You can use the machine store, or *.snk file, or embedded string. The client only needs the public key. If you are using SN assems, then the public key in the Assembly is convient as you have the public key you know the server has a private key for. You can also embed the public key string in the client so a simple sn -R will not work to do a MITM attack. On the server side, you could use key store or load from .snk.
> * I have split the SCTMessage class in 2: a request class and a response > class. I had thought about that originally, but any null values, by default, don't serialize so the effect is the same if using one doc class and you can drop another class. No value type fields, so we can pull this off kinda neat. If I had more fields and/or value type fields, I would probably go with another class as well.
> * I include the length of the salt string in the request message. I wanted to include only that which was required or added security. I don't see the salt length as adding security. The RSA recommendation is that it be random and >= 64 bits. So 8 or more bytes should do fine. Then just remove that many and you can drop another field from the protocol. The salt is there to make it harder to do dictionary attacks on the username or password encrypted fields. To pull that off, you would need to guess or brute force the correct key, IV, salt, and password at the *same time. I just added it to the username field as it is cheap and pretty simple. And if you think about it. The username can be just as important to keep secret as its plain text can be valuable information to an attacker.
> * In order to keep the code clean, I do not actually verify the > username/password against the windows database or any other credential > store. There is plenty of info available about those things, I don't see the > need to add another example. I might go ahead and include that logic for others as it is important to the protocol. You should only return a SCT if you authenticate with correct username/password combo. So that integration is at heart of the solution. Your web methods should also require all soap bodies signed with a SCT. That is how you force a prior authentication and the other side has an *authenticated SCT. For example, your IsCustomerValid() web method should have the logic to require an authenticated SCT signed the soap body. As it is, any client could call that method without including any token (unless I missed something.) Cheers.
 Signature William Stacey, MVP http://mvp.support.microsoft.com
SA - 15 Feb 2005 17:31 GMT > I would rather have all in one or the other myself. Or complete projects in > each if you wanted to show both. I could have done that, however, I wrote the sample for myself in the first place :o) I decided to share it because I think your idea is solid and deserves attention.
> So why not just include them in your Utils class as static methods? That is > what I did, then I don't need another class for those simple methods. No offense, but that code was written for my company and is therefore intellectual property... I don't think it takes away from the usefulness of the sample. That should be the principle behind component re-use, it's black-box stuff.
> > * I use the machine key store to store the RSA key pair. A program is > > included that will allow you to create an RSA key pair and store it in the [quoted text clipped - 6 lines] > in the client so a simple sn -R will not work to do a MITM attack. On the > server side, you could use key store or load from .snk. OK, the goal for me is to have a way of distributing the software so that every customer can have their own key pair, and (specific project requirements) one client could connect to multiple servers from different sites (with different key pairs in that case).
> > * I have split the SCTMessage class in 2: a request class and a response > > class. [quoted text clipped - 4 lines] > If I had more fields and/or value type fields, I would probably go with > another class as well. I just think it's good design practice. They are in essence two different documents and should therefore be treated as such.
> > * I include the length of the salt string in the request message. > [quoted text clipped - 8 lines] > if you think about it. The username can be just as important to keep secret > as its plain text can be valuable information to an attacker. I only include the length of the salt to make the whole scheme more flexible, not for added security. Actually, I have wondered if adding the salt length to the message might give the hacker to much info?
> > * In order to keep the code clean, I do not actually verify the > > username/password against the windows database or any other credential [quoted text clipped - 11 lines] > is, any client could call that method without including any token (unless I > missed something.) Cheers. The code clearly indicates where the validation should take place. Personally, I feel that adding any type of validation code would make the sample specific to any chosen authentication method. Whether using Azman, ADAM, windows logon methods, or some home-grown database implementation, the idea is to authenticate the user.
I omitted the token validation from the sample, my mistake. One reason is that I would really rather have a custom TokenIssuer so that WS-Policy can then be used to validate incoming messages. I should not have distributed the sample without that check though.
William Stacey [MVP] - 15 Feb 2005 18:40 GMT > No offense, but that code was written for my company and is therefore > intellectual property... I don't think it takes away from the usefulness of > the sample. That should be the principle behind component re-use, it's > black-box stuff. None taken. :-) Hope you did not take offense to that either. I just thought it strange to included all the hard stuff that most would concider IP, but then say a simple thing like a ByteArrayComparer is IP? O well. Does not really matter. Glad fokes are finding some value.
> OK, the goal for me is to have a way of distributing the software so that > every customer can have their own key pair, and (specific project > requirements) one client could connect to multiple servers from different > sites (with different key pairs in that case). OK. I just want to understand the why of it. Just interested. At the moment, I don't see the value of each client having a unique private key for a couple reasons. 1) you need to figure out a way to protect it and 2) If they get a SCT with a username/password, isn't that enouph to prove who they are (assuming your passwords are strong and not known.) Unless your doing some other two-factor authentication such as One-Time-Password or something.
> I just think it's good design practice. They are in essence two different > documents and should therefore be treated as such. Cool. I just have a different opinion for this usage.
> I only include the length of the salt to make the whole scheme more > flexible, not for added security. Actually, I have wondered if adding the > salt length to the message might give the hacker to much info? Well not sure it helps either way. If you don't include it, the fixed salt len can be derived from the code or possibly infered from capture of message of a known password (say his own SCT session). If you explicitly include it, then you don't need to infer it as it is plain. I am just struggling with finding the value in it as it would seem to be an unneeded element at this point.
> I omitted the token validation from the sample, my mistake. One reason is > that I would really rather have a custom TokenIssuer so that WS-Policy can > then be used to validate incoming messages. I should not have distributed > the sample without that check though. No problem. Just pointing out for others. I posted an example SCT check logic in another post on this thread. Cheers!
 Signature William Stacey, MVP http://mvp.support.microsoft.com
SA - 15 Feb 2005 19:10 GMT > None taken. :-) Hope you did not take offense to that either. I just > thought it strange to included all the hard stuff that most would concider > IP, but then say a simple thing like a ByteArrayComparer is IP? O well. > Does not really matter. Glad fokes are finding some value. You did the hard stuff :o) I just added some code to it. My ByteArrayComparer is obviously easy. Even the RSA and Rijndael classes are easy enough, but take some time, it's just that that's policy...
> > OK, the goal for me is to have a way of distributing the software so that > > every customer can have their own key pair, and (specific project [quoted text clipped - 7 lines] > are (assuming your passwords are strong and not known.) Unless your doing > some other two-factor authentication such as One-Time-Password or something. If every customer has the same private key, a hacker would merely need to purchase the product to hack into other people's passwords, sessions, etc. (Or am I wrong here?)
> > I just think it's good design practice. They are in essence two different > > documents and should therefore be treated as such. > > Cool. I just have a different opinion for this usage. No doubt yours works just as well.
> > I only include the length of the salt to make the whole scheme more > > flexible, not for added security. Actually, I have wondered if adding the [quoted text clipped - 6 lines] > with finding the value in it as it would seem to be an unneeded element at > this point. Not if you would say that you might allow the salt value to be a configuration option? Again, I am thinking commercial software.
> > I omitted the token validation from the sample, my mistake. One reason is > > that I would really rather have a custom TokenIssuer so that WS-Policy can [quoted text clipped - 4 lines] > logic in another post on this thread. > Cheers! Wondering if you'd be interested pursuing writing this as a custom TokenIssuer and then writing an article for publication, perhaps in MSDN Magazine?
Thanks for the feedback!
Sven.
William Stacey [MVP] - 15 Feb 2005 19:52 GMT > If every customer has the same private key, a hacker would merely need to > purchase the product to hack into other people's passwords, sessions, etc. > (Or am I wrong here?) Can't say wrong or right in terms of what additional things you may be thinking. However, in terms of just the SCT thing I posted, you don't need private PKI key on clients at all. Only the *public key on the client, the server(s) maintain the private key. If you have multiple servers (say a farm), then each server can access same private key pair using any method you prefer (i.e. db, shared file, key store, etc) Using this public PKI method, a hacker can not hack into other people's passwords off the wire as they can not decrypt the AES session key that was encrypted with the public key. The hacker can send his own requests using the public key, but can not decrypt any other messages from others, even if they use the same public key. So a hacker can not figure out your session key or password and the session is safe within the context of the AES session. To crack, he would need to crack PKI and/or AES using brute force - so we are safe as PKI/AES can be (which is not to say PKI or AES can not be cracked given time and resources). So to get back to your point. I don't see what unique private PKI key on each client is adding here as we are not using a private key for the SCT request. Unless your talking about some other method in addition to the SCT session. If so, I would love to hear about your ideas.
All that said, there is still one weakness here. Even thou the public key is public and not secret, we still need to protect it from change/replacement somehow. As a hacker who gets access to your machine may be able to replace your public key with a public key he created from a new key pair. Now he could Man-In-The-Middle the session. You would send encrypted request using "his" public key, and he could decrypt with the matching private key is knows already. Then just drop the session as he has the password or continue being in the middle and forwarding requests. This would be a hard attack to pull off that would require access to client machine and some network access - but something to think about. I think even public Certs would be vulnerable to this type of attack given the same access to machine and network (say an Inside-Job).
The only thing I can think of to head off that kind of attack is SN sign your client assem with key pair *and encrypt the same public key string in the assem (and obfuscate) and compare the two keys at some point. This pretty much would force a decompile to remove the key compare logic or change the public key. The double check also would guard against any minor/major change to the code or resources as the loader would fail to load the assem. Moreover, they could not just resign the assem as the double check using the embedded version would fail. Raises the bar a bit more.
> Not if you would say that you might allow the salt value to be a > configuration option? Again, I am thinking commercial software. I like config options as well. However, I still don't see what value this could add to commercial software or otherwise. I am racking my head to find a value, but am not able to at this point.
> Wondering if you'd be interested pursuing writing this as a custom > TokenIssuer and then writing an article for publication, perhaps in MSDN > Magazine? Sure. You have any connections into MSDN mag? Cheers!
 Signature William Stacey, MVP http://mvp.support.microsoft.com
SA - 15 Feb 2005 21:11 GMT > > If every customer has the same private key, a hacker would merely need to > > purchase the product to hack into other people's passwords, sessions, etc. [quoted text clipped - 18 lines] > the SCT request. Unless your talking about some other method in addition to > the SCT session. If so, I would love to hear about your ideas. OK, apparently I did not make it clear: the server product is the product being sold (clients too, of course)! So, if every installation with every customer has the same key pair, the hacker has the private key by purchasing the product.
> All that said, there is still one weakness here. Even thou the public key > is public and not secret, we still need to protect it from [quoted text clipped - 8 lines] > even public Certs would be vulnerable to this type of attack given the same > access to machine and network (say an Inside-Job). Right. See my first comment. Would need access to the machine (client or server) in order to do so.
> The only thing I can think of to head off that kind of attack is SN sign > your client assem with key pair *and encrypt the same public key string in [quoted text clipped - 4 lines] > the assem. Moreover, they could not just resign the assem as the double > check using the embedded version would fail. Raises the bar a bit more. That's a good idea. Of course, in my situation, where we'll have different private/public key pairs for different installations, that would not work, as you can only have one public key embedded in the assembly.
> > Not if you would say that you might allow the salt value to be a > > configuration option? Again, I am thinking commercial software. > > I like config options as well. However, I still don't see what value this > could add to commercial software or otherwise. I am racking my head to find > a value, but am not able to at this point. I may have taken this idea too far.
> > Wondering if you'd be interested pursuing writing this as a custom > > TokenIssuer and then writing an article for publication, perhaps in MSDN > > Magazine? > > Sure. You have any connections into MSDN mag? Cheers! Except for the fact that I have a subscription, no... If you'd like to take this more private, visit http://www.adduxis.com and get my e-mail address of the contacts page.
Thanks.
William Stacey [MVP] - 15 Feb 2005 21:42 GMT > OK, apparently I did not make it clear: the server product is the product > being sold (clients too, of course)! So, if every installation with every > customer has the same key pair, the hacker has the private key by purchasing > the product. ahh. Makes perfect sense then. Thanks SA.
 Signature William Stacey, MVP http://mvp.support.microsoft.com
James Hancock - 14 Feb 2005 21:00 GMT Thanks! Do you have the GetBytes and in the GETSCTNew I can't find the SnkUtil.GetRSAFromSnkFile function or the definition for sha.ComputeHash (sha is never defined)..
Thanks again, James Hancock
> Here are those two methods: > [quoted text clipped - 138 lines] >> >> with >> >> > > the same problem) William Stacey [MVP] - 15 Feb 2005 02:41 GMT The full SnkUtil class is in one of my blogs at http://spaces.msn.com/members/staceyw
sha.ComputeHash() is a method of the SHA1 class in the framework.
 Signature William Stacey, MVP http://mvp.support.microsoft.com
> Thanks! Do you have the GetBytes and in the GETSCTNew I can't find the > SnkUtil.GetRSAFromSnkFile function or the definition for sha.ComputeHash [quoted text clipped - 104 lines] > >> > blog > >> >> > on getting SCT using soap.tcp using public key at http://spaces.msn.com/members/staceyw/Blog/cns!1pnsZpX0fPvDxLKC6rAAhLsQ!303.entry
> >> >> > > Ok, so I have been looking and looking for a solution that is > > simple [quoted text clipped - 34 lines] > >> >> with > >> >> > > the same problem) James Hancock - 14 Feb 2005 21:05 GMT Also need ArraysEqual and ToUTCDateTime and SnkUtil.GetPublicKeyFromAssembly
And where was base.SendRequestResponse come from? I.e. what class does the Client method go into and what does that class inherit from?
Thanks again!
> Here are those two methods: > [quoted text clipped - 138 lines] >> >> with >> >> > > the same problem) SA - 14 Feb 2005 21:48 GMT James,
I suggest you look at my sample, hopefully that will help out.
.SendRequestResponse is inherited from SoapClient (Microsoft.Web.Services2.Messaging namespace).
 Signature Sven.
> Also need ArraysEqual and ToUTCDateTime and > SnkUtil.GetPublicKeyFromAssembly [quoted text clipped - 105 lines] > >> > blog > >> >> > on getting SCT using soap.tcp using public key at http://spaces.msn.com/members/staceyw/Blog/cns!1pnsZpX0fPvDxLKC6rAAhLsQ!303.entry
> >> >> > > Ok, so I have been looking and looking for a solution that is > > simple [quoted text clipped - 34 lines] > >> >> with > >> >> > > the same problem) James Hancock - 15 Feb 2005 01:13 GMT Ok, so I don't want to use this with soap stuff really, I only want to use it for Web Services. Do I have to use pure soap messaging or can I do it with a pure web service?
> James, > [quoted text clipped - 172 lines] >> >> >> with >> >> >> > > the same problem) William Stacey [MVP] - 15 Feb 2005 01:46 GMT You could it with sockets and no xml if you wanted. However SCTs are a WSE thing. If you not using WS-*, then probably no need for this. You could use the same idea however to do a shared key exchange. I would probably use Diffie-Hellman at that point or SRP.
 Signature William Stacey, MVP http://mvp.support.microsoft.com
> Ok, so I don't want to use this with soap stuff really, I only want to use > it for Web Services. Do I have to use pure soap messaging or can I do it [quoted text clipped - 131 lines] > >> >> > blog > >> >> >> > on getting SCT using soap.tcp using public key at http://spaces.msn.com/members/staceyw/Blog/cns!1pnsZpX0fPvDxLKC6rAAhLsQ!303.entry
> >> >> >> > > Ok, so I have been looking and looking for a solution that is > >> > simple [quoted text clipped - 38 lines] > >> >> >> with > >> >> >> > > the same problem) James Hancock - 15 Feb 2005 14:58 GMT Ok. I'm getting totally confused. Here's what I want to do:
I have a web service. It uses WSE 1.0 right now with shared secret to encrypt the transactions that go over the wire to ensure data security. All I want to do is upgrade to WSE 2.0 to fix all of the bloody bugs with WSE 1.0's attachment implimentation.
However of course, WSE 2.0 took out the shared secret encryption for some god forsaken reason and didn't bother to put in an equivalent easily.
So right now I've got it using UserNameToken and sending the password as plain text. Needless to say I don't like this at all. What I wanted to do is SendNone with my username tolken thus basically creating a shared secret because the server already knows the password and can return it to the authenticaltoken command thus leaving the (incredibly strong) password out of the equation.
Anyhow, I like your solution better, but I'm getting confused and frustrated. GETSCTNew aparently needs a class that is inherited from SoapClient. Well of course this isn't a soap communication beyond the fact that it's a web service so it's using soap stuff under neath. At that point I get confused, becuase how the heck do I send this stuff?
Right now I do this:
us.CookieContainer = cookieJar;
us.Timeout = 1800000;
us.Url = URL;
Microsoft.Web.Services2.Security.Tokens.UsernameToken tok = new Microsoft.Web.Services2.Security.Tokens.UsernameToken(Licience, Common.EncryptString(Key), Microsoft.Web.Services2.Security.Tokens.PasswordOption.SendPlainText);
//Sync.RequestSoapContext
SoapContext requestContext = us.RequestSoapContext;
requestContext.Security.Timestamp.TtlInSeconds = -1;
requestContext.Security.Tokens.Add(tok);
MessageSignature sig = new MessageSignature(tok);
requestContext.Security.Elements.Add(sig);
requestContext.Security.Elements.Add(new EncryptedData(tok));
Which signs and encrypts the communication nicely.
us = a web service that is in my web references.
On the server side I have it setup in my web.config so that it knows about my implimentation of usernametoken and I do my own authentication in that class and then every web method I then check the soap contents to make sure that it is encrypted, signed and has a valid usernametoken on it.
Add to that a ton of functions that I can't find that you use all over the place and I'm really lost. (hence why I asked how to use SendNone on UserNameTokens so that I could do this the easy way)
Man I hope they make this stuff easier in Indigo... I thought Avalon was going to be great, but now I am convinced that Indigo is going to be where it's at if they finally fix this and make encryption without certificates easy.
James Hancock
> You could it with sockets and no xml if you wanted. However SCTs are a > WSE [quoted text clipped - 206 lines] >> >> >> >> with >> >> >> >> > > the same problem) William Stacey [MVP] - 15 Feb 2005 17:28 GMT > However of course, WSE 2.0 took out the shared secret encryption for some > god forsaken reason and didn't bother to put in an equivalent easily. Effectivily, UsernameTokens(UT) is using a shared secret. The shared secret is the password. The encryption key is derived from the password. More on that below.
> So right now I've got it using UserNameToken and sending the password as > plain text. Needless to say I don't like this at all. What I wanted to do > is SendNone with my username tolken thus basically creating a shared secret > because the server already knows the password and can return it to the > authenticaltoken command thus leaving the (incredibly strong) password out > of the equation. The problem with using just UTs and either SendNone, SendHashed or SendPlain is if you sign a request, you may have all the data you need to perform a dictionary attack on the signature to get the password used to sign the data. Depending on the data sent, you could also do a dictionary attack on the encrypted body to figure out what password was used to encrypt it. If your password is a cryptographically strong random bytes and >= 16 bytes, then that may be ok as that is like trying to brute force an AES 16 byte random key. If you go that route, I would use SendNone, a 16 (or 32) byte *random password, and encrypt and sign all requests. Also note, you can't use DerivedKeyTokens with UTs, so that is another down side of using UTs.
> Anyhow, I like your solution better, but I'm getting confused and > frustrated. GETSCTNew aparently needs a class that is inherited from > SoapClient. GetSCTNew is a just a soap method like any other. Yes the class derives from SoapClient. Are you having issues with get a SoapClient proxy working with your SoapService? My SCT method just returns a SCT token if you pass the correct username/pw. Then you can use the SCT to sign and encrypt messages without a UT. If you using 16 byte random password, then it is probably still not as strong as using a SCT, but maybe good enouph for your purposes and easier as you said. I attached code of client class at end of this post.
> Add to that a ton of functions that I can't find that you use all over the > place and I'm really lost. (hence why I asked how to use SendNone on > UserNameTokens so that I could do this the easy way)
> Man I hope they make this stuff easier in Indigo... I thought Avalon was > going to be great, but now I am convinced that Indigo is going to be where > it's at if they finally fix this and make encryption without certificates > easy. Looks like Indigo will make things much easier. Here is client side class.
using System; using System.Collections; using System.Security.Cryptography; using System.IO; using System.Text; using System.Diagnostics; using Microsoft.Web.Services2; using Microsoft.Web.Services2.Addressing; using Microsoft.Web.Services2.Messaging; using Microsoft.Web.Services2.Security.Tokens; using Microsoft.Web.Services2.Security; using System.Xml; using Microsoft.Web.Services2.Security.Policy; using Microsoft.Web.Services2.Security.Cryptography; using System.Globalization; using System.Reflection;
namespace WSESimpleTCPDLL { public sealed class ServiceClient : SoapClient { private System.Security.Cryptography.RSACryptoServiceProvider rsaPub; private readonly Hashtable sctList = new Hashtable( new CaseInsensitiveHashCodeProvider(), new CaseInsensitiveComparer() ); private readonly object syncRoot = new object(); private static SHA1 sha = SHA1.Create();
public ServiceClient( EndpointReference endpoint ) : base( endpoint ) { string xml = GetPublicKey(); rsaPub = new System.Security.Cryptography.RSACryptoServiceProvider(); rsaPub.FromXmlString(xml);
sctList = new Hashtable( new CaseInsensitiveHashCodeProvider(), new CaseInsensitiveComparer() ); sctList = Hashtable.Synchronized(sctList); }
private ServiceClient() : base() { }
private System.Security.Cryptography.RSACryptoServiceProvider RSAPubKey { get { return rsaPub; } }
public SecurityContextToken GetSCTNew(string userName, string password) { SecurityContextToken curSCT = (SecurityContextToken)sctList[userName]; if ( curSCT != null ) { if ( curSCT.IsCurrent ) return curSCT; // Else, remove curSCT and continue for new one. sctList.Remove(userName); } // Load server's public RSA key. Could get from Assembly, file, etc. System.Security.Cryptography.RSACryptoServiceProvider pubRSA = SnkUtil.GetPublicKeyFromAssembly(Assembly.GetExecutingAssembly());
// Create SCT Request. SCTMsg ki = new SCTMsg(); byte[] key = Utils.GetRandomBytes(64); // 64 bytes each side. byte[] sKey = Utils.GetBytes(key, 32); // 32 bytes AES key. byte[] iv = Utils.GetBytes(key, 16); // Is this secure? // Add some random salt to the username and pw to make it so much // harder to figure out via a brute force attack on AES. Nice thing // about use AES instead of PKI is we don't have to worry about size // of username or password. string salt = Convert.ToBase64String(Utils.GetRandomBytes(10)).Substring(0, 10); string saltun = salt + userName; string saltpw = salt + password; byte[] unBytes = Encoding.UTF8.GetBytes(saltun); byte[] pwBytes = Encoding.UTF8.GetBytes(saltpw); ki.Key = pubRSA.Encrypt(key, false); RijndaelManaged rm = new RijndaelManaged(); rm.Key = sKey; rm.IV = iv; ICryptoTransform encryptor = rm.CreateEncryptor(); ki.Username = Utils.RijndaelEncrypt(encryptor, unBytes); ki.Password = Utils.RijndaelEncrypt(encryptor, pwBytes); // Add signature. This is the msg digest encrypted with AES. // Note we are using the actual 64 key in the hash and not // the "wire" version. Now the message itself does not // contain the raw data needed to brute force the hash. byte[] hashData = Encoding.UTF8.GetBytes( Convert.ToBase64String(key) + Convert.ToBase64String(ki.Username) + Convert.ToBase64String(ki.Password)); byte[] msgHash = sha.ComputeHash(hashData); ki.Signature = Utils.RijndaelEncrypt(encryptor, msgHash);
// Send request. SoapEnvelope se = new SoapEnvelope(); se.SetBodyObject(ki); SCTMsg rki = (SCTMsg)base.SendRequestResponse("GetSCTNew", se).GetBodyObject(typeof(SCTMsg));
// Verify Signature. Digest signed by the server's private key. hashData = Encoding.UTF8.GetBytes( Convert.ToBase64String(key) + // Server used 64 byte key. rki.SCTIdentifier + rki.SCTExpires); if ( ! pubRSA.VerifyData(hashData, new SHA1CryptoServiceProvider(), rki.Signature) ) throw new Exception("Could not verify hash.");
// Create SCT. Note we are not wrapping a UT on this version. // Not sure it is needed. Do we have a reason? SecurityContextToken sct = new SecurityContextToken(rki.SCTIdentifier); sct.KeyBytes = iv; // SCTs require 16 byte Keys. DateTime expires = Utils.FromUTCDateTimeString(rki.SCTExpires); expires = expires.ToLocalTime(); sct.LifeTime = new LifeTime(expires);
// Add SCT to static Hashtable for this username. // This hashtable is not required if you just want to hold onto the SCT // yourself. sctList[userName] = sct; return sct; }
// Some other web method. Anyone can call. [SoapMethod("Ping")] public string Ping(string msg) { return (string)base.SendRequestResponse("Ping", msg).GetBodyObject(typeof(string)); }
// Some other web method. Server requires authenticated SCT. [SoapMethod("GetDateString")] public string GetDateString() { SoapEnvelope se = new SoapEnvelope(); SecurityContextToken sct = GetSCTNew("staceyw", "1234"); DerivedKeyToken dt = new DerivedKeyToken((IDerivableToken)sct); se.Context.Security.Tokens.Add(sct); se.Context.Security.Tokens.Add(dt); se.Context.Security.Elements.Add(new MessageSignature(dt)); string r = (string)base.SendRequestResponse("GetDateString", se).GetBodyObject(typeof(string)); return r; }
} }
// // Server method may look like: // [SoapMethod("GetDateString")] public string GetDateString(string data) { if ( ! AccessIsAllowed(@"mvptools\newgroup") ) throw new Exception("Security exception."); Debug.WriteLine("Is in Role: true"); return DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ", CultureInfo.InvariantCulture); }
/// <summary> /// Require message is signed by SCT or Derived SCT *and it is /// Authenticated. /// </summary> /// <param name="role"></param> /// <returns></returns> private bool AccessIsAllowed(string role) { SecurityElementCollection elements = RequestSoapContext.Current.Security.Elements;
// Loop through all of the security tokens (could be more than one). foreach( ISecurityElement securityElement in elements ) { if( securityElement is MessageSignature ) { MessageSignature sig = (MessageSignature)securityElement; if( (sig.SignatureOptions & SignatureOptions.IncludeSoapBody) != 0 ) { SecurityToken sigToken = sig.SigningToken; // Find the token used to sign this message if ( sigToken is SecurityContextToken || sigToken is DerivedKeyToken ) { if ( sigToken.Principal.Identity.IsAuthenticated ) { if ( role == null ) return true; // Allow any role. if ( sigToken.Principal.IsInRole(role) ) return true; // Allow only users in "role". else return false; // Not member. } else return false; // Not authenticated. } else return false; // Not one of tokens we allow. } } } return false; }
 Signature William Stacey, MVP http://mvp.support.microsoft.com
SA - 15 Feb 2005 17:31 GMT James,
let's see if we can address some of your concerns.
> Anyhow, I like your solution better, but I'm getting confused and > frustrated. GETSCTNew aparently needs a class that is inherited from > SoapClient. Well of course this isn't a soap communication beyond the fact > that it's a web service so it's using soap stuff under neath. At that point > I get confused, becuase how the heck do I send this stuff? It depends. On the client side, the service proxy inherits from SoapClient. On the server-side, the service interface inherits from SoapService.
I don't see why you are saying that's not SOAP communication... It definitely is sending SOAP messages back and forth. I implement all my web services that way. I need to write my own proxies rather than relying on wsewsdl2.exe (or whatever that tool is called...), but it gives me much more control for very little effort.
Please try the sample I supplied. Let me/us know if you have any questions about it, after walking through it with the debugger.
> Right now I do this: <snip>
> Which signs and encrypts the communication nicely. > > us = a web service that is in my web references. Actually, "us" is just a class that's auto-generated by the WSDL tool. It is not a web service, it's a web service proxy.
So basically, you'd write your own "us" class. That will be a class that inherits from SoapClient. That class' interface will resemble your server class' interface (just like "us" does now).
> On the server side I have it setup in my web.config so that it knows about > my implimentation of usernametoken and I do my own authentication in that > class and then every web method I then check the soap contents to make sure > that it is encrypted, signed and has a valid usernametoken on it. OK, so you basically have a custom UsernameTokenManager. You won't need that any longer with this implementation. Much has been written about that lately, but the conclusion is always that unless you use SSL every time, all the time, there is no secure way to use UsernameTokens.
> Add to that a ton of functions that I can't find that you use all over the > place and I'm really lost. (hence why I asked how to use SendNone on > UserNameTokens so that I could do this the easy way) OK, walk through the sample with a debugger. Take the encryption and hashing stuff for granted. (That's black box stuff, it really has nothing to do with this sample...) The only thing you need to understand is where a public/private key pair is used and where a shared session key is used. If you see RSA encryption, then it's PKI. If you see Rijndael, then that refers to the shared session key.
If there are any non-encryption related functions you can't seem to find, check the WSE documentation first. More than likely, there inherited from SoapClient or SoapService, or static (Shared) methods of WSE 2.0 classes. If you still don't seem to find the function, let me/us know.
Also review the architecture document that's included. If you don't have a means to open Visio files (there's a free viewer available from Microsoft at [1], but I understand if you don't want to install that), I will create a PDF from that file. Print it, and annotate is you like when going through the sample.
> Man I hope they make this stuff easier in Indigo... I thought Avalon was > going to be great, but now I am convinced that Indigo is going to be where > it's at if they finally fix this and make encryption without certificates > easy. Unfortunately, security is never "easy." If it was, people wouldn't need us anymore, they could just drag-and-drop their way to interoperable web services. Pray that day never comes, or that you have another job offer by that time ;o)
Just exaggerating. But the main point still is that using usernames and passwords is increasingly risky because of several reasons, some of which are outlined in Keith's article at [2].
[1] http://office.microsoft.com/en-us/officeupdate/CD010798711033.aspx
[2] http://msdn.microsoft.com/webservices/default.aspx?pull=/library/en-us/dnwse/htm l/securusernametoken.asp
William Stacey [MVP] - 15 Feb 2005 18:01 GMT > Just exaggerating. But the main point still is that using usernames and > passwords is increasingly risky because of several reasons, some of which > are outlined in Keith's article at [2]. > http://office.microsoft.com/en-us/officeupdate/CD010798711033.aspx http://msdn.microsoft.com/webservices/default.aspx?pull=/library/en-us/dnwse/htm l/securusernametoken.asp
I had also blogged on the weakness of UsernameTokens with supporting code example at: "Crack your WSE SendHashed Passwords." http://spaces.msn.com/members/staceyw/Blog/cns!1pnsZpX0fPvDxLKC6rAAhLsQ!178.entry
This could work with SendNone or SendHashed. Naturally SendPlain is a joke unless the plain text is actually encrypted first with a prior shared secret or PKI. It is much easier to crack ~standard passwords, but given some time, you could crack most passwords. Even passwords people "think" are strong, like "Letmein;12" can be cracked pretty fast.
 Signature William Stacey, MVP http://mvp.support.microsoft.com
James Hancock - 16 Feb 2005 15:29 GMT > James, > [quoted text clipped - 18 lines] > more > control for very little effort. Because all of my web services are derived from Microsoft.Web.Services2.WebServicesClientProtocol or down the list
System.Web.Services.Protocols.SoapHttpClientProtocol
SA - 16 Feb 2005 17:38 GMT > Because all of my web services are derived from > Microsoft.Web.Services2.WebServicesClientProtocol or down the list > > System.Web.Services.Protocols.SoapHttpClientProtocol Yes, that's a difference, but that doesn't mean it's not SOAP ;o)
HTH,
Sven.
Softwaremaker - 11 Feb 2005 06:55 GMT James,
Grokking in the dark here: Have you set the usernametoken manager in the config file ?
 Signature Thank you.
Regards, William T (Softwaremaker) http://www.softwaremaker.net/blog =========================================
> Ok, so I have been looking and looking for a solution that is simple and > eligent and easy to mainatain (see previous post) that replaces the WSE 1.0 [quoted text clipped - 18 lines] > I would be happy :)... sounds like there are a lot of others in here with > the same problem) James Hancock - 11 Feb 2005 16:53 GMT Yup, and all works perfectly if I send the password as plain text or hashed.
> James, > [quoted text clipped - 26 lines] >> I would be happy :)... sounds like there are a lot of others in here with >> the same problem)
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|