ecadlabs / signatory

Signatory - A Tezos Remote Signer for signing block-chain operations with private keys using YubiHSM, AWS, GCP, Ledger's or Azure Key Vault
https://signatory.io
Apache License 2.0
62 stars 18 forks source link

authorizing principal from http header "username" instead of from jwt-user claim allows malicious impersonation #372

Closed stephengaudet closed 1 year ago

stephengaudet commented 1 year ago

for the "jwt authZ per PKH feature", Signatory is not authorizing the principal name in the jwt claim "user", rather, it is authorizing the principal name found in the http header "username". this allows for user A to request signing from user B's key.

steps to reproduce: 1.configure 2 jwt users like so:

    c.Server.Jwt = JwtConfig{Users: map[string]*JwtUserData{"username1": {Password: "password1", Secret: secret},
        "username2": {Password: "password2", Secret: secret}}}

2.configure an active key that only authorizes username1 but not username2 like so: c.Tezos[pkh1].JwtUsers = []string{"username1"} 3.get a bearer token for username2 like so:

    h = [][]string{{"Content-Type", "application/json"}, {"username", "username2"}, {"password", "password2"}}
    code, bytes = request(login, "", h)
    require.Equal(t, 201, code)
    token2 := string(bytes)

4.request signing from the PKH allowed for only username1 not username2. use username2's token, but, put "username1" in the username http header:

    h = [][]string{{"Content-Type", "application/json"}, {"username", "username1"}, {"Authorization", "Bearer " + token2}}
    code, bytes = request(url1, message, h)
    assert.Equal(t, 403, code)
    assert.Contains(t, string(bytes), "user `username2' is not authorized to access "+pkh1) 

expected: http error 403, username2 is not authorized to access pkh1.

actual: successful sign request with username1's key

failing integration test name: TestPerPkh