A shopping cart application I'm working on jumps domain when it goes from the normal page into the submit-your-details page.
Long story short there are two copies of the application deployed: one server for the 'main' site and one server with an ev certificate running on https for the customer details (including payment; this is a PCI compliance issue).
My question is this:
When jumping from http://shop.domain -> https://secure.domain (and back, if the user browses back), how can I preserve the session?
Its trivial to pass cookies cross domain using JSONP, but I have no idea what to do with them on the remote side to 'reconnect' to the session.
I have read various things about rolling your own custom session provider, etc. etc. but I haven't found one that is more than just generic advice; certainly no examples of how this might be used to rejoin a session.
This is a for an MVC3 c# web app.
Problem with Session's is that they are kept in the same domain.
If you have the 2 applications in sub domains you can always append this to your web.config
<httpCookies domain=".domain.com"/>
and that will do the trick, but if the domains are completely different, the best way is always to roll out your own session provider or use an existing one, like SQL.
You can use for this any Caching System where instead of append variables into a session variable, you append them into the cache as key/value pair, you can always use a NoSQL alternative (plenty of free accounts out there so you can prototyping and make a proof of concept in order to roll out the final bits).
Memcached server is always a good alternative and Couchbase as the community version available for free.
The trick here is to do this:
Cache.AddObject(key + "UserInfo-name", "Bruno Alexandre");
where key could be a query string value appended in global.asax upon session_start
instead of this
Session["UserInfo-name"] = "Bruno Alexandre";
When you create cookie then you must write
Response.AppendCookie("Your cookie name");
To get that the code is something like
if (Request.Cookies["Your cookie name"] != null)
{
string value = Request.Cookies["Your cookie name"].Value;
}
and if there are different solutions then find
machineKey
which need to be same. you get it under
system.web in web.config file
and then write after machineKey
<httpCookies domain=".yourdomainname.com" />
I am creating user session using HttpContext from a function.
HttpContext cu;
string username = cu.User.Identity.Name;
username = Guid.NewGuid().ToString();
cu.Session["username"] = username;
HttpCookie hc = new HttpCookie("username", username);
hc.Domain = ".yourdomain.com";
hc.Expires = DateTime.Now.AddDays(1d);
cu.Response.Cookies.Add(hc);
With this code, I am able to share session within 3 sub-domains.
Related
I have added the following settings inside my web.config file to initiate an API call to external system. So I am storing the API URL + username + password as follows:-
<appSettings>
<add key="ApiURL" value="https://...../servlets/AssetServlet" />
<add key="ApiUserName" value="tmsservice" />
<add key="ApiPassword" value="test2test2" />
Then inside my action method I will be referencing these values when building the web client as follows:-
public ActionResult Create(RackJoin rj, FormCollection formValues)
{
XmlDocument doc = new XmlDocument();
using (var client = new WebClient())
{
var query = HttpUtility.ParseQueryString(string.Empty);
foreach (string key in formValues)
{
query[key] = this.Request.Form[key];
}
query["username"] = System.Web.Configuration.WebConfigurationManager.AppSettings["ApiUserName"];
query["password"] = System.Web.Configuration.WebConfigurationManager.AppSettings["ApiPassword"];
string apiurl = System.Web.Configuration.WebConfigurationManager.AppSettings["ApiURL"];
But in this was I will be exposing the username and password and these can be captured by users, so my question is how I can secure the API username and password?
You can encrypt the web.config with aspnet_regiis. This is to stop people with access to your server from reading sensitive information.
By the way, I would put your config settings inside a class, that can then be injected into your controllers - it will make unit testing easier.
Generally, web.config is a secure file and IIS does not serve it, therefore it will not be exposed to users who are making requests to web server. Web server only serves specific type of files and web.config is surely not one of 'em.
Quite often you save your database connection string in it which includes password. Now imagine an scenario where web.config was not secure. You have created a major security threat to your application.
Therefore, specially as long as your project is not too big, you should not be worrying about it.
Yet, you may have a better approach but creating a project called "Resources" and save all the critical information such as settings, consts, enums and etc in there. That would be a slick and organized approach.
If you are passing the username/password over the wire though (for example in case of a secured API call), you may want to use https to make sure that information that are travelling are encrypted but that has nothing to do with the security of web.config file.
I know this may sound like over engineering, but if you can, you really should use a secret management service, such as AWS Secrets Manager or Azure Key Vault.
By storing your passwords, even in encrypted form, in your web.config or app.config, you creating several problems for yourself:
now your encrypted passwords are going to be committed to your source control, making them accessible to anyone with the read access. To get rid of them properly, you'll need to do a history rewrite (if you are using git) which is a major pain
while you technically can put your passwords in the machine-level config, and outside of the source control, you'll need to update all those files when your password changes
anyone who's got your encrypted password now can try to decrypt it, using either aspnet_regiis.exe tool (if that's what you used to encrypt it), or if you rolled your own security, reverse engineer that using your source code, figuring out what decryption algo & key it is using
whenever you need to change a password, you'll need to make changes to that file & re-deploy the application.
On the other hand, when you use a secret management service, no secrets or decryption key or algorithm is stored in your source code. Retrieving a secret is as simple as this:
For Azure Key Vault:
var keyVaultUrl = "https://<your-key-vault-name>.vault.azure.net/";
var credential = new DefaultAzureCredential();
var client = new SecretClient(vaultUri: new Uri(keyVaultUrl), credential);
KeyVaultSecret secret = client.GetSecret("<your-secret-name>");
Console.WriteLine($"{secret.Name}: {secret.Value}");
For AWS Secrets Manager (skipped some error handling code):
var client = new AmazonSecretsManagerClient(accessKeyId, secretAccessKey,
RegionEndpoint.APSoutheast2);
var request = new GetSecretValueRequest {
SecretId = secretName
};
GetSecretValueResponse response = null;
response = client.GetSecretValueAsync(request).Result;
This approach has lots of advantages over storage of local secrets:
you don't have to mess with storing different values in configs for Prod/Staging/Dev environments -- just read appropriately named secrets (such as '[Dev|Prod|Stag]DBPassword`
only selected few people can have access to the very important secrects (such as, I dunno, say Transfer all $$$ from Deus account to all E-Coin wallets everywhere authorisation code)
if anyone steals your source code (disgruntled employee, accidental leak) non of your passwords have been leaked
changing a password is easy -- you just update it using the could management console and restart the app(s)
I have written a couple of articles, showing how to set up and read secrets with AWS and Azure on my blog, feel free to check it out if you need step-by-step directions and complete source code:
How to use AWS Secrets Manager to store & read passwords in .Net Core apps
How to securely store and retrieve sensitive info in .NET Core apps with Azure Key Vault
The web.config file is just a file on the file system and so you should (mostly) consider its security in the same way as you would any other file. It will not be served by IIS (unless you make a frankly insane config change to IIS - easy to check for, just try and request it with a browser)
It is good practice to secure your website directory (c:/sites/my-site-here or whatever) using folder permissions to just the website app domain user to read the files (and the deployment user if needed) by using normal windows file permissions
So it may not be necessary to encrypt if you have confidence in the security of the web server. However if you are say on shared hosting, or selling the website code, or the source code is public, then it might be wise to encrypt it. it is a little bit hassle some though.
Why use Web.config?
One of the advantages of having data in Web.config as opposed to storing it in Constants, Enums, etc... is that you can change the data for different environments easily.
Protecting data
The best way to secure the data in Web.config is to encrypt them. Instead of encrypting entire sections in the config file as suggested by Joe and user1089766 you can just encrypt the password string and store it in the config.
Retrieving data
You can use a helper function such as the one below to decrypt the keys.
private const readonly string decryptKey = "";
public string GetFromConfig(string key)
{
var encryptedText = System.Web.Configuration.WebConfigurationManager.AppSettings[key];
var plainText = Decrypt(encryptedText, decryptKey);
return plainText;
}
In this way the decryption key will be inside the project common for all environments. But you can change the data in the web.config easily without recompiling your app.
PS: You can change the decryptionKey and the corresponding data with each version to improve security.
I have to encourage you to separate the code from the Keys. Even if you encrypt the file, someone can clone it from your repo and while it is encrypted, you may no longer be able to track the file, or may get access to a key in the future, etc.
Plus as Art indicated (and maybe others in the thread) this makes it is really easy to have a separate set of keys for Dev / Test / Prod / etc. If you encrypt the file, sounds like you are going to either have the same encrypted data and decryption key in all of these environments. You won't necessarily have an easy way to change in one but not the others.
Think about the long game - not just passwords but other configuration information should be loaded and unique per environment (API Keys, etc.)
We use this approach for developers too. I don't want each developer to have their own API key, passwords, etc so they don't have access to systems they don't need. I can shutdown a user's API key if a development laptop is lost. I can rotate dev / test / prod API keys and only have to worry about changing in one place, not inform all users that a file has been updated and they need to re-clone.
I am very confused in my implementation of sessions in asp.net web application. My logic is once user enters user name+password, I validate credentials and then create a new session with some user info[All I am after from this point onward is that this user has access to restricted resources and a user must never be able to access those resources unless he/she is authenticated]. This I validate on each request and the rest. Here is my issue though. I have many places in the website where I have html links, and I read that if I have a link such as
<a href='resource1.aspx'>resource 1</a>
This will generate a new session id, hence in reality invalidating the existing session id, which in my case will be treated as session expired and user is sent to login page. While reading up on this issue I came across an asp.net API method[
Response.ApplyAppPathModifier(url);
] which prepends the session id to each request hence resolving the new session id generation for each link. Though it resolves session breaking issue it does add the session id next to all of the urls and now session id can be seen in the source code( view source for web page). I really don't want to use cookies and want to use session for user sessions...Can some one please help me create a system which will work the way I wish it to ? if I am doing it utterly incorrect, I would really really appreciate a details discussion and if possible some example...Thanks you much in advance..
It looks like you are trying to use cookieless sessions which add a session id to all links in order to be able to track the sessions.
The other (much more common, standard and IMO secure) approach is to use normal sessions, which auto creates a session cookie (when you use the .Session object), and uses that to determin the current session. If you don't want a cookie you'll have to stick with cookieless, and the session id in the url.
I have added the following settings inside my web.config file to initiate an API call to external system. So I am storing the API URL + username + password as follows:-
<appSettings>
<add key="ApiURL" value="https://...../servlets/AssetServlet" />
<add key="ApiUserName" value="tmsservice" />
<add key="ApiPassword" value="test2test2" />
Then inside my action method I will be referencing these values when building the web client as follows:-
public ActionResult Create(RackJoin rj, FormCollection formValues)
{
XmlDocument doc = new XmlDocument();
using (var client = new WebClient())
{
var query = HttpUtility.ParseQueryString(string.Empty);
foreach (string key in formValues)
{
query[key] = this.Request.Form[key];
}
query["username"] = System.Web.Configuration.WebConfigurationManager.AppSettings["ApiUserName"];
query["password"] = System.Web.Configuration.WebConfigurationManager.AppSettings["ApiPassword"];
string apiurl = System.Web.Configuration.WebConfigurationManager.AppSettings["ApiURL"];
But in this was I will be exposing the username and password and these can be captured by users, so my question is how I can secure the API username and password?
You can encrypt the web.config with aspnet_regiis. This is to stop people with access to your server from reading sensitive information.
By the way, I would put your config settings inside a class, that can then be injected into your controllers - it will make unit testing easier.
Generally, web.config is a secure file and IIS does not serve it, therefore it will not be exposed to users who are making requests to web server. Web server only serves specific type of files and web.config is surely not one of 'em.
Quite often you save your database connection string in it which includes password. Now imagine an scenario where web.config was not secure. You have created a major security threat to your application.
Therefore, specially as long as your project is not too big, you should not be worrying about it.
Yet, you may have a better approach but creating a project called "Resources" and save all the critical information such as settings, consts, enums and etc in there. That would be a slick and organized approach.
If you are passing the username/password over the wire though (for example in case of a secured API call), you may want to use https to make sure that information that are travelling are encrypted but that has nothing to do with the security of web.config file.
I know this may sound like over engineering, but if you can, you really should use a secret management service, such as AWS Secrets Manager or Azure Key Vault.
By storing your passwords, even in encrypted form, in your web.config or app.config, you creating several problems for yourself:
now your encrypted passwords are going to be committed to your source control, making them accessible to anyone with the read access. To get rid of them properly, you'll need to do a history rewrite (if you are using git) which is a major pain
while you technically can put your passwords in the machine-level config, and outside of the source control, you'll need to update all those files when your password changes
anyone who's got your encrypted password now can try to decrypt it, using either aspnet_regiis.exe tool (if that's what you used to encrypt it), or if you rolled your own security, reverse engineer that using your source code, figuring out what decryption algo & key it is using
whenever you need to change a password, you'll need to make changes to that file & re-deploy the application.
On the other hand, when you use a secret management service, no secrets or decryption key or algorithm is stored in your source code. Retrieving a secret is as simple as this:
For Azure Key Vault:
var keyVaultUrl = "https://<your-key-vault-name>.vault.azure.net/";
var credential = new DefaultAzureCredential();
var client = new SecretClient(vaultUri: new Uri(keyVaultUrl), credential);
KeyVaultSecret secret = client.GetSecret("<your-secret-name>");
Console.WriteLine($"{secret.Name}: {secret.Value}");
For AWS Secrets Manager (skipped some error handling code):
var client = new AmazonSecretsManagerClient(accessKeyId, secretAccessKey,
RegionEndpoint.APSoutheast2);
var request = new GetSecretValueRequest {
SecretId = secretName
};
GetSecretValueResponse response = null;
response = client.GetSecretValueAsync(request).Result;
This approach has lots of advantages over storage of local secrets:
you don't have to mess with storing different values in configs for Prod/Staging/Dev environments -- just read appropriately named secrets (such as '[Dev|Prod|Stag]DBPassword`
only selected few people can have access to the very important secrects (such as, I dunno, say Transfer all $$$ from Deus account to all E-Coin wallets everywhere authorisation code)
if anyone steals your source code (disgruntled employee, accidental leak) non of your passwords have been leaked
changing a password is easy -- you just update it using the could management console and restart the app(s)
I have written a couple of articles, showing how to set up and read secrets with AWS and Azure on my blog, feel free to check it out if you need step-by-step directions and complete source code:
How to use AWS Secrets Manager to store & read passwords in .Net Core apps
How to securely store and retrieve sensitive info in .NET Core apps with Azure Key Vault
The web.config file is just a file on the file system and so you should (mostly) consider its security in the same way as you would any other file. It will not be served by IIS (unless you make a frankly insane config change to IIS - easy to check for, just try and request it with a browser)
It is good practice to secure your website directory (c:/sites/my-site-here or whatever) using folder permissions to just the website app domain user to read the files (and the deployment user if needed) by using normal windows file permissions
So it may not be necessary to encrypt if you have confidence in the security of the web server. However if you are say on shared hosting, or selling the website code, or the source code is public, then it might be wise to encrypt it. it is a little bit hassle some though.
Why use Web.config?
One of the advantages of having data in Web.config as opposed to storing it in Constants, Enums, etc... is that you can change the data for different environments easily.
Protecting data
The best way to secure the data in Web.config is to encrypt them. Instead of encrypting entire sections in the config file as suggested by Joe and user1089766 you can just encrypt the password string and store it in the config.
Retrieving data
You can use a helper function such as the one below to decrypt the keys.
private const readonly string decryptKey = "";
public string GetFromConfig(string key)
{
var encryptedText = System.Web.Configuration.WebConfigurationManager.AppSettings[key];
var plainText = Decrypt(encryptedText, decryptKey);
return plainText;
}
In this way the decryption key will be inside the project common for all environments. But you can change the data in the web.config easily without recompiling your app.
PS: You can change the decryptionKey and the corresponding data with each version to improve security.
I have to encourage you to separate the code from the Keys. Even if you encrypt the file, someone can clone it from your repo and while it is encrypted, you may no longer be able to track the file, or may get access to a key in the future, etc.
Plus as Art indicated (and maybe others in the thread) this makes it is really easy to have a separate set of keys for Dev / Test / Prod / etc. If you encrypt the file, sounds like you are going to either have the same encrypted data and decryption key in all of these environments. You won't necessarily have an easy way to change in one but not the others.
Think about the long game - not just passwords but other configuration information should be loaded and unique per environment (API Keys, etc.)
We use this approach for developers too. I don't want each developer to have their own API key, passwords, etc so they don't have access to systems they don't need. I can shutdown a user's API key if a development laptop is lost. I can rotate dev / test / prod API keys and only have to worry about changing in one place, not inform all users that a file has been updated and they need to re-clone.
I am facing a very basic problem while building a website ; The website have 10 pages , The problem is that when i login once how can i remain logged in through out the rest of the pages ??
Since this question includes tags for asp.net and sesion variables, I'm not sure what you are missing.
On login form:
if (authentaionSuceeded){
HttpContext.Current.Session["loggedin"]="yes";
}
On all other pages (except for logout)
if (HttpContext.Current.Session["loggedin"]=="yes"){
// whatever you do for logged in users.
}
That's the basic idea. Although I prefer to access the session variable through an extension method/class that provides a type safety and a list of all session variables. The example in that answer is in VB, but you can do the same thing in c#.
There are some possible solutions as below:
Cookies: Store session information in the cookies in the page header
Hidden Form Fields: Maintain the session information in some hidden fields in the page forms
In each option, you need to generate the session key(some encrypted unique key) on the server side and on subsequent request, you should be able to validate that session key. Its better to regenerate a new session key on each request and expire it after certain interval. So for active user, it will keep getting new keys, but inactive user session will simply expire.
I am developing the application that stores current user and user's role to session state (System.Web.SessionState.HttpSessionState Page.Session).
if (Session["username"] == null)
Session.Add("username", User.Identity.Name);
if (Session["isAdministrator"] == null)
Session.Add("isAdministrator", User.IsInRole(domain + "\\Domain Admins"));
After I check these session states in code behind for granting permissions to some excecution:
if ((bool)Session["isAdministrator"] || computer.Administrators.Contains(Session["username"].ToString()))
My question is next: how safe that mechanism is? Is it possible to change the session states using some JavaScript for example or some how else?
Thanks :)
If User.Identity.Name is set, why do you need to put it in the Session? Why don't you just call User.IsInRole(domain + "\\Domain Admins") directly (or wrap it in a helper)? It looks to me like you're using Windows Authentication, so setting the username in the session is redundant.
As for your XSS question, the session stores the session ID in a cookie, so in theory an attacker could be sniffing the HTTP traffic or inject JavaScript code into your pages, get a hold of the cookie, then use it and impersonate another user.
It is not possible to change the session state using javascript or other client-side mechanisms, as the state is only stored on the server. However, it is, as others have pointed out, possible for a malicious user to hijack a session by getting hold of the contents of the session cookie.
ASP.NET is designed with this weakness in mind - the session ID is suitably long and hard to predict. Also, the session cookie is marked as HTTP ONLY, which means that most modern browsers will not allow javascript code to access it.
In general I would say this is very safe from XSS attacks. ASP.Net, by default, tracks a users session based on a Cookie which contains the users session ID. You can see this if you open your browsers cookie list and look for ones from your site, there will be one there named ASP.Net Session something... The SessionID's unique, and not incremental. Probably some variance of a GUID.
For added security you can also specify, in your web.config, how long to keep a users session alive. If you are dealing with sensitive information you might want to set this timeout to be relatively short period of time, maybe 10 minutes of inactivity, the default is 20 minutes. You can find more info # http://msdn.microsoft.com/en-us/library/system.web.sessionstate.httpsessionstate.timeout.aspx.
<system.web>
<sessionState timeout="10" />
</system.web>
--Peter