Key encryption in ASP.NET Core - c#

I am using Microsoft.AspNetCore.DataProtection in ASP.NET Core 2.0 application for data protection. And for the default settings I have added below code in Startup.cs file
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddDataProtection().ProtectKeysWithDpapi();
...
...
}
But that code throws an error:
InvalidOperationException: The 'IXmlRepository' instance could not be found. When an 'IXmlEncryptor' instance is set, a corresponding 'IXmlRepository' instance must also be set.
Did I miss something in this implementation?

You specified how to encrypt the keys (the Windows DPAPI implementation of IXmlEncryptor) but you did not specify where to persist the encryption keys (the IXmlRepository). There are various options to persist the keys, for example the file system, registry or some remote location in the cloud.
Try using PersistKeysToFileSystem() or PersistKeysToRegistry(). I suggest you take a look at the documentation regarding ASP.NET Core Data Protection configuration.

Related

Identity Server still including in-memory keys in discovery doc after providing custom implementation of ISigningCredentialStore

I'm working on an app that uses the IdentityServer6 library. Out of the box this seems to use a pair of in-memory signing keys which I can see in the jwks discovery doc when run locally.
I've now provided a custom implementation of ISigningCredentialStore and IValidationKeysStore to load my own key pair from an external source. These I've registered as per the docs like this:
builder.Services.AddSingleton<ISigningCredentialStore, MySigningCredentialStore>();
builder.Services.AddSingleton<IValidationKeysStore, MyValidationKeysStore>();
However, when I run this I now get the original pair of keys, plus my own two in the discovery doc, so four in total. So how can I stop IdentityServer using its own keys?
OK, I worked this out. Needed to set KeyManagement.Enabled to false in the options for AddIdentityServer.

appsettings.json and azure function by timer

I am pretty a new at azure function development
and I a not really understand how configuration for azure function, especially for local development
I need to set up some parameters at configuration and use them at my code
I have appsettings.json and local.settings.json
I added IConfiguration configuration as parameter to constructor to some my class
and try to get value by calling
_configuration["MyVar"]
but values are always null. (like it not read appsettings.json)
that is the best practice to get/set some parameters values for local test and use them after on azure side.
You can set your configuration values in local.settings.json for debugging and in the Function AppSettings in Azure Portal for when it's deployed. If you want to use a custom appsettings file, you need a FunctionStartup class.
You won't be able to configure the trigger bindings in the appsettings file, you'll have to use the Function AppSettings for that. Please see this StackOverflow post for more details.
Recommended way to read App settings in Azure functions(in App Service) is:
var value = Environment.GetEnvironmentVariable("your_key_here");
Check out this article for detailed explanation: Azure — Reading application settings in Azure Functions (ASP.NET Core)

Problem on CORS configuration with Web Api 2, OWIN and Identity Server

I have a few web applications under the same domain, all using a stand alone Identity Server 3 app for login purposes. Under test environment, every single one of then are under the same domain (http://192.168.100.1, or by dns http://companyServer).
Recently, one application needed to request some data from another app, and I found the following error when debugging on Visual Studio:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://companyServer:60000/MyApp/Api/Company/Info?parameter=123. (Reason: CORS header 'Access-Control-Allow-Origin' not present).
We have a central library responsible for configuring Web API on our systems, it has the following (among other things):
public static IAppBuilder UseCebiUtilWebApi(this IAppBuilder app, CebiWebApiOptions options)
{
Logger.Debug("Configuring Web API");
app.UseCors(CorsOptions.AllowAll);
...
}
On the same method, we also configure Identity Server.
I also checked on my Login Server App, and there is the following code regarding CORS:
public class CompanyCorsPolicyService : DefaultCorsPolicyService
{
public CompanyCorsPolicyService()
{
base.AllowAll = true;
}
}
This method is being called on the project's Startup.cs.
As far as I know, every single end of my environmet should be enabling full CORS access, no matter the origin. But the header is still missing.
I've tried quite a few solutions on the internet:
Using "config.EnableCors" instead of "app.UseCors"
Overriding GrantResourceOwnerCredentials,
I have also tried setting up manually some CORS related headers on Web.Config, but I was unable to find the specific question here on SO.
I don't think identity server is related to this problem, but since that is the difference between my evironment and the solutions I've found, I decided to put it in here too.
Any ideas?
It's possible that the OPTIONSVerbHandler could be intercepting all OPTIONS (CORS pre-flight) requests.
Try disabling that so that ASP.Net can handle those requests instead.

How to set Sentry log level in runtime in .NET Core?

I'm using Sentry with .NET Core which is currently configured as
"SentryOptions": {
"Dsn": "https://...",
"LogLevel": "Error",
"UseRequestFactory": false,
"IsDisabled": false
},
which is loaded in ConfigureServices
serviceCollection.AddTransient<ISentryProvider, SentryProvider>();
serviceCollection.AddOptions().Configure<SentryOptions>(section);
Is there a way to change LogLevel in runtime? I don't want to have to change the appsettings.json and re-deploy just to toggle a config.
Is this a ASP.NET Core app or just .NET Core using generic Host? Are you using the Sentry.AspNetCore integration? That integration does load the Sentry key from appsettings.json automatically so you don't need to touch the DI container for any Sentry configuration. It has docs here.
Sentry.AspNetCore depends on Sentry.Extension.Logging (docs here) so it brings the support to capturing all LogErrors and higher as errors and LogInformation and lower as breadcrumbs (default settings). That means you can use DI to take IHub or ISentryClient anywhere in your app.
Your answer is likely: The specific settings MinimumBreadcrumbLevel and MinimumEventLevel are not reloaded if you change their value in the appsettings.json. For example, you could disable Sentry altogether:
{
"Logging": {
"LogLevel": {
"Sentry": "None", // Disables Sentry
}
}
More details on the ASP.NET docs.
Since this is an integration built on top of the Microsoft.Extensions.Logging package, you can configure the general app's log level and it should affect Sentry's loggers. They don't have auto reload of configuration at a higher level. It's the job of each logging provider to reload the configuration.
A way around this if you'd like to try (undocumented/unsupported): You could resole the IOptions<SentryOptions> from the container (don't register it yourself, the SDK already does that) and change the LogLevels at runtime. The logger instance holds a reference to the options and checks the level at runtime:
https://github.com/getsentry/sentry-dotnet/blob/f5f57545a1f17820d8beda3238ad76fc7ceac7ef/src/Sentry.Extensions.Logging/SentryLogger.cs#L40-L41
Finally, note that if you use Serilog, it changes the logging backend a things are different in that case. Sentry offers a Sentry.Serilog package too.

.Net Core Machine Key alternative for webfarm

I have been using dotnet core to create an application that runs in a Kubernetes cluster on Linux hosts. As I was testing it noticed getting exceptions when validating the CSRF tokens, that makes sense since I did not edit the machine key to be the same on every instance yet. As i proceeded to set the machine key in web.config i noticed this would no longer work in .Net Core.
As is is now using the DataProtection API, the machine key no longer worked. I tried implementing the api into my application, but when i read i would need to use a network share to exchange the keys between all instances i was stunned. Surely there must be an easier (and better) way to accomplish this without having to rely on a share to be online right?
i tried to set the following in the Startup class in the ConfigureServices method:
services.AddDataProtection().SetApplicationName("DockerTestApplication");
I somehow expected the keys to be generated using the applicationname, but this did not resolve the issue.
I found some interesting docs that all use code that will no longer compile, i guess Microsoft changed up some things:
https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/compatibility/replacing-machinekey
Does anyone know a solution to this problem that will also run on Linux and has the ability to share the tokens over the network between instances?
Thanks in advance!
I've made some tests to back up my comment about copying keys. First I created simple console application with the following code:
var serviceCollection = new ServiceCollection();
serviceCollection.AddDataProtection()
.SetApplicationName("my-app")
.PersistKeysToFileSystem(new DirectoryInfo(#"G:\tmp\so\keys"));
var services = serviceCollection.BuildServiceProvider();
var provider = services.GetService<IDataProtectionProvider>();
var protector = provider.CreateProtector("some_purpose");
Console.WriteLine(Convert.ToBase64String(protector.Protect(Encoding.UTF8.GetBytes("hello world"))));
So, just create DI container, register data protection there with specific folder for keys, resolve and protect something.
This generated the following key file in target folder:
<?xml version="1.0" encoding="utf-8"?>
<key id="e6cbce11-9afd-43e6-94be-3f6057cb8a87" version="1">
<creationDate>2017-04-10T15:28:18.0565235Z</creationDate>
<activationDate>2017-04-10T15:28:18.0144946Z</activationDate>
<expirationDate>2017-07-09T15:28:18.0144946Z</expirationDate>
<descriptor deserializerType="Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=1.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60">
<descriptor>
<encryption algorithm="AES_256_CBC" />
<validation algorithm="HMACSHA256" />
<masterKey p4:requiresEncryption="true" xmlns:p4="http://schemas.asp.net/2015/03/dataProtection">
<!-- Warning: the key below is in an unencrypted form. -->
<value>rVDib1M1BjbCqGctcP+N25zb+Xli9VWX46Y7+9tsoGywGnIg4p9K5QTM+c388i0mC0JBSLaFS2pZBRdR49hsLQ==</value>
</masterKey>
</descriptor>
</descriptor>
</key>
As you see, file is relatively simple. It states creation, activation, expiration dates, algorithms used, reference to deserializer class and of course key itself.
Now I configured asp.net application (so, another application, not that console one) like this:
services.AddDataProtection()
.SetApplicationName("my-app")
.PersistKeysToFileSystem(new DirectoryInfo(#"G:\tmp\so\keys-asp"))
.DisableAutomaticKeyGeneration();
If you now try to run application and do something that requires protection - it will fail, because there no keys and automatic key generation is disabled. However, if I copy keys generated by console app to the target folder - it will
happily use them.
So pay attention to the usual security concerns with copying keys, to expiration time of those keys (configurable with SetDefaultKeyLifetime) and using the same version of Microsoft.AspNetCore.DataProtection in all applications you share keys with (because it's version is specified in key xml file) - and you should be fine. It's better to generate your shared keys in one place and in all other places set DisableAutomaticKeyGeneration.

Categories