Added rough version of use of Data protection API and saving key protected to file#12
Added rough version of use of Data protection API and saving key protected to file#12geertendoornenbal wants to merge 2 commits intomrsheepuk:masterfrom
Conversation
modified: src/TokenAuthExampleWebApplication/RSAKeyUtils.cs modified: src/TokenAuthExampleWebApplication/Startup.cs modified: src/TokenAuthExampleWebApplication/project.json Added use of a key file and data protection API for securing the key.
modified: RSAKeyUtils.cs unfortunate remainder of old names
|
You can create a simple console project that calls the function GenerateProtectedKeyToFile to create a key file. After that you should be able to run the application as it is. |
|
Thanks, I have tried calling Because it falls over Deserializing the KeyParams from the authtoken.key file - becuase the file text isn't JSON - instead the file text has actually been encrypted and needs decrypting first: The above doesn't work because when authtoken.key is written, the JSON is first Protect()'ed before being written, as per below: Therefore I tried chainging the load key params method to do an Unprotect first but that doesn't work either - it falls over on the call to Unprotect.. So basically, struggling to see how this all works at present! |
|
Did you create one from a different application? If so you need to specify an appname, to make it come from the 'same' source. This is mentioned in this line of code: |
|
So the creation has to be done like this: |
|
No I am creating within the same application. I think I have figured out the issues and managed to get it to work but I had to make code changes / fixes. The two problems are:
|
| Modulus = this.Modulus, | ||
| P = this.P, | ||
| Q = this.Q | ||
| string lProtectedString = mProtector.Protect(lSerializedParameters); |
There was a problem hiding this comment.
Here - the json is being protected before being written to the file..
|
You're right. In the project where I had this set up, I did the same things you mentioned (unprotect, and made IDataProtector a member of the RSAKeyUtils class, with dependency injection). Apparently I forgot to move this to the example code. |
|
No problems, glad I am not going crazy! I have it working now so it was still valuable as sample code ;) |
|
Good to hear you have it working! I added this in a rush, because I spend quite some time on it to get it to work, and wanted to provide the code so others could save time ;) |
|
Just to be complete: I added the DataProtector as follows: And use it as follows: |
|
Cool. I'm wondering if, now that I have an "authtoken.key" file - will DataProetection be able to Unprotect() and read that file forever more? I know that DataProtection can do key rotation? Or perhaps does this automatically, and I am just wondering if in X days time, all of a sudden DataProtection will start using different keys, and and will no longer be able to Unprotect the contents of the authtoken.key file? |
|
I've wondered the same thing. It's hard to figure this out based on only the documentation (http://docs.asp.net/en/latest/security/data-protection/, especially look at encryption at rest). I could not really figure out what really was going on and what the best approach was. |
|
Indeed - this worry (regarding what happens when the DPAPI rolls the keys over) is why I haven't merged this pull request in yet, I want to know the answer to that, else every time the keys get rolled, all the authentication tokens will become unreadable... As I understand it, the old keys should remain available for unprotecting for a certain amount of time, even once new keys have been generated by DPAPI, but unless the key file gets re-written by something, sooner or later it seems that it's going to expire. |
|
Yeah.. my first thought was to put a simple try catch around the method that Unprotects()'s and reads the key. If it fails to Unprotect() (because the DPAPI keys have just changed) then delete the file and generate a new key file, protected with latest DPAPI, then read that one and return the result. I think this would work in that now tokens will be signed with a new key, but made me wonder what happens tot he existing tokens sitting in people's browsers etc when this happens.. Assuming they'd all now be invalid.. So now I am wondering how to make it so that everyone doesn't get thrown out of the system when this process happens! :( |
|
Just trying to think of the reasons why you'd generate a new key file:
I can understand 1) which is a rare event and so kicking people out of the system and asking them to re-authenticate isn't a huge deal in a rare scenario like that. But as for 2) - DPAPI forcing you to change the key file when it rolls its keys seems like not a good idea. I think you'd almost want to guarantee that you can read the key (using DPAPI or whatever protection mechanism) for the lifetime of the key, and you don;t want DPAPI or whatever to dictate that lifetime.. as it has massive impact on your users potentially. |
|
Because of the above, I don't think DPAPI makes sense unless you can configure it in such a way that you are guaranteed to be able to read the key file for the lifetime of the key. Time to hit the DPAPI docs and see if that's possible! :) |
|
Indeed... it might "just work", in that if it's configured correctly, it might be the case that the old expired keys are ALWAYS available for unprotect operations. But I read the docs over and over and couldn't really convince myself that this was what happened, but also couldn't think how to test it easily without waiting 45 days! |
|
@mrsheepuk haha I see.. I'll see what I can find out |
|
Feel free to chime in: aspnet/DataProtection#137 |
|
I've just had another look at the documentation, it has been updated since I last looked - it now reads:
This would imply that it is always safe to use this method, so long as the DPAPI is configured to keep the keys in a way which is accessible to all machines in a cluster of web servers. |
|
And as long your key won't be compromised (and you know about it!) ;) |
|
Ah excellent news ;) |
|
It feels like there's still an extra hop than should be needed. It would be ideal to use the DPAPI directly to sign and verify the tokens, thus removing the entire need to generate and store a key file on disk. If we could find a way to hook the "unprotect" into the JWT verify token stage... Then it would be as simple as configure the DPAPI and off you go! I'll have another play... |
|
@mrsheepuk Yep - I completely agree! |
|
@mrsheepuk not sure this would work if you need to share the public key across multiple API servers. You'd need a file written out to disk somewhere ahead of time to be shared with the API servers. Generating the key's on the fly doesnt really work, unless somehow you pulled in a database/key store into the mix. I dont even want to go there. Correct me if I'm wrong please. I'm new to this land of security. |
|
Hi @Icestorm0141 - from the DP API documentation you can choose to store the keys on a UNC path accessible by all machines which need them. The DPAPI then manages adding new keys to the shared storage and timing out old keys. To use a UNC path, it sounds like you need X.509 certificates set up for all machines which are used to secure the keys at rest, I think. I'm not 100% clear on this... |
|
Why this pull request not merged into main branch? |



I've added some code to show how to use the data protection API, and save the protected key to file.
However, it is a rough version, and I'm wondering if saving to file is the most secure option.
I also removed the RSAKeyParametersWithPrivate class, because it is not necessary anymore.
Please note that I quickly threw this together from my own project, to show you how this can be done.