Are the data protection keys necessary for docker container? - c#

I am getting the following error in my logs when running my application on a docker container.
[08:20:54 WRN] Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed. <s:Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository>
[08:20:54 WRN] No XML encryptor configured. Key {<some-id} may be persisted to storage in unencrypted form. <s:Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager>
I was reading into data protection keys, especially from this article https://www.edument.se/post/storing-the-asp-net-core-data-protection-key-ring-in-azure-key-vault?lang=en and it seems to be something that might be really important when deploying an app. However, what I don't understand is what is it being used for? I am not using identity or session cookies. And for the technologies I am using, I create my own keys to encrypt the information.(For example for JWT or for encrypting some text).
I do use cookies to set my jwt token by using the set-token header with HTTPonly flag. Could that be what the key is being created for?
I want to know in order to define if we should take action to make the keys persistent or if can just ignore it. I would appreciate it a lot if someone has some insight into this that is willing to share.
Here a screenshot of the file where the keys are being stored

Actually, the section What happens if I don’t configure the data protection service in ASP.NET Core? of the referenced post gives a great explanation of what it is used for.
And yes, setting HttpOnly=true means encrypting the cookie's value with the Key Ring. You can do a simple test: run your service locally in a docker container, perform the flow that sets the cookie on your browser, then remove the container and create a new one. Now try to perform the action that requires the cookie, and it will fail because your service can't longer decrypt the cookie's value.

Related

CookieTempDataProvider causes CryptographicException

I have an ASP.NET Core app (1.1 targeting full framework) that uses TempDataProvider to store some metadata about the currently logged-in user, such as their "display name" and some other preferences for the app. In my Startup.cs ConfigureServices method I have added the line
services.AddSingleton<ITempDataProvider, CookieTempDataProvider>();
which is populated after login using (for example)
TempData["DisplayName"] = login.DisplayName;
This works well, creating an encrypted, chunked session cookie for the user named .AspNetCore.Mvc.CookieTempDataProvider. I can "peek" and clear on logout, etc. as I expect. However after some interval - perhaps the app pool going idle, but the browser session remaining active - I receive a CryptographicException:
System.Security.Cryptography.CryptographicException: The key {guid} was not found in the key ring
It appears that the browser session cookie is still good, but the server has lost its ability to decrypt and use it. Currently the only way to resolve is to manually clear the cookie and let the app create a new one.
Is there any way to protect against this behavior? I do want the contents of the cookie to be difficult/impossible to forge, and this seemed like a valid mechanism to achieve that.

Web service lifetime against authentication list

What I have
I'm making a web service using C#.
In order to authenticate users, they have to send their name plus their encrypted password, in order to check if exists in a database.
Then, If it's found, I create a string token, which is a 10 char string randomly generated in order to send it the next times while the session is alive, avoiding to have to send the original credentials anymore.
What is my problem
Using this approach, my problem appears due to the service lifetime.
It's known that web services are not initialized each time a request arrives, but nor is infinite. So there will be a moment, when it'll be destroyed and initialized again.
At this point, my token list would be erased, as well as all the alive connections with it, as this is its function.
So I'm stuck at this point. I'm not sure about how to proceed, maybe I'm just fooling around and there's a simpler way to authenticate users? Or maybe you've and idea about how to don't loose all these alive sessions without having to write them at a DB.
Thank you in advance
Update:
My goal
I aim to create a personal Web Service, just build for me and some friends. Not inside a company nor anything like this. Not in the same LAN neither.
I want to add a bit of security to this service, so I wanted to add authentication to the WS, mainly in order to avoid people pretending to be another and this kind of stuff. So I created User+Password system.
Then, in order to avoid to send them both in each WS Request, I started to write the "token" approach described above.
Notice that I'm using token word because it's similarity with token systems for these cases, but it's a completely created from 0 system, nothing proffesional, so do not assume anything complex about it if I've not said that.
How my system works (or try to)
User -> Auth (user, pass_encrypted) -> WS -> DB (exist? OK)
WS -> token (randomly generated, 10char string) -> User
After that, at each WS request, User sends the token instead of credentials.
After receiving it, WS looks for the token at a List<structureToken>, so it obtains the user which is doing the call, and (for example) the access level, in order to know if the user has rights to run this call.
Your current problem is that you want same list to be persisted through restarts and not persisted to any physical media at the same time. You have to pick one of the choices and live with it: not persisted - just ignore the fact you can have list in memory and make sure token can be validated by itself, if persisting - pick storage and save you list of random numbers.
Since you are building simple system without actual need to have proven verifiable security you can get some ideas from existing systems (like STS and the way it creates token). Basically STS signs information about user (indeed after validation) and than encrypts it with public key of receiving party. So particular server that supposed to get the token can decrypt it (as it has private key part), everyone else may still use it but have to treat as non-verifiable black box token.
Simplest version of this would be no encryption of information, just basic signing. Proper signing requires private/public pair (so external party can validate signature), but since in your case both parties are the same service - you can just SHA256. To prevent external callers to fake you signature you need to have some private information included in hash to "salt" value before hashing. Random number hardcoded into server code (or read from settings) would be good enough. You may also want to include expiration as part of signed value.
So your "token" could look like:
Name,expiration,Base64 of SHA256 of {Name + expiration + secret value}
Bob-2015-06-30-A23BDEDDC56
Since your server code have "secret value" you can always re-compute hash to verify if it is indeed the correct token.
Notes:
do not use it for any real services. Use an existing authentication and make sure to review all security comments related to proper usage of it.
this approach gives you chance to learn a some other concepts - i.e. key update (when your "secret value" need to change, or in real systems signing/encryption certs).

Use MachineKey.Protect Outside of ASP.NET

I need to encrypt a cookie outside of ASP.NET (Console App, Powershell etc.) but since this cookie will eventually be read by my MVC application it needs to be encrypted with the same key.
I can use the MachineKey class outside of ASP.NET however I can't specify the encryption type or key as these are outlined in the application's web.config which doesn't exists in this context. Since there is no config the key is randomly generated everytime.
How can I encrypt data using the same decryption key below so it is guaranteed to be decrypted successfully later by my MVC application?
<machineKey
validationKey="207FE3B8E01D0FF81871D7F3EFC082A14341A7820942D24D3BEF8954CAE53D860F46FBCDDA73F752CE1052D475D442CC8C14FC814739A757D52D152EF5EE179E"
decryptionKey="326C47E59EB1B38AEA84DBC9633BB770C318A740E477C82F3A8D9506F030D953"
validation="SHA1" decryption="AES"
/>
Some possible ideas.
Just use an App.config with your console app and mirror the machine
key from the web.config of your main project.
Grab the machine key programatically. To do this you would need the
path of the machine key (perhaps you could store it in DB, windows
registry, or somewhere?). MSDN has some great examples of this method.
Grabbing the key is basically:
Configuration config = WebConfigurationManager.OpenWebConfiguration(configPath);
MachineKeySection configSection = (MachineKeySection)config.GetSection("system.web/machineKey");
Then it is just a matter of using the right method to encrypt the cookie. Keep in mind that some ASP.NET membership providers serialize additional data into the cookie so depending on which one you are using, this may not be possible. Also, if your app uses the UserData section of a cookie then this could break it.

Form authentication cookie vulnerability

I have a question regarding Form authentication cookie vulnerability. In JavaScript we can use document.cookie to access form authentication cookie value (assuming it is not httponly). This value is encrypted. I have read in many blogs that if someone get's this value our security is breached. My question is how can he(attacker) breach it(the credentials inside the cookie) since the form authentication encryption method uses machine key to encrypt that cookie, so to decrypt it, the same machine key would be needed? Isn't that so? Can you clarify me on this that how that cookie value is vulnerable since the attacker should have my machine key with him only then he can decrypts it? Am I right here?
how can he(attacker) breach it(the credentials inside the cookie) since the form authentication encryption
He doesn't have to decrypt the encrypted cookie. He could just use the encrypted value of the cookie and become you.
The server does the encryption, so it doesn't know that the browser giving it the cookie was who the cookie was originally issued to.
Using an extension like Modify This Cookie (or anything else that achieves that functionality) would allow me to set my cookie to your encrypted value if I were able to obtain it.
Ironically, the very same question was asked about StackOverflow. Have a look at Troy's post for further information.
What I've done, don't know how much it actually helps, but I've never seen any breaches (although there are some 100 attempts made) is to pair the cookie with an IP-address, which means that I look up if the call comes from the same IP-address as the previous call, if not, it resets the cookie and you'll have to log in again. This isn't exactly viable for all sites, but in my case it was more important to add some measures of security rather than allowing for mobility.
This approach is probably nicely suceptible for MITM attacks, but you can never protect yourself against all eventualities except if you have a monster budget and no restrictions regarding performance and accessibility.

Storing My Amazon Credentials in C# Desktop App

I'm Looking at using Amazon S3 and simpleDB in a desktop application.
The main issue I have is that I either need to store my aws credentials in the application or use some other scheme.
I'm guessing that storing them in the application is out of the question as they would be easily picked out.
Another option is to create a web service that creates the aws authentication signature but this has its own issues.
Does the signature require all the data from a file thats being uploaded? If so I would have to transfer all the data twice.
There would then be a central failure point which was one of the main reasons for using aws.
Any ideas?
UPDATE:
I needed to make it a bit clearer that I'm wanting to store my aws credentials in an application handed out to others. DPAPI or any other encryption would be only stop people simply using reflector to get the credentials. Using any encryption still needs the key that is easy to get.
UPDATE 2 - Sept 2011
Amazon have released some details on using the AWS Security Token Service, which allows for authentication without disclosing your secret key. More details are available on this blog post.
Tim, you're indeed hitting on the two key approaches:
NOT GOOD ENOUGH: store the secret key "secretly" in the app. There is indeed a grave risk of someone just picking it out of the app code. Some mitigations might be to (a) use the DPAPI to store the key outside the app binary, or (b) obtain the key over the wire from your web service each time you need it (over SSL), but never store it locally. No mitigation can really slow down a competent attacker with a debugger, as the cleartext key must end up in the app's RAM.
BETTER: Push the content that needs to be protected to your web service and sign it there. The good news is that only the request name and timestamp need to be signed -- not all the uploaded bits (I guess Amazon doesn't want to spend the cycles on verifying all those bits either!). Below are the relevant code lines from Amazon's own "Introduction to AWS for C# Developers". Notice how Aws_GetSignature gets called only with "PutObject" and a timestamp? You could definitely implement the signature on your own web service without having to send the whole file and without compromising your key. In case you're wondering, Aws_GetSignature is a 9-line function that does a SHA1 hash on a concatenation of the constant string "AmazonS3", the operation name, and the RFC822 representation of the timestamp -- using your secret key.
DateTime timestamp = Aws_GetDatestamp();
string signature = Aws_GetSignature( "PutObject", timestamp );
byte[] data = UnicodeEncoding.ASCII.GetBytes( content );
service.PutObjectInline( "MainBucket", cAWSSecretKey, metadata,
data, content.Length, null,
StorageClass.STANDARD, true,
cAWSAccessKeyId, timestamp, true,
signature, null );
EDIT: note that while you can keep the secret key portion of your Amazon identity hidden, the access key ID portion needs to be embedded in the request. Unless you send the file through your own web service, you'll have to embed it in the app.
The main issue I have is that I either need to store my aws credentials in the application or use some other scheme.
Does Windows have a system-wide service similar to Apple's Keychain Manager? If so, put your credentials there. If not, perhaps you can build a watered-down version of it for storing a strongly-encrypted version of your AWS credentials.
Does the signature require all the data from a file thats being uploaded?
The HMAC SHA-1 signature is an encoded encryption of the HTTP request headers. This signature is a hash value and will be very short relative to your data, only 20 bytes long.
You can encrypt the config file and/or use ProtectedData. Here's my blog post on both.
UPDATE: You might be a be to encrypt your app.config as part of an install step. Sample here: http://www.codeproject.com/KB/security/encryptstrings.aspx. Not great, but the best I've found so far.
Will you let anyone that gets a hold of a copy of your program access the data on S3/SimpleDB? If not, you will need your own authentication scheme that's independent from AWS security.
In that case, you could implement a web service that accepts the credentials that you give your customers (a username/password for example, a digital certificate, etc) and then performs the S3/SimpleDB operations that your program requires. That way, the AWS credentials never leave AWS. If a particular user's credentials are compromised, you can cancel those credentials in your web service.

Categories

Resources