Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blazor: HMAC encryption not supported #1865

Closed
ealsur opened this issue Sep 21, 2020 · 38 comments
Closed

Blazor: HMAC encryption not supported #1865

ealsur opened this issue Sep 21, 2020 · 38 comments
Assignees
Labels
Engineering engineering improvements (CI, tests, etc.)

Comments

@ealsur
Copy link
Member

ealsur commented Sep 21, 2020

No description provided.

@ealsur ealsur added the Engineering engineering improvements (CI, tests, etc.) label Sep 21, 2020
@ealsur ealsur self-assigned this Sep 21, 2020
@dotnetspark
Copy link

@ealsur, when is this update coming up?

@ealsur
Copy link
Member Author

ealsur commented Sep 22, 2020

If you refer to the merged PR, it will be shipped in the upcoming release, I don't have the exact date but it should be this week/early the next I'm guessing

@dotnetspark
Copy link

thanks

@ealsur
Copy link
Member Author

ealsur commented Sep 23, 2020

@ylr-research fix is in 3.13.0 released today

@dotnetspark
Copy link

dotnetspark commented Sep 23, 2020

Just upgraded and ran the app see the new error

image

I'm keeping the same code in Program.cs

            builder.Services.AddHttpClient();
            builder.Services.AddSingleton<CosmosClient>(serviceProvider =>
            {
                IHttpClientFactory httpClientFactory = serviceProvider.GetRequiredService<IHttpClientFactory>();

                CosmosClientOptions cosmosClientOptions = new CosmosClientOptions
                {
                    HttpClientFactory = httpClientFactory.CreateClient,
                    ConnectionMode = ConnectionMode.Gateway
                };

                return new CosmosClient("<endpointConnectionString>", cosmosClientOptions);
            });

@ealsur
Copy link
Member Author

ealsur commented Sep 24, 2020

Mmm can you try to do a clean of the solution, delete any pre-existing binary folders? I just tried a basic Blazor WASM app and it worked and was able to list data without issues.

I pulled 3.13.0 into a new Blazor WASM app, registered it, and used it to call UpsertItemAsync:

image

@dotnetspark
Copy link

@ealsur you were right. The app is now initializing properly. However, when I query a container I get this errors

image

Here you can see my code. It was working before.

            var container = CosmosClient.GetContainer("Database", "Container");
            var iterator = container
                .GetItemLinqQueryable<IDictionary<string, string>>(true)
                .Where(m => m["name"].Contains(prefix))
                .ToFeedIterator();

            while (iterator.HasMoreResults)
            {
                // Todo
            }

@ealsur
Copy link
Member Author

ealsur commented Sep 24, 2020

I cannot repro, the query executes and I can get a page of results:

The HTTP POST is the query execution. The app is running on Edge.

image

@dotnetspark
Copy link

dotnetspark commented Sep 24, 2020

@ealsur I'm opening all connection and sharing my endpoint connection string, database and container. See if you can get data. Maybe it's a setting I'm missing, and not directly related to the SDK.
endpoint: AccountEndpoint=
Database: InventoryDataStore
Container: Products

@ealsur
Copy link
Member Author

ealsur commented Sep 24, 2020

You seem to have CORS enabled
image

@dotnetspark
Copy link

I see. I've seen it before. I basically had to add an entry to allow localhost. Just recently I removed the DB account and created it again. I forgot about that setting. It should work now. Give it a try

@dotnetspark
Copy link

I just tried myself an got the same error. I checked Program.cs and don't anything about CORS.

@ealsur
Copy link
Member Author

ealsur commented Sep 24, 2020

Maybe you need to use * for CORS settings?

@dotnetspark
Copy link

dotnetspark commented Sep 24, 2020

Just did and the error is still the same. Were you able to get data?

image

@ealsur
Copy link
Member Author

ealsur commented Sep 24, 2020

Yes, and I was able to print the Ids of all your docs (I removed the Contains filter).

Microsoft.Azure.Cosmos.FeedIterator<dynamic> iterator = CosmosClient.GetContainer("InventoryDataStore", "Products")
        .GetItemQueryIterator<dynamic>(queryText: "SELECT * FROM c");
while (iterator.HasMoreResults)
{
    Microsoft.Azure.Cosmos.FeedResponse<dynamic> rr = await iterator.ReadNextAsync();
    foreach (dynamic item in rr)
    {
        Console.WriteLine("id " + item.id);
    }
}

You can see that the query is hitting your account, and then it prints the ids.

image

I suggest you rotate those keys immediately and edit your comment to remove the keys.

@dotnetspark
Copy link

Yes, thanks.

See below. I just copied your code.

image

@ealsur
Copy link
Member Author

ealsur commented Sep 24, 2020

I cannot get it to repro but I have found several issues related to this on newer WASM versions, previous WASM versions were based off Mono, see dotnet/aspnetcore#26123, dotnet/runtime#40074, dotnet/runtime#40076. Also it seems they are adding it back in RC2 dotnet/runtime#41761?

My environment seems to still be using the older WASM based off Mono, so this is working.

@dotnetspark
Copy link

I just have to wait for RC2 to come out?

@ealsur
Copy link
Member Author

ealsur commented Sep 24, 2020

That's what I understand from those PRs. In my WASM project I'm running on NET Core 3.1 with the Blazor 3.2.1 packages, but it seems like new Blazor apps on newer VS versions use .NET 5 rc1 and the rc1 Blazor packages. There isn't much we can do on our side, SHA256 is the algorithm used to generate the auth headers on requests.

@lewing
Copy link

lewing commented Oct 2, 2020

The SHA* hash algorithms were added back in RC2 as a special exception to policy. That exception did not extend code dealing with secrets so HMAC computations were not included. Given that, there isn't anything we can do on the runtime side either. I'm not familiar enough to be sure but if there is a way to supply a custom asynchronous authentication provider you might be able to use the Blazor interop code to call into the browser and use crypto.sign to generate your authentication code. Unfortunately it won't be possible to use System.Security to do it in net5.0.

cc @GrabYourPitchforks

@ealsur ealsur changed the title Add Blazor WASM test project Blazor: HMAC encryption not supported Oct 2, 2020
@GrabYourPitchforks
Copy link

Larry's comment is correct. The .NET security team and MS Crypto Board concluded that given limitations of the Blazor runtime, we could not safely include support for keyed algorithms (HMAC, RSA, AES, etc.) in the .NET 5 release. Please feel free to email me or ping me on Teams if you need more background or need to discuss workarounds.

Blazor runtime support for keyed algorithms (including HMAC) is planned for 6.0.

@23min
Copy link

23min commented Oct 3, 2020

I get this when I upload to blob storage using Azure.Storage.

System.PlatformNotSupportedException: System.Security.Cryptography.Algorithms is not supported on this platform.
   at System.Security.Cryptography.HMACSHA256..ctor(Byte[] key)
   at Azure.Storage.StorageSharedKeyCredential.ComputeHMACSHA256(String message)
   at Azure.Storage.StorageSharedKeyCredential.ComputeSasSignature(StorageSharedKeyCredential credential, String message)
   at Azure.Storage.StorageSharedKeyCredentialInternals.ComputeSasSignature(StorageSharedKeyCredential credential, String message)
   at 

@ealsur
Copy link
Member Author

ealsur commented Oct 5, 2020

@23min I don't think that is related to the Cosmos DB SDK. Could you please post that in the SDK repo related to that particular library? The authors might be able to help further (it might be related to the Issues in the dotnet repo linked here, so might want to link that)

@23min
Copy link

23min commented Oct 5, 2020

@ealsur, sure I can do that.
Just saying, it's System.Security.Cryptography.HMACSHA256..ctor that's catching, exact same fault.
It's not unique to Cosmos DB SDK.

@ScottRFrost
Copy link

For what it's worth, I believe that not having HMAC / etc is a major breaking change / step backwards in functionality for going from .NET Core 3.x to .NET 5. It's not a trivial / edge case for a Blazor app to use cryptography in this way.

It was difficult to track down this issue all the way to Github, and I honestly only found it because I knew the exact error text after I tried to implement it.

I believe the upgrade breaking change documentation at https://docs.microsoft.com/en-us/dotnet/core/compatibility/3.1-5.0 should be updated to include this major issue. This will hopefully prevent people from spending hours attempting to upgrade their Blazor apps to .NET 5 and ending up dead in the water until .NET 6 comes out a year or more from now.

@ealsur
Copy link
Member Author

ealsur commented Oct 9, 2020

@dotnetspark
Copy link

@ealsur is HMAC API listed?

@ealsur
Copy link
Member Author

ealsur commented Oct 9, 2020

You are right, they are missing the HMAC, I filed a comment on that doc

@23min
Copy link

23min commented Oct 9, 2020

Crazy, so you can not save a blob or save to Cosmos Db from a blazor app and have to build a whole API layer instead.

@ScottRFrost
Copy link

@ealsur I believe https://docs.microsoft.com/en-us/dotnet/core/compatibility/3.1-5.0#systemsecuritycryptography-apis-not-supported-on-blazor-webassembly may be inaccurate.

Affected APIs

All System.Security.Cryptography APIs except the following:
...

  • System.Security.Cryptography.SHA256

...

However, I'm unable to implement something that ONLY uses System.Security.Cryptography.SHA256 without any of the HMAC functions.

My code:

using System.Security.Cryptography;
...
using SHA256 sha256 = SHA256.Create();
var hashed = sha256.ComputeHash(utf8.GetBytes(url+ticks));

ComputeHash throws: CA1416: HashAlgorithm.ComputeHash(byte[]) is unsupported on 'browser'. even at design time.

Unless I'm doing something wrong, this would mean System.Security.Cryptography.SHA256 is NOT supported on Blazor WebAssembly, not just the HMAC functionality, despite the compatibility notes claiming System.Security.Cryptography.SHA256 is an exception.

@campersau
Copy link

@ScottRFrost That was an oversight and is already fixed: dotnet/runtime#43380

@ealsur
Copy link
Member Author

ealsur commented Oct 16, 2020

@23min leaving aside the unsupported Security APIs, it is a good question to ask: Is using Master Keys in a client side application (WASM or even Xamarin for example) a good practice? If you rotate your keys, you just blocked all client side apps, right? In that case, a centralized model that returns access tokens to the clients might be a better approach from a security and availability perspective?

@ScottRFrost
Copy link

ScottRFrost commented Oct 16, 2020

@ealsur the idea is to have separate API keys for each user, and never send the API key over the wire.

If I "sign" my request with an authorization header string that has my username, my UTC time at time of request, and a HMAC of the URL + the UTC time using an API key specific to my user as the HMAC's key, the server simply has to do the same HMAC (it can look up my API key because I provided my username in the request) and compare results. If the server's HMAC matches mine (and the server's UTC time isn't too far off of what I submitted in my request) the request is genuine.

This prevents forged request, requests for other users (just changing my username won't work because other users would have different API keys), and replay attacks (once the UTC time is more than 10 minutes off, just deny the request). If a user's account is compromised, they just change their API key on the server, then whoever had access to the old keys can no longer sign requests.

This is similar to how Amazon does it (and many others) https://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html

Edit - I'm not saying that access token based approaches are bad (if often over-engineered), just that there's nothing wrong with API key + signing with HMAC, as many large companies use it to secure their APIs.

@ealsur
Copy link
Member Author

ealsur commented Oct 16, 2020

@ScottRFrost This issue is on the scope of the Cosmos DB SDK, so I'm limiting the scope of applications interacting with Cosmos DB and the cases where this intersects with the Security APIs being removed on .NET 5 for WASM. I agree that there could be other scenarios where HMAC is needed in architectures, but I believe that discussion would need to happen in the core dotnet repo?

@dotnetspark
Copy link

@ealsur see this thread. The preferred approach is using resource tokens.

@solid-computing
Copy link

Is there workaround to get the HmacSha256 working such as using JavaScript? I need it to connect to AWS cognito Identity.

@ealsur
Copy link
Member Author

ealsur commented Dec 30, 2020

@solid-computing I think you are in the wrong repo, this is for the Azure Cosmos DB SDK.

@ghost
Copy link

ghost commented Dec 15, 2021

Closing due to in-activity, pease feel free to re-open.

@ghost ghost closed this as completed Dec 15, 2021
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Engineering engineering improvements (CI, tests, etc.)
Projects
None yet
Development

No branches or pull requests

8 participants