jwtk/jjwt

Stop including JWT payload in exception messages?

laurids opened this issue · 2 comments

Is your feature request related to a problem? Please describe.
If you try to parse a JWT with invalid JSON formatting in the payload, a MalformedJwtException is thrown, with the error message Malformed JWT JSON: <JWT payload>. With GDPR in mind, we don't want messages reaching the client or logs to include the JWT payload.

Describe the solution you'd like
Could there perhaps be a field on MalformedJwtException that contains the JWT payload, but not included in the error message itself? So the caller still has the option to inspect the JWT payload, but wouldn't unknowingly violate GDPR if the error message is propagated to logs or other components.

Describe alternatives you've considered
As a workaround, we are catching MalformedJwtException and throwing our own exception. However, in some cases we would like to include the original error message. For example, if the JWT header is missing the alg field, the message is nice and descriptive:
JWT string has a digest/signature, but the header does not reference a valid signature algorithm.

Additional context
N/A

Hi @laurids !

Thanks for creating the issue! I think creating a field on MalformedJwtException makes sense. 👍

Forgot to close this. This change was implemented in b687ca5 as:

// Don't disclose potentially-sensitive information per https://github.com/jwtk/jjwt/issues/824:
String value = "payload".equals(name) ? RedactedSupplier.REDACTED_VALUE : base64UrlEncoded.toString();
String msg = "Invalid Base64Url " + name + ": " + value;
throw new MalformedJwtException(msg, t);

Additionally, because of the streams-based I/O changes in that same commit, the payload is not guaranteed to be a String, so we don't print it out after successful Base64-decoding but failed JSON parsing, because the changes to the deserialize helper method can't assume it's a String:

protected Map<String, ?> deserialize(InputStream in, final String name) {
try {
Reader reader = Streams.reader(in);
JsonObjectDeserializer deserializer = new JsonObjectDeserializer(this.deserializer, name);
return deserializer.apply(reader);
} finally {
Objects.nullSafeClose(in);
}
}