Where (how?) does IIS store custom application pool identities? - asp.net

I have an application pool that I use for development… and I have it running under my credentials (so I don't have to worry about permission/access issues). Two things make me think my credentials might be just sitting in a file (or registry entry)… which is worrisome:
When I change my password, I have to update the stored credentials
The setup dialog has a confirm password field
If IIS was just storing some authentication token or something, I would expect to only enter my password once (because authentication was happening immediately).
Anyone know where my credentials are being stored? Are they just encrypted using some system key then pulled out and used when the app pool spins up?
Here is the dialog where I'm entering the identity's credentials:
I open that dialog from the app pool's Advanced Settings:
Other Info
IIS 7.5 on Windows 7
I am using virtual accounts for other application pools, but that's not what I'm using here: I'm using actual Windows account credentials
UPDATE
Based on nicolas-dietrich's response, I found the following…
The application pool credentials (and general settings) for IIS 7.5 are stored in %systemroot%\System32\Inetsrv\config\applicationHost.config.
Encryption is handled by AesProtectedConfigurationProvider, which is the standard (?) way to protect sensitive config info (like db connection strings or–you know–passwords)
Here are the relevant sections with sensitive/irrelevant info replaced by ellipses (…):
<configProtectedData>
<providers>
<!-- … -->
<add name="IISWASOnlyAesProvider" type="Microsoft.ApplicationHost.AesProtectedConfigurationProvider" description="Uses an AES session key to encrypt and decrypt" keyContainerName="iisWasKey" cspProviderName="" useOAEP="false" useMachineContainer="true" sessionKey="…" />
</providers>
</configProtectedData>
<system.applicationHost>
<applicationPools>
<add name="DefaultAppPool" queueLength="5000" managedRuntimeVersion="v4.0" />
<add name="GeneralDev" queueLength="5000" autoStart="true">
<processModel identityType="SpecificUser" userName="mydomain\myusername" password="[enc:IISWASOnlyAesProvider:…:enc]" />
</add>
<!-- … -->
<applicationPoolDefaults managedRuntimeVersion="v4.0">
<processModel identityType="ApplicationPoolIdentity" loadUserProfile="true" setProfileEnvironment="false" />
</applicationPoolDefaults>
</applicationPools>
<!-- … -->
</system.applicationHost>
Hopefully, safe enough? ¯\_(ツ)_/¯

In IIS6 the AppPool identities were stored within the IIS metabase (%systemroot%\System32\Inetsrv\metabase.xml) in an encrypted string located under W3SVC/AppPools//WAMUserPass.
That was not so secured though as it was possible to decrypt and to show it as plain text (http://www.jasonsamuel.com/2010/04/28/how-to-get-the-iusr-and-iwam-user-account-passwords-on-an-iis-server/)

Related

Login failed for user '...' in ASP.NET WebAPI

The client application and the sql server instance are on separate machines. I'm working with Entity Framework and have created the Data Model for the database. Locally the application works fine with the database. But after the application has been deployed on IIS, I cannot access to the database. I'm getting the error message:
The underlying provider failed on Open.
Login failed for user 'domain\account'.
In the Web.config of the WebAPI is the connectionString defined as follows:
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
<authentication mode="Windows" />
</system.web>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="mssqllocaldb" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
<connectionStrings>
<add name="QuReContext" connectionString="metadata=res://*/Models.QuReModel.csdl|res://*/Models.QuReModel.ssdl|res://*/Models.QuReModel.msl;provider=System.Data.SqlClient;provider connection string="data source=spartak,2500;initial catalog=First_DB;User Id=domain\account;Password=MyPW;MultipleActiveResultSets=True;"" providerName="System.Data.EntityClient" />
</connectionStrings>
I've tried many kinds of solutions from threads in stackoverflow. But nothing has helped. I'm using the ASP.NET WebAPI 2, the Entity Framework 6, IIS 7.5 on a remote Webserver with Windows Server 2008 R2 and the SQL Server 2014 where my domain account is defined for access the database. This domain account I've written in the connection string of Web.config.
On IIS is created in Default Web Site "MyClientApp" and in this application is an extra application "RestApi" available. The Application Pool is defined as follows: Identity: ApplicationPoolIdentity, Managed Pipeline Mode: Integrated, Under the authentication of the application "RestApi" is just Windows authentication and basic authentication enabled.
Do anyone has an idea?
You can set up SQL Server to support two authentication modes:
Integrated (Windows) security
Mixed (Windows + SQL Server logins)
The first mode uses the current user credentials to try to login in SQL Server. In this case, the credentials are the ones from the process running the ASP.NET application, in other words, the app pool user. To specify this kind of login you need to include this in your connection string: Integrated Security=SSPI. (I've seen on some occassions that, apart from specifying integrated security, people specify user and password, but I'm not sure if you can override the current user credentials. In fact, I think that only worked in Windows CE).
The second mode supports integrated security, and also SQL Server logins, where the user and passwords are managed by SQL Server itself, and have nothing to do with Windows users and passwords. To authenticate a SQL Server login you must specify the user ID and password as you're doing in your query string: User Id=myUsername; Password=myPassword;
You should read about integrated and mixed security mode in SQL Server. This is quite an old information, but still applies.

Asp.net delegation

I am making a .Net Web API that gets data by calling an SQL server. The user is authenticated via Windows Authentication (Kerberos). I would like the user credentials to be passed to the SQL server via delegation, but the SQL server sees an anonymous user.
This is what I have done:
IIS application:
Windows Authentication and asp.net impersonation enabled. Anonymous and forms authentication disabled.
Enable kernel mode authentication is checked.
Providers: Negotiate, Kerberos.
Use app pool credentials: True.
Application pool:
Managed pipeline mode: Classic.
Identity: Network service.
In AD, the computer the web server runs on is set to "Trust this computer for delegation to any specific service (Kerberos only)"
The connection string to the SQL server contains Integrated Security=SSPI;
Edit: In my web.config I have
<system.web>
<authentication mode="Windows" />
<identity impersonate="true" />
</system.web>
and
<security>
<authentication>
<windowsAuthentication enabled="true">
<providers>
<clear />
<add value="Negotiate" />
<add value="Kerberos" />
</providers>
<extendedProtection tokenChecking="None" />
</windowsAuthentication>
<anonymousAuthentication enabled="false" />
</authentication>
</security>
The generic HOST spn is set for the machine.
From the browser I access the web application via http://machinename.domain.net.
I would expect in this setup that my IIS application is run under the machine account?
When I catch a request in the debugger on the web server, I can see that WindowsIdentity.GetCurrent().Name is the account of the user browsing the web application and WindowsIdentity.GetCurrent().AuthenticationType is set to "Kerberos". So that should be good.
However WindowsIdentity.GetCurrent().ImpersonationLevel is only set to "Impersonate". I would have expected it to be set to "Delegate"?
When I make a request to the SQL server, I get "Login failed for user 'NT AUTHORITY\ANONYMOUS LOGON'" so obviously the user credentials are not passed to the SQL server.
I hope someone can see what I am doing wrong. I really need a push in the right direction.
For future reference if someone runs into the same issue:
The issue was that we tried from Chrome. It works in IE, but on Chrome the registry change mentioned in this post was needed: Kerberos delegation doesn't work in chrome
You should be able to set the Authentication to ASP.NET Impersonation within IIS. You will probably be required to set the following in your web.config file too, as part of < system.web> section.
<identity impersonate="true" />
This may be required in the < system.webServer> section to, although not always recommended due to security concerns.
<validation validateIntegratedModeConfiguration="false" />

Azure Configuration Settings More Secure than Web.Config?

I'm using Azure Cloud Services, not Web Sites.
I would like to know if storing sensitive data (passwords) in Azure Service Configuration Settings is secure.
I really don't want to implement the 4-part blog series required to encrypt the web.config in Azure Web Roles, so I'm thinking I could just keep my settings in Azure config and then access them through RoleEnvironment.GetConfigurationSettingValue().
These settings are in a config file much like web.config, so my question is whether this config file is just used to build the cloud service and then discarded, or if it stays on disk during the life of the instance (thereby exposing sensitive data to attack).
I like the ability to update these settings at runtime through the Portal and I consider the Portal a secure endpoint, so I'm OK with it. However, if the file stays on disk then it is no more secure than the web.config file IMHO.
We encrypt/decrypt Azure config settings and other content using the domain certificate installed on the web roles. I posted a full example on my blog here: Securing Azure ServiceConfiguration values for Enterprise Deployment.
I created a feature request: http://feedback.azure.com/forums/34192--general-feedback/suggestions/9025255-certificate-based-settings-encryption
This is similar (but more idiomatic, imho) to what Remote Desktop plugin does. Remote Desktop adds:
<ConfigurationSettings>
<Setting name="Microsoft.WindowsAzure.Plugins.RemoteAccess.Enabled" value="true" />
<Setting name="Microsoft.WindowsAzure.Plugins.RemoteAccess.AccountUsername" value="<name-of-user-account>" />
<Setting name="Microsoft.WindowsAzure.Plugins.RemoteAccess.AccountEncryptedPassword" value="<base-64-encrypted-password>" />
<Setting name="Microsoft.WindowsAzure.Plugins.RemoteAccess.AccountExpiration" value="<certificate-expiration>" />
<Setting name="Microsoft.WindowsAzure.Plugins.RemoteForwarder.Enabled" value="true" />
</ConfigurationSettings>
<Certificates>
<Certificate name="Microsoft.WindowsAzure.Plugins.RemoteAccess.PasswordEncryption" thumbprint="<certificate-thumbprint>" thumbprintAlgorithm="sha1" />
</Certificates>
RDP plugin "knows" Microsoft.WindowsAzure.Plugins.RemoteAccess.AccountEncryptedPassword value is encrypted will use the certificate Microsoft.WindowsAzure.Plugins.RemoteAccess.PasswordEncryption to decrypt it.
My feature request is to add attribute named thumbprint to <Setting /> node. Calls to CloudCloudConfigurationManager.GetSetting() would seamlessly decrypt the value using the certificate indicated.
How wonderful that would be...

ASP.NET Oracle ODP.NET Integrated Security Slowness

The following results in successful sub-second page loads.
<add name="test"
connectionString="Data Source=TEST_ORACLE;User Id=user;Password=password;" />
The following subtle change to use the app pool's custom identity results in successful page loads that are 20+ times slower.
<add name="test"
connectionString="Data Source=TEST_ORACLE;User Id=/;" />
It appears that I at least got the trusted connection to work. What am I missing?
Try Integrated Security=SSPI; instead of User Id=/;
Does your app pool identity have network logon rights?
The connections strings that I use look like
<add
name="myOracleConnection"
connectionString="Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=MyServer)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=XE))); User Id=MyUser; Password=MyPassword;"
providerName="system.data.oracleclient"/>
I.e. I do not rely on these external configuration files (were they named .ora? I forgot it).
Maybe you can lower dependencies and side-effects if you also try to make your connection string self-containing with everything included?

Why is ASP.NET ignoring my Membership connection string?

I have an ASP.NET app using built-in Membership functionality. As such, I have a connection string in my web.config that looks like this:
<add name="MembershipSqlServer" connectionString="Data Source=servername;Database=aspnetdb;uid=user;pwd=password;" />
When working on my dev machine, everything is peachy keen. But when I move things to the web server (which also happens to run the SQL Server), I get this error when User.IsInRole() is called:
System.Data.SqlClient.SqlException: Login failed for user 'NT AUTHORITY\NETWORK SERVICE'.
F$%*&!! Why is it attempting to connect in this way? Why isn't it using user/password from the connection string? Web.config is identical on dev and server, I am using the DB on the server during development.
OK, I figured it out... only 35 minutes. :P
Long story short: There are two parts to asp.net membership… a membership provider and a ROLE provider. Why you’d ever want these two things separated, I don’t know… But my web.config wasn’t specifying the role provider and connection string, so it was defaulting to the settings in machine.config (aka LocalSqlServer connection string).
So all this time, my app users were on the server... but the roles were stored in a local .MDF file in App_Data. Ugh.
What does the membership providers section in your web.config look like? Is it possible that you left out the connectionStringName attribute? In which case, I believe it would be trying to connect to the database on your local machine using integrated security.
The membership providers section in your web.config should look something like:
<membership defaultProvider="SqlProvider">
<providers>
<add
name="SqlProvider"
type="System.Web.Security.SqlMembershipProvider"
connectionStringName="MembershipSqlServer"
...
/>
</providers>
</membership>
Do you see this <authentication mode="Windows" /> in your web.config? And your other connectionString uses Integrated Security=True; On your Sql server in order to use windows authentication you must have a Login(on the server) for the windows user or group as well as have an associated user in the database.
The simple but not suggested fix would be to create a login for 'NT AUTHORITY\NETWORK SERVICE'
on you sql server and then a user in your specific database for that maps to that login.
The secure way is to do this for each of the network security groups that need to access the sql server so you can manage the group permissions independently.
i think the answer is that :
public static string ConnectionString(SPSite site)
{
var connectionStringField = BaseMembershipProvider(site).GetType().GetField("_sqlConnectionString", BindingFlags.Instance | BindingFlags.NonPublic);
if (connectionStringField != null)
{
return connectionStringField.GetValue(BaseMembershipProvider(site)).ToString();
}
else
{
return "";
}
}
it worked for me with out any Error
thanks babania

Resources