-
Notifications
You must be signed in to change notification settings - Fork 10.3k
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
Use Base64Url in WebEncoders #56959
Use Base64Url in WebEncoders #56959
Conversation
235ee9c
to
7e6ff25
Compare
cc: @buyaa-n |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
Should this be taken a step further as outlined in #56426? |
If that's going to be done, it should be done separately from improving the implementation, which will still exist even if the type were obsoleted. And at this point I suggest it's too late to obsolete it for .NET 9 even if we wanted to. |
Ah, we are already entering the finishing straight for the upcoming release. |
I've debugged through why some of the tests are failing. The crux of it is that, despite its name, WebEncoders.Base64UrlDecode actually accepts both Base64 and Base64Url. This seems like an accident, as I don't see any mention of it in comments or documentation, but effectively it works by looking through the input for -_ and replacing them with +/ and then delegating to Convert.FromBase64CharArray, but it's not validating that the input didn't already contain +/. Which means if it was Base64-encoded to begin with, that data will just be passed through to the underlying FromBase64CharArray. And in these tests, there's code producing Base64 rather than Base64Url, e.g. aspnetcore/src/Components/Endpoints/src/DependencyInjection/ServerComponentSerializer.cs Line 46 in 2f79c47
I can see four paths forward then:
I've done (2). @javiercn? |
@stephentoub we should be fine changing the implementation on the server bits to use Base64 to decode always. As far as I remember we always produce Base64 payloads, the reason being that they get embedded in comments, and the special characters for Base64Url include I believe that when we ran into that we switched to Base64 but I can't find the concrete change. I think we should be fine switching to pure Base64 for these serialization/deserialization scenarios. It's our own format that we internally produce and doesn't have to survive across framework versions. |
I'm confused... you want to change the public WebEncoders.Base64UrlDecode methods to only decode Base64? |
@stephentoub let me get back to you later. I was suggesting changing the method Blazor uses. |
@stephentoub looking at this in more depth. Let's see if I understood correctly.
Also, didn't realize that this functionality was added for netstandard2.0 too. Makes me want to take this change more (with a compat switch) and signal the deprecation for the entire package #56426 on 10 (even in 9, but we would have to chat with some folks about it). The reason I think I would be ok with the deprecation is that the changes that are needed here are easy (and likely few). |
Yup. (At least I assume it was an accident; it looks like an unintentional side-effect.)
Ok, I'm aware of the one place I linked to: aspnetcore/src/Components/Endpoints/src/DependencyInjection/ServerComponentSerializer.cs Line 46 in 2f79c47
where that Base64 eventually finds its way here. I'm not sure what else would break if that were changed to instead do Base64Url encoding, but we can try.
Ok, so the changes you'd want to see to what's currently in this PR:
Is that right? |
This one is fine as Base64, I think that's the place where we I'm confused. We should keep the code as is, and if we are using
Yep, I'll make sure we also do a breaking change announcement.
Yep, I think it's fine to keep the check for net standard for max backwards compat.
We need to do a quick check to make sure we didn't intend Base64 and we were relying on this behavior by mistake. In the components case, the data should be Base64 and I'm pretty sure is decoded as Base64 and not Base64Url, but I'm going to double check. |
Base64UrlDecode is used in DataProtectionCommonExtensions.Unprotect: aspnetcore/src/DataProtection/Abstractions/src/DataProtectionCommonExtensions.cs Lines 183 to 198 in 829583b
which is in turn used in tests like these: https://github.com/dotnet/aspnetcore/blob/829583b4d4112d9f8586e8abe4069ec52568767c/src/Components/Endpoints/test/EndpointHtmlRendererTest.cs that get fed input very indirectly from that ServerComponentSerializer. What is it you'd recommend doing here? |
@stephentoub Protect also uses aspnetcore/src/DataProtection/Abstractions/src/DataProtectionCommonExtensions.cs Line 165 in 829583b
The only case where I could think this could potentially cause problems is if someone used another helper to manually convert the bytes, and then did a Convert.ToBase64 on top, and then passed that output to Unprotect later on, which seems far-fetched, and definitely something we can handle inside Unprotect if we need to. (This is so unlikely that I think I'm ok with us just not accounting for this possibility, worst case, there's a compat switch that can be flipped). |
This code: aspnetcore/src/Components/Endpoints/src/DependencyInjection/ServerComponentSerializer.cs Lines 44 to 46 in d98caa8
is not using a Protect that uses Base64UrlEncode. It's calling a different Protect and then passing the output of that to ToBase64String. That Base64 string is finding its way to this Unprotect call, that's doing Base64UrlDecode. |
Ah, I see. This was always meant to do Base64 decoding, so I think it's safe for us to change it to do so. I imagine what we need to do is This was likely accidental on our part and just happened to work precisely because of what you mentioned. I suspect this happened because we tried to optimize the encode path and the decode path just kept working. It gives me a bit of pause as I think someone else might have done something similar. That said, I still think we should go with the app compat switch and get feedback in RC. Worst case, we can flip the switch to be on by default. What do you think? |
Thanks. How would you feel about this perf optimization merging and then separately following up with the larger behavioral change? I think it's likely we'll find it needs to be reverted, and I'd like to not have the use of the new Base64Uri methods caught up in that. |
@stephentoub sounds good. |
No description provided.