Skip to content

fix: Throw exception on invalid base64#576

Open
Oinkling wants to merge 4 commits intofirebase:mainfrom
Oinkling:strict-base64
Open

fix: Throw exception on invalid base64#576
Oinkling wants to merge 4 commits intofirebase:mainfrom
Oinkling:strict-base64

Conversation

@Oinkling
Copy link

@Oinkling Oinkling commented Aug 8, 2024

Fixed JWT::urlsafeB64Decode not actually throwing an InvalidArgumentException on invalid base64 characters, despite doc comment saying that it does.

Fixed JWT::urlsafeB64Decode not actually throwing an
InvalidArgumentException on invalid base64 characters, despite doc
comment saying that it does.
@bshaffer
Copy link
Collaborator

bshaffer commented Apr 9, 2025

It looks like it currently throws an InvalidArgumentException but you want it to throw a UnexpectedValueException?

As this would be a breaking change, wouldn't it be better to just reflect the doc comment to match what's happening, rather than alter the existing behavior?

@Oinkling
Copy link
Author

The current behavior of urlsafeB64Decode is to call base64_decode using the default value (false) for the $strict parameter.
This will result in PHP just ignoring any characters that are not a part of base64 and as such never actually fail, despite the documentation saying that it will.
Since a valid JWT will never contain any characters that are outside of base64url I don't think this should be considered a breaking change as those tokens would most likely have triggered one of the other exceptions that validates the token anyway.

In regards to the changing I do in decode with InvalidArgumentException to UnexpectedValueException
As explained above the current behavior is to ignore invalid characters, the fact that urlsafeB64Decode even throws an InvalidArgumentException now is because of my change, so that change in itself doesn't break much.
The reason I change them to UnexpectedValueException is because every other validation error in decode uses that exception, so any try/catch around it will still work as normal, introducing no breaking changes, only adding more explanations as to what went wrong.

I would had had urlsafeB64Decode simply throw an UnexpectedValueException and then not having to do all the converting up in decode if it weren't for the documentation stating that it should throw an InvalidArgumentException

Last change still allowed input that was invalid base64URL but valid
base64
@Oinkling
Copy link
Author

I have added tests to demonstrate the error I described

However, while working on that I realized that my solution would still allow invalid base64URL through, as long as it is valid base64. I have also fixed that now.

Copy link
Collaborator

@bshaffer bshaffer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this should be considered a breaking change

Unfortunately, I think this is still a breaking change. I wish we had merged this for the 7.0 release, because it's a good change. But I don't feel comfortable validating these errors differently without protecting them behind a new major version.

try {
$headerRaw = static::urlsafeB64Decode($headb64);
} catch (InvalidArgumentException $e) {
throw new UnexpectedValueException('Unable to decode header');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

every other validation error in decode uses that exception

This method also can throw InvalidArgumentException, although you're right the majority of validation in this method throws UnexpectedValueException


public function testMalformedBase64Url()
{
$this->expectException(InvalidArgumentException::class);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add checking the exception message as well using expectExceptionMessage? Same with the test below

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants