-
Notifications
You must be signed in to change notification settings - Fork 112
Add info about security filters [DOC-768] #2264
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -57,6 +57,7 @@ To avoid deserialization of objects from untrusted sources, Hazelcast offers som | |
| xref:security:tls-ssl.adoc#mutual-authentication[mutual TLS authentication] and disabling xref:clusters:network-configuration.adoc#multicast-element[multicast join] configuration. | ||
| We recommend using Java serialization filter configuration for whitelisting the set of trusted classes or | ||
| packages which are allowed for deserialization. | ||
| * Hazelcast can fall back to zero-configuration Compact serialization for classes that have no explicit serializer. We recommend restricting the classes eligible for zero-config Compact serialization by defining an allowlist of only the classes your application needs, rather than relying on the default behavior. See xref:serialization:compact-serialization.adoc#zero-config-filter[Restricting Classes for Zero-Config Compact Serialization]. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would also add a recomendation to configure serialization restrictions (Java - previous point) and ZCCS (this point) not only on members but also on clients. And they do not have to be the same, although blocked classes will not be usable in client/member that has them blocked. |
||
| * Hazelcast uses Java reflection during SQL execution when the object format is set to `java`. We recommend using xref:sql:sql-reflection-configuration.adoc#configuring-reflection[Java reflection filter configuration] to whitelist the set of trusted classes or packages that are allowed to create through reflection. | ||
| * You can disable script executions on the Hazelcast members. Scripts executed from Management center have access | ||
| to system resources (files, etc.) with privileges of user running Hazelcast. | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -111,7 +111,7 @@ Client.newHazelcastClient( | |||||
| compact: { | ||||||
| serializers: [ | ||||||
| new FooSerializer() | ||||||
| ] | ||||||
| ] | ||||||
| ) | ||||||
| ---- | ||||||
| -- | ||||||
|
|
@@ -511,20 +511,20 @@ struct hz_serializer<employee> : public compact_serializer | |||||
| static employee read(compact_reader& reader) | ||||||
| { | ||||||
| employee e; | ||||||
|
|
||||||
| e.id = reader.read_int64("id"); | ||||||
| e.name = reader.read_string("name"); | ||||||
|
|
||||||
| return e; | ||||||
| } | ||||||
|
|
||||||
| static void write(const employee& e, compact_writer& writer) | ||||||
| { | ||||||
| writer.write_int64("id", e.id); | ||||||
| writer.write_string("name", e.name); | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| static std::string type_name() { return "employee"; } | ||||||
| static std::string type_name() { return "employee"; } | ||||||
| }; | ||||||
| ---- | ||||||
| -- | ||||||
|
|
@@ -1037,8 +1037,8 @@ When Hazelcast cannot associate a class with any other serialization mechanism, | |||||
| throwing an exception directly, it tries to use zero-configuration Compact serialization | ||||||
| as a last effort. | ||||||
|
|
||||||
| Hazelcast tries to extract a schema out of the class. If successful, it registers the | ||||||
| zero-config serializer associated with the extracted schema and uses it while serializing | ||||||
| Hazelcast tries to extract a schema out of the class. If successful, it registers the | ||||||
| zero-config serializer associated with the extracted schema and uses it while serializing | ||||||
| and deserializing instances of that class. If the automatic schema extraction fails, | ||||||
| Hazelcast throws an exception. | ||||||
|
|
||||||
|
|
@@ -1132,6 +1132,86 @@ module org.example.Foo { | |||||
| } | ||||||
| ---- | ||||||
|
|
||||||
| [[zero-config-filter]] | ||||||
| == Restricting Classes for Zero-Config Compact Serialization | ||||||
|
|
||||||
| Zero-config Compact serialization uses reflection to serialize any class that does not have another registered serializer. To control which classes are eligible for this, and to prevent classes from being serialized unintentionally, configure a filter that allows or blocks classes. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. these restrictions apply only to ZCCS. it is possible to register explicit serializers for classes that are not allowed for ZCCS. |
||||||
|
|
||||||
| The filter uses an allowlist and a blocklist. This is the same format as the xref:sql:sql-reflection-configuration.adoc[SQL Java reflection filter]. You can allow or block classes by fully qualified class name, package name, or class-name prefix. The filter can be set on both members and clients. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it is better to link to https://docs.hazelcast.com/hazelcast/5.7/serialization/serialization-configuration#untrusted-classes instead of SQL docs (SQL is a specific feature) |
||||||
|
|
||||||
| When a filter is configured: | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. describe also how to configure empty filter to effectively disable ZCCS |
||||||
|
|
||||||
| * If a class is on the blocklist, serializing an object of that class throws an exception. | ||||||
| * If a class is on the blocklist, deserializing its data returns a `GenericRecord` instead of an instance of the class, rather than throwing an exception. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is actually quite nice feature, possibly worth highlighting a bit more. some features like PredicateAPI/SQL query can process a compact-serialized class even if it is blocked from serialization, because extracting individual fields without object creation is safe. |
||||||
| * If the allowlist is non-empty, only classes on the allowlist (and not on the blocklist) are eligible for zero-config Compact serialization. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
both conditions need to be met. partentheses introduce a bit of assymetry in the text. Maybe:
Suggested change
? |
||||||
|
|
||||||
| Without a configured filter, Hazelcast applies a built-in blocklist of internal classes. This does not cover your own classes, so for the strongest protection, we suggest defining an allowlist containing only the classes your application needs. | ||||||
|
|
||||||
| [tabs] | ||||||
| ==== | ||||||
| XML:: | ||||||
| + | ||||||
| -- | ||||||
| [source,xml] | ||||||
| ---- | ||||||
| <hazelcast> | ||||||
| ... | ||||||
| <serialization> | ||||||
| <compact-serialization> | ||||||
| <zero-config-filter defaults-disabled="false"> | ||||||
| <whitelist> | ||||||
| <class>example.Foo</class> | ||||||
| <package>com.acme.app</package> | ||||||
| <prefix>com.acme.</prefix> | ||||||
| </whitelist> | ||||||
| <blacklist> | ||||||
| <class>com.acme.app.BeanComparator</class> | ||||||
| </blacklist> | ||||||
| </zero-config-filter> | ||||||
| </compact-serialization> | ||||||
| </serialization> | ||||||
| ... | ||||||
| </hazelcast> | ||||||
| ---- | ||||||
| -- | ||||||
| YAML:: | ||||||
| + | ||||||
| -- | ||||||
| [source,yaml] | ||||||
| ---- | ||||||
| hazelcast: | ||||||
| serialization: | ||||||
| compact-serialization: | ||||||
| zero-config-filter: | ||||||
| defaults-disabled: false | ||||||
| whitelist: | ||||||
| class: | ||||||
| - example.Foo | ||||||
| package: | ||||||
| - com.acme.app | ||||||
| prefix: | ||||||
| - com.acme. | ||||||
| blacklist: | ||||||
| class: | ||||||
| - com.acme.app.BeanComparator | ||||||
| ---- | ||||||
| -- | ||||||
| Java:: | ||||||
| + | ||||||
| -- | ||||||
| [source,java] | ||||||
| ---- | ||||||
| Config config = new Config(); | ||||||
| JavaSerializationFilterConfig filter = new JavaSerializationFilterConfig(); | ||||||
| filter.getWhitelist().addClasses("example.Foo"); | ||||||
| filter.getWhitelist().addPackages("com.acme.app"); | ||||||
| filter.getWhitelist().addPrefixes("com.acme."); | ||||||
| filter.getBlacklist().addClasses("com.acme.app.BeanComparator"); | ||||||
| config.getSerializationConfig().getCompactSerializationConfig().setZeroConfigFilter(filter); | ||||||
| ---- | ||||||
| -- | ||||||
| ==== | ||||||
|
|
||||||
| == Schema Evolution | ||||||
|
|
||||||
| This section provides an introduction to schema evolution, explaining how Compact serialization allows your object | ||||||
|
|
@@ -1255,7 +1335,7 @@ public class Employee { | |||||
| [source,cs] | ||||||
| ---- | ||||||
| public record Employee( | ||||||
| long Id, | ||||||
| long Id, | ||||||
| string Name, | ||||||
| int Age // newly-added field | ||||||
| ); | ||||||
|
|
@@ -1354,7 +1434,7 @@ public class EmployeeSerializer : ICompactSerializer<Employee> | |||||
| { | ||||||
| var id = reader.ReadInt64("id"); | ||||||
| var name = reader.ReadString("name"); | ||||||
| // the new 'age' field is there, but the old reader does not | ||||||
| // the new 'age' field is there, but the old reader does not | ||||||
| // know anything about it, and ignores the field. | ||||||
| return new Employee(id, name); | ||||||
| } | ||||||
|
|
@@ -1375,14 +1455,14 @@ struct hz_serializer<employee> : compact_serializer | |||||
| employee& read(compact_reader& reader) | ||||||
| { | ||||||
| employee e; | ||||||
|
|
||||||
| e.id = reader.read_int32("id"); | ||||||
| e.name = reader.read_string("name"); | ||||||
| // The new "age" field is there, but the old reader does not | ||||||
| // know anything about it. Hence, it will simply ignore that field. | ||||||
| return e; | ||||||
| } | ||||||
|
|
||||||
| // ... | ||||||
| }; | ||||||
| ---- | ||||||
|
|
@@ -1507,10 +1587,10 @@ struct hz_serializer<employee> : compact_serializer | |||||
| employee& read(compact_reader& reader) | ||||||
| { | ||||||
| employee e; | ||||||
|
|
||||||
| e.id = reader.read_int64("id"); | ||||||
| e.name = reader.read_string("name"); | ||||||
|
|
||||||
| // read the "age" field if it exists, else use the default value 0 | ||||||
| // reader.read_int32("age") would throw if the "age" field | ||||||
| // does not exist in data. | ||||||
|
|
@@ -1520,7 +1600,7 @@ struct hz_serializer<employee> : compact_serializer | |||||
| } else { | ||||||
| e.age = 0; | ||||||
| } | ||||||
|
|
||||||
| return e; | ||||||
| } | ||||||
| }; | ||||||
|
|
||||||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@th0masb could you verify this, in particular the requirement about disabling defaults to configure empty allowlist. We might have discussed this previously, but I realized (again?) that this is a bit unfortunate. If you start with empty allowlist and disabled defaults, but then want to add some unreasonable classes to allowlist (eg.
com.hazelcast) you lose the safety net of default blocklist.