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

Akka.Serialization: add type include / exclude for polymorphic serializers #5026

Open
2 of 3 tasks
Aaronontheweb opened this issue May 20, 2021 · 5 comments
Open
2 of 3 tasks

Comments

@Aaronontheweb
Copy link
Member

Aaronontheweb commented May 20, 2021

One of the issues with polymorphic serialization is that since it relies on reflection to directly instantiate CLR types, bad actors can submit malicious input that gets instantiated inside an ActorSystem and runs what would otherwise by unauthorized code. This is a classic problem with the BinaryFormatter serializer that's existed in .NET Framework for years, but it's generally a type of hazard for really any reflection-based serializer.

Akka.NET isn't particularly susceptible to this issue as Akka.Remote and Akka.Persistence are almost always used inside closed environments that aren't exposed to public networks. Our documentation, for years, has given guidance that Akka.Remote generally shouldn't be exposed to public networks and in the event that it is, you should be using certificate based authentication on both sides of the connection via TLS.

That being said, it's a good idea for us to mitigate this issue the same way both the original Scala Akka implementation does for their default "Jackson" JSON serializer and other popular .NET projects, such as MsgPack for C#, have done it - to filters to prevent or allow only a narrow band of types from being deserialized.

Here's what MsgPack's implementation looks like: https://github.com/neuecc/MessagePack-CSharp/blob/4142e346ead283997c46f7257f36a3037177bccf/src/MessagePack/Formatters/TypelessFormatter.cs#L97

And here's a range of types that should generally be filtered out from deserialization based on some research HP conducted on .NET reflection-based serialization https://stackoverflow.com/a/49041203/377476

Approach

The approach I think is best:

  1. Add a check inside the NewtonSoftJsonSerializer to see if an incoming message of a particular type is allowed or disallowed, depending on configuration;
  2. If it's disallowed, throw an SerializationException with a specific error message containing the type name / disallow reason - this should be logged by Akka.Remote or Akka.Persistence;
  3. Have NewtonSoftJsonSerializer ship with a default set of excluded types - i.e. from those lists above, automatically check for those upon deserialization;
  4. Allow the user to specify their own include / exclude rules via the NewtonSoftJsonSerializerSetup and the HyperionSerializerSetup classes at startup, since those are readily available and make it easy to configure these types of bindings programmatically.
  5. Optional: Allow users to totally disable type filtering via configuration in order to improve performance, since this feature does impose a per-message deserialization cost. IMHO this is kind of a silly option - if you care about performance, you should migrate to schema-based serialization using custom Google Protocol Buffer, MsgPack, etc types and avoid the overhead of reflection in the first place. But, if someone has a bunch of legacy data sitting inside Akka.Persistence and they're not worried about this issue affecting them it might be worthwhile to give users the ability to turn this off.

Any suggestions?

To Dos

  1. Add Hyperion Support
  2. Integrate Hyperion Support into Akka.Serialization.Hyperion + document it
  3. Integrate methodology into Newtonsoft.Json Serializer in Akka.Actor
@Aaronontheweb
Copy link
Member Author

For the Hyperion implementation of this, probably best to add the filtering inside Hyperion itself rather than inside the HyperionSerializer in Akka.NET - that way it becomes a feature of that library we merely configure from inside Akka.NET, rather than an Akka.NET-specific feature.

@Aaronontheweb
Copy link
Member Author

Also, our network security documentation needs a facelift - don't think we've touched that since Akka.NET v1.2.0.

@Danthar
Copy link
Member

Danthar commented May 20, 2021

For the Hyperion implementation of this, probably best to add the filtering inside Hyperion itself rather than inside the HyperionSerializer in Akka.NET - that way it becomes a feature of that library we merely configure from inside Akka.NET, rather than an Akka.NET-specific feature.

Yup. That would be the better way to implement this.

No suggestions otherwise. LGTM

@Aaronontheweb
Copy link
Member Author

First step for Hyperion is complete - actually implementing this feature inside the Serializer: akkadotnet/Hyperion#242

Still need to do a new Hyperion release, expose this through Akka.Serialization.Hyperion, and then document how to enable it.

Then we'll need to repeat this process for the Newtonsoft.Json serializer.

@Aaronontheweb
Copy link
Member Author

Stage 2 is underway: #5208 - this will be released in Akka.NET v1.4.24

@Aaronontheweb Aaronontheweb modified the milestones: 1.4.24, 1.4.25 Aug 18, 2021
@Aaronontheweb Aaronontheweb modified the milestones: 1.4.25, 1.4.26 Sep 8, 2021
@Aaronontheweb Aaronontheweb modified the milestones: 1.4.26, 1.4.27 Sep 28, 2021
@Aaronontheweb Aaronontheweb modified the milestones: 1.4.27, 1.4.28 Oct 11, 2021
@Aaronontheweb Aaronontheweb modified the milestones: 1.4.28, 1.4.29 Nov 10, 2021
@Aaronontheweb Aaronontheweb modified the milestones: 1.4.29, 1.4.30 Dec 13, 2021
@Aaronontheweb Aaronontheweb modified the milestones: 1.4.30, 1.4.31 Dec 20, 2021
@Aaronontheweb Aaronontheweb added this to the 1.4.36 milestone Mar 18, 2022
@Aaronontheweb Aaronontheweb modified the milestones: 1.4.36, 1.4.37, 1.4.38 Apr 14, 2022
@Aaronontheweb Aaronontheweb modified the milestones: 1.4.38, 1.4.39 May 25, 2022
@Aaronontheweb Aaronontheweb modified the milestones: 1.4.39, 1.4.40 Jun 1, 2022
@Aaronontheweb Aaronontheweb modified the milestones: 1.4.40, 1.4.41 Jul 27, 2022
@Aaronontheweb Aaronontheweb modified the milestones: 1.4.41, 1.4.42 Sep 7, 2022
@Aaronontheweb Aaronontheweb modified the milestones: 1.4.42, 1.4.43, 1.4.44 Sep 23, 2022
@Aaronontheweb Aaronontheweb modified the milestones: 1.4.44, 1.4.45, 1.4.46 Oct 17, 2022
@Aaronontheweb Aaronontheweb modified the milestones: 1.4.46, 1.4.47 Nov 15, 2022
@Aaronontheweb Aaronontheweb modified the milestones: 1.4.47, 1.4.48 Dec 9, 2022
@Aaronontheweb Aaronontheweb modified the milestones: 1.4.48, 1.4.49 Jan 5, 2023
@Aaronontheweb Aaronontheweb modified the milestones: 1.4.49, 1.4.50 Jan 26, 2023
@Aaronontheweb Aaronontheweb removed this from the 1.4.50 milestone Mar 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants