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

Still vulnerable with multiple allowed algorithms #1

Closed
cschomburg opened this issue Aug 11, 2021 · 3 comments
Closed

Still vulnerable with multiple allowed algorithms #1

cschomburg opened this issue Aug 11, 2021 · 3 comments

Comments

@cschomburg
Copy link

Maybe I'm missing something obvious, but I tried your library and it is still vulnerable to type confusion when using multiple allowed algorithms (i.e. your first example in firebase/php-jwt#351).

Furthermore your JWT::encode function has two problems:

  • Encode does not work when you supply a keyring (keyId check is wrong)
  • PHPDoc parameters are wrong for $key, $keyId and $head

Consider this test case:

<?php

use ParagonIE\PhpJwtGuard\JWT;
use ParagonIE\PhpJwtGuard\KeyRing;
use PHPUnit\Framework\TestCase;

class JWTTest extends TestCase
{
    public function testConfusion(): void
    {
        $hsKey = hash('sha256', 'phpunit-test-key-for-issue-351');

        $esPubkey = <<<END
            -----BEGIN PUBLIC KEY-----
            MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEVs/o5+uQbTjL3chynL4wXgUg2R9
            q9UU8I5mEovUf86QZ7kOBIjJwqnzD1omageEHWwHdBO6B+dFabmdT9POxg==
            -----END PUBLIC KEY-----
            END;

        $keyring = new KeyRing();
        $keyring->with('HS256', 'foo', $hsKey);
        $keyring->with('ES256', 'bar', $esPubkey);

        $payload = ['sub' => 'phpunit'];
        $token = JWT::encode($payload, $esPubkey, 'HS256', 'bar'); // wrong algo

        $fail = false;
        try {
            JWT::decode($token, $keyring, ['HS256', 'ES256']);
            $fail = true;
        } catch (UnexpectedValueException $ex) {
        }
        $this->assertFalse($fail, 'Expected an exception');
    }

    public function testEncode(): void
    {
        $keyring = new KeyRing();
        $keyring->with('HS256', 'foo', hash('sha256', 'phpunit-test-key-for-issue-351'));

        $payload = ['sub' => 'phpunit'];
        JWT::encode($payload, $keyring, 'HS256', 'foo'); // should not throw exception
    }
}
@paragonie-security
Copy link
Collaborator

The first example in that example is actually a dud created in haste when trying to understand the full impact of the finding, and we need to correct it because it's confusing people.

If you are permitting both algorithms, explicitly, in the same call, then you've deliberately made the choice to permit algorithm confusion. You can permit none as well.

If your argument is, "We should prevent that in this wrapper library too," then that's worth considering.

@cschomburg
Copy link
Author

I definitely think it's worth considering, since I ran into this issue and immediately tried the wrapper after seeing your post as a hotfix, with the impression that it also prevents the problem with multiple allowed algorithms.

Or alternatively you might want to state explicitly in the README that this is not covered, since I suspect other people will run into the same issue and may be misled into thinking it will fix the issue.

Thanks for your immediate response and making people aware of this vulnerability!

paragonie-security added a commit that referenced this issue Aug 11, 2021
- We guard against invalid algorithms by partitioning by algorithm first
- Fix the JWT::encode() wrapping

Thanks @cschomburg for this report
@paragonie-security
Copy link
Collaborator

This is fixed in v0.3.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants