biscuit-rust
biscuit-rust copied to clipboard
Proposal: Use padding free Base64 encoding/decoding
Hey folks,
I think I've found an issue with how base64 encoding/decoding works with Biscuit tokens. Currently, the encode/decode config used for Base64 operations is invoked as follows:
-
base64::encode_config(slice, base64::URL_SAFE)
in biscuit-auth/src/token -
base64::decode_config(slice, base64::URL_SAFE)
in biscuit-auth/src/token
The problem here is that the default encode/decode configs use padding. The padding character for base64 is the =
character, which is not url-safe.
This means that any token that requires padding cannot be correctly used in contexts with URLs.
For example, take the token on the biscuitsec front page (== at the end):
En0KEwoEMTIzNBgDIgkKBwgKEgMYgAgSJAgAEiAs2CFWr5WyHHWEiMhTXxVNw4gP7PlADPaGfr_AQk9WohpA6LZTjFfFhcFQrMsp2O7bOI9BOzP-jIE5PGhha62HDfX4t5FLQivX5rUhH5iTv2c-rd0kDSazrww4cD1UCeytDSIiCiCfMgpVPOuqq371l1wHVhCXoIscKW-wrwiKN80vR_Rfzg==
When used with URL encoding, this token becomes:
En0KEwoEMTIzNBgDIgkKBwgKEgMYgAgSJAgAEiAs2CFWr5WyHHWEiMhTXxVNw4gP7PlADPaGfr_AQk9WohpA6LZTjFfFhcFQrMsp2O7bOI9BOzP-jIE5PGhha62HDfX4t5FLQivX5rUhH5iTv2c-rd0kDSazrww4cD1UCeytDSIiCiCfMgpVPOuqq371l1wHVhCXoIscKW-wrwiKN80vR_Rfzg%3D%3D
Now, this token can no longer be decoded using the biscuit-rust library. For example:
use biscuit_auth::Biscuit;
biscuit_auth::UnverifiedBiscuit::from_base64("En0KEwoEMTIzNBgDIgkKBwgKEgMYgAgSJAgAEiAs2CFWr5WyHHWEiMhTXxVNw4gP7PlADPaGfr_AQk9WohpA6LZTjFfFhcFQrMsp2O7bOI9BOzP-jIE5PGhha62HDfX4t5FLQivX5rUhH5iTv2c-rd0kDSazrww4cD1UCeytDSIiCiCfMgpVPOuqq371l1wHVhCXoIscKW-wrwiKN80vR_Rfzg%3D%3D").unwrap();
called `Result::unwrap()` on an `Err` value: Base64(InvalidByte(218, 37))
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
If we used the non-URL encoded version, the token is correctly parsed.
Any token that has been padded and is used with a URL (e.g. from a web-browser) cannot be parsed by the library.
To resolve this, we could:
- Change the existing base64 encoding function to produce un-padded output and the base64 decoding function to accept both padded and un-padded inputs. This can be accomplished by switching to
-
base64::encode_config(slice, base64::URL_SAFE_NO_PAD)
in biscuit-auth/src/token -
base64::decode_config(slice, base64::URL_SAFE_NO_PAD)
in biscuit-auth/src/token
- Create a new set of functions
Biscuit::to_base64_urlsafe()
andBiscuit::from_base64_urlsafe()
. - Add a flag to
Biscuit::to_base64
andBiscuit::from_base64
to control padding behavior.
Changing the default behavior might be risky, so 2 or 3 might be easier to implement.
Personally, I think that padding should not be used at all. See below from the creator of the rust-base64 crate:
The = pad bytes, on the other hand, are entirely a self-own by the Base64 standard. They do not affect decoding other than to provide an opportunity to say "that padding is incorrect". Exabytes of storage and transfer have no doubt been wasted on pointless = bytes https://github.com/marshallpierce/rust-base64
If we don't mind getting rid of the padding completely, option 1 would be the simplest solution. Otherwise, I have a PR for option 3. Option 2 is also viable if we don't want to change the interface of the existing functions.