- Notifications
You must be signed in to change notification settings - Fork 382
Description
Following #9709 and the PR #9879 to mitigate this by disabling the feature, this issue is to track efforts to make this feature safe to use again. There are several approaches that can be used to make this safe, and reasons that no one solution is a guaranteed fit for all applications, so I propose that we find a general extension point to add, and if populated by an application, permit the use of enhanced classes without warning or error.
Basic approaches:
- Sign serialized data with a trusted private key and serialize the signature+public key with the data. Then, when reading the data back, the server can confirm the public key is trusted and that the signature is correct. A single server might create an in-memory key on startup (no persistence/coordination required), but then server restarts mean that clients must re-fetch all entities. A persisted key resolves this issue, at the cost of some additional configuration. A cluster of servers performing any kind of load balancing or handoff that allows entities from one server to be passed to another further requires coordination of keeping separate private keys but sharing trusted public keys (or using a common CA/etc), or all servers sharing the same keypair.
- Authenticate first before deserializing. This assumes that no authenticated user could be malicious, not usually an acceptable assumption.
onBeforeRequestDeserializedcan be overridden today to read from the request or session to validate in this way. - Allow developer control/configuration of the
ObjectInputStreamand surrounding code. In some cases it could be sufficient to offer a limited set of allowed classes that ObjectInputStream.resolveClass could read, and to check each one as it is read that it matches the expected field to write. SeeServerSerializationStreamReader.checkResolvefor the current implementation here.
Option 1 seems to be the superior choice in terms of granting flexibility and not requiring trusting malicious clients, but it also likely requires the most flexible configuration. We could go so far as to delegate this as a simple interface such as
public interface SharedClassKeyValidation { /** * Given a plain payload, returns a signed payload that will be later accepted by verifyAndUnwrap. * It must always be true that verifyAndUnwrap(signAndAppend(payload)) returns the original payload. */ String signAndAppend(String payload); /** * Given a signed payload, confirms the signature is valid and the key accepted, and returns the * underlying payload. If the signature or key is invalid, returns empty. */ Optional<String> verifyAndUnwrap(String signedPayload); }and offer a simple (single server), in-memory only (won't survive restarts) implementation to start from, and configuration to provide a custom implementation.