This is an automated email from the ASF dual-hosted git repository. chaokunyang pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/fory-site.git
commit 1b7cf0f94202124e9e545f02ef81fa8b37d8b8c1 Author: chaokunyang <[email protected]> AuthorDate: Sat Jun 20 16:33:10 2026 +0000 🔄 synced local 'docs/guide/' with remote 'docs/guide/' --- docs/guide/cpp/configuration.md | 70 ++++++++++++++++++++++++++++++---- docs/guide/csharp/configuration.md | 60 ++++++++++++++++++++++++++--- docs/guide/dart/configuration.md | 41 +++++++++++++++++--- docs/guide/go/configuration.md | 56 ++++++++++++++++++++++++--- docs/guide/java/configuration.md | 9 +++++ docs/guide/javascript/configuration.md | 29 ++++++++++---- docs/guide/kotlin/configuration.md | 5 +++ docs/guide/python/configuration.md | 44 +++++++++++++++------ docs/guide/rust/configuration.md | 38 +++++++++++++++--- docs/guide/scala/configuration.md | 5 +++ docs/guide/swift/configuration.md | 25 +++++++++++- docs/guide/xlang/serialization.md | 35 +++++++++++++++++ 12 files changed, 367 insertions(+), 50 deletions(-) diff --git a/docs/guide/cpp/configuration.md b/docs/guide/cpp/configuration.md index 478e82f8fd..d617450041 100644 --- a/docs/guide/cpp/configuration.md +++ b/docs/guide/cpp/configuration.md @@ -115,6 +115,56 @@ This limits the maximum depth for nested polymorphic object serialization (e.g., - **Increase**: For legitimate deeply nested data structures - **Decrease**: For stricter security requirements or shallow data structures +### max_schema_versions_per_type(uint32_t) + +Set the maximum accepted remote metadata versions for one logical type. + +```cpp +auto fory = Fory::builder() + .max_schema_versions_per_type(10) + .build(); +``` + +**Default:** `10` + +### max_type_fields(uint32_t) + +Set the maximum fields accepted in one received remote struct metadata body. + +```cpp +auto fory = Fory::builder() + .max_type_fields(512) + .build(); +``` + +**Default:** `512` + +### max_type_meta_bytes(uint32_t) + +Set the maximum encoded body bytes accepted for one received TypeDef body, +excluding the 8-byte header and any extended-size varint. + +```cpp +auto fory = Fory::builder() + .max_type_meta_bytes(4096) + .build(); +``` + +**Default:** `4096` + +### max_average_schema_versions_per_type(uint32_t) + +Set the average accepted remote metadata versions across accepted remote types. +The effective global floor is `8192` schemas. + +```cpp +auto fory = Fory::builder() + .max_average_schema_versions_per_type(3) + .build(); +``` + +**Default:** `3` + ### check_struct_version(bool) Enable/disable struct version checking. @@ -150,13 +200,17 @@ auto fory = Fory::builder().build_thread_safe(); // Returns ThreadSafeFory ## Configuration Summary -| Option | Description | Default | -| ---------------------------- | --------------------------------------- | ------- | -| `xlang(bool)` | Use xlang mode | `true` | -| `compatible(bool)` | Enable schema evolution | `true` | -| `track_ref(bool)` | Enable reference tracking | `true` | -| `max_dyn_depth(uint32_t)` | Maximum nesting depth for dynamic types | `5` | -| `check_struct_version(bool)` | Enable struct version checking | `false` | +| Option | Description | Default | +| ------------------------------------------------ | ------------------------------------------------- | ------- | +| `xlang(bool)` | Use xlang mode | `true` | +| `compatible(bool)` | Enable schema evolution | `true` | +| `track_ref(bool)` | Enable reference tracking | `true` | +| `max_dyn_depth(uint32_t)` | Maximum nesting depth for dynamic types | `5` | +| `max_type_fields(uint32_t)` | Max fields in one received struct metadata body | `512` | +| `max_type_meta_bytes(uint32_t)` | Max encoded bytes in one received metadata body | `4096` | +| `max_schema_versions_per_type(uint32_t)` | Max remote metadata versions for one logical type | `10` | +| `max_average_schema_versions_per_type(uint32_t)` | Average remote metadata versions across types | `3` | +| `check_struct_version(bool)` | Enable struct version checking | `false` | ## Security @@ -166,6 +220,8 @@ Security-related configuration: - Use `check_struct_version(true)` with `compatible(false)` for intentional same-schema payloads. - Keep `max_dyn_depth(...)` as low as your model permits to reject unexpectedly deep polymorphic graphs. +- Keep the remote schema metadata limits at their defaults unless the data is not malicious and a + trusted peer sends larger metadata or many schema versions. - Prefer concrete fields over broad polymorphic fields for untrusted input. ## Related Topics diff --git a/docs/guide/csharp/configuration.md b/docs/guide/csharp/configuration.md index a158a6d5e3..e7c0c24d42 100644 --- a/docs/guide/csharp/configuration.md +++ b/docs/guide/csharp/configuration.md @@ -35,12 +35,16 @@ ThreadSafeFory threadSafe = Fory.Builder().BuildThreadSafe(); `Fory.Builder().Build()` uses: -| Option | Default | Description | -| -------------------- | ------- | -------------------------------------------- | -| `TrackRef` | `false` | Reference tracking disabled | -| `Compatible` | `true` | Compatible schema-evolution metadata enabled | -| `CheckStructVersion` | `false` | Struct schema hash checks disabled | -| `MaxDepth` | `20` | Max dynamic nesting depth | +| Option | Default | Description | +| --------------------------------- | ------- | ------------------------------------------------- | +| `TrackRef` | `false` | Reference tracking disabled | +| `Compatible` | `true` | Compatible schema-evolution metadata enabled | +| `CheckStructVersion` | `false` | Struct schema hash checks disabled | +| `MaxDepth` | `20` | Max dynamic nesting depth | +| `MaxTypeFields` | `512` | Max fields in one received struct metadata body | +| `MaxTypeMetaBytes` | `4096` | Max encoded bytes in one received metadata body | +| `MaxSchemaVersionsPerType` | `10` | Max remote metadata versions for one logical type | +| `MaxAverageSchemaVersionsPerType` | `3` | Average remote metadata versions across types | ## Builder Options @@ -92,6 +96,48 @@ Fory fory = Fory.Builder() `value` must be greater than `0`. +### `MaxTypeFields(int value)` + +Sets the maximum fields accepted in one received remote struct metadata body. + +```csharp +Fory fory = Fory.Builder() + .MaxTypeFields(512) + .Build(); +``` + +### `MaxTypeMetaBytes(int value)` + +Sets the maximum encoded body bytes accepted for one received TypeMeta body, +excluding the 8-byte header and any extended-size varint. + +```csharp +Fory fory = Fory.Builder() + .MaxTypeMetaBytes(4096) + .Build(); +``` + +### `MaxSchemaVersionsPerType(int value)` + +Sets the maximum accepted remote metadata versions for one logical type. + +```csharp +Fory fory = Fory.Builder() + .MaxSchemaVersionsPerType(10) + .Build(); +``` + +### `MaxAverageSchemaVersionsPerType(int value)` + +Sets the average accepted remote metadata versions across accepted remote types. +The effective global floor is `8192` schemas. + +```csharp +Fory fory = Fory.Builder() + .MaxAverageSchemaVersionsPerType(3) + .Build(); +``` + ## Common Configurations ### Compatible service @@ -127,6 +173,8 @@ Security-related configuration: - Register only the expected types before deserializing untrusted payloads. - Use `CheckStructVersion(true)` with `Compatible(false)` for intentional same-schema payloads. - Set `MaxDepth(...)` to reject unexpectedly deep dynamic object graphs. +- Keep the remote schema metadata limits at their defaults unless the data is not malicious and a + trusted peer sends larger metadata or many schema versions. - Prefer generated or registered concrete models over broad dynamic fields for untrusted input. ## Related Topics diff --git a/docs/guide/dart/configuration.md b/docs/guide/dart/configuration.md index f84ff49c2a..6a4c640f6a 100644 --- a/docs/guide/dart/configuration.md +++ b/docs/guide/dart/configuration.md @@ -34,6 +34,10 @@ final fory = Fory(); // customize limits while keeping default compatible mode final fory = Fory( maxDepth: 512, + maxTypeFields: 512, + maxTypeMetaBytes: 4096, + maxSchemaVersionsPerType: 10, + maxAverageSchemaVersionsPerType: 3, ); ``` @@ -82,13 +86,38 @@ Limits how deeply nested an object graph can be. Increase this if you have legit final fory = Fory(maxDepth: 128); ``` +### Remote schema metadata limits + +Compatible mode can receive remote metadata for schema evolution. These limits +bound metadata size and accepted schema versions: + +```dart +final fory = Fory( + maxTypeFields: 512, + maxTypeMetaBytes: 4096, + maxSchemaVersionsPerType: 10, + maxAverageSchemaVersionsPerType: 3, +); +``` + +- `maxTypeFields` limits fields in one received struct metadata body. +- `maxTypeMetaBytes` limits encoded body bytes in one received TypeMeta body, excluding the 8-byte + header and any extended-size varint. +- `maxSchemaVersionsPerType` limits accepted remote metadata versions for one logical type. +- `maxAverageSchemaVersionsPerType` limits the average across accepted remote types. The + effective global floor is `8192` schemas. + ## Defaults -| Option | Default | -| -------------------- | ------- | -| `compatible` | `true` | -| `checkStructVersion` | `false` | -| `maxDepth` | 256 | +| Option | Default | +| --------------------------------- | ------- | +| `compatible` | `true` | +| `checkStructVersion` | `false` | +| `maxDepth` | 256 | +| `maxTypeFields` | 512 | +| `maxTypeMetaBytes` | 4096 | +| `maxSchemaVersionsPerType` | 10 | +| `maxAverageSchemaVersionsPerType` | 3 | ## Xlang Notes @@ -105,6 +134,8 @@ Security-related configuration: - Register only the expected generated models before deserializing untrusted payloads. - Use `checkStructVersion: true` with `compatible: false` for intentional same-schema payloads. - Set `maxDepth` to reject unexpectedly deep payload shapes. +- Keep the remote schema metadata limits at their defaults unless the data is not malicious and a + trusted peer sends larger metadata or many schema versions. - Prefer generated schemas and explicit field metadata over broad dynamic fields for untrusted input. ## Related Topics diff --git a/docs/guide/go/configuration.md b/docs/guide/go/configuration.md index eb1aae5846..20d9012aee 100644 --- a/docs/guide/go/configuration.md +++ b/docs/guide/go/configuration.md @@ -33,12 +33,16 @@ f := fory.New(fory.WithXlang(true)) Default settings: -| Option | Default | Description | -| ---------- | ------- | -------------------------------------------- | -| TrackRef | false | Reference tracking disabled | -| MaxDepth | 20 | Maximum nesting depth | -| IsXlang | true | Xlang mode enabled | -| Compatible | true | Compatible schema-evolution metadata enabled | +| Option | Default | Description | +| ------------------------------- | ------- | ------------------------------------------------- | +| TrackRef | false | Reference tracking disabled | +| MaxDepth | 20 | Maximum nesting depth | +| IsXlang | true | Xlang mode enabled | +| Compatible | true | Compatible schema-evolution metadata enabled | +| MaxTypeFields | 512 | Max fields in one received struct metadata body | +| MaxTypeMetaBytes | 4096 | Max encoded bytes in one received metadata body | +| MaxSchemaVersionsPerType | 10 | Max remote metadata versions for one logical type | +| MaxAverageSchemaVersionsPerType | 3 | Average remote metadata versions across types | ### With Options @@ -47,6 +51,10 @@ f := fory.New( fory.WithXlang(true), fory.WithTrackRef(true), fory.WithMaxDepth(10), + fory.WithMaxTypeFields(512), + fory.WithMaxTypeMetaBytes(4096), + fory.WithMaxSchemaVersionsPerType(10), + fory.WithMaxAverageSchemaVersionsPerType(3), ) ``` @@ -119,6 +127,40 @@ f := fory.New(fory.WithMaxDepth(30)) - Protects against deeply nested, recursive structures or malicious data - Serialization fails with error when exceeded +### WithMaxTypeFields + +Set the maximum fields accepted in one received remote struct metadata body: + +```go +f := fory.New(fory.WithMaxTypeFields(512)) +``` + +### WithMaxTypeMetaBytes + +Set the maximum encoded body bytes accepted for one received TypeDef body, +excluding the 8-byte header and any extended-size varint: + +```go +f := fory.New(fory.WithMaxTypeMetaBytes(4096)) +``` + +### WithMaxSchemaVersionsPerType + +Set the maximum accepted remote metadata versions for one logical type: + +```go +f := fory.New(fory.WithMaxSchemaVersionsPerType(10)) +``` + +### WithMaxAverageSchemaVersionsPerType + +Set the average accepted remote metadata versions across accepted remote types. +The effective global floor is `8192` schemas: + +```go +f := fory.New(fory.WithMaxAverageSchemaVersionsPerType(3)) +``` + ### WithXlang Select the wire mode: @@ -346,6 +388,8 @@ Security-related configuration: - Register only the expected structs before deserializing untrusted data. - Use `WithMaxDepth(...)` to reject unexpectedly deep payloads. +- Keep the remote schema metadata limits at their defaults unless the data is not malicious and a + trusted peer sends larger metadata or many schema versions. - Prefer concrete struct fields over broad `any` or interface-typed fields for untrusted input. ## Related Topics diff --git a/docs/guide/java/configuration.md b/docs/guide/java/configuration.md index a42da9f949..7b3ce60bf6 100644 --- a/docs/guide/java/configuration.md +++ b/docs/guide/java/configuration.md @@ -38,6 +38,10 @@ This page documents all configuration options available through `ForyBuilder`. | `registerGuavaTypes` | Whether to pre-register Guava types such as `RegularImmutableMap`/`RegularImmutableList`. These types are not public API, but seem pretty stable. [...] | `requireClassRegistration` | Disabling may allow unknown classes to be deserialized, potentially causing security risks. [...] | `maxDepth` | Set max depth for deserialization, when depth exceeds, an exception will be thrown. This can be used to refuse deserialization DDOS attack. [...] +| `maxTypeFields` | Maximum fields accepted in one received remote struct metadata body. [...] +| `maxTypeMetaBytes` | Maximum encoded body bytes accepted for one received TypeDef or TypeMeta body, excluding the 8-byte header and any extended-size varint. [...] +| `maxSchemaVersionsPerType` | Maximum accepted remote metadata versions for one logical type. [...] +| `maxAverageSchemaVersionsPerType` | Average accepted remote metadata versions across all accepted remote types. The effective global floor is `8192` metadata entries. [...] | `suppressClassRegistrationWarnings` | Whether to suppress class registration warnings. The warnings can be used for security audit, but may be annoying, this suppression will be enabled by default. [...] | `metaShareEnabled` | Enables or disables meta share mode. [...] | `scopedMetaShareEnabled` | Scoped meta share focuses on a single serialization process. Metadata created or identified during this process is exclusive to it and is not shared with by other serializations. [...] @@ -93,6 +97,11 @@ Security-related options: - `requireClassRegistration(true)` restricts deserialization to registered classes. - `withMaxDepth(...)` rejects unexpectedly deep object graphs. +- `withMaxTypeFields(...)` and `withMaxTypeMetaBytes(...)` bound the field count + and encoded body size of one received remote metadata body. +- `withMaxSchemaVersionsPerType(...)` and + `withMaxAverageSchemaVersionsPerType(...)` bound accepted remote metadata versions without + changing registration, dynamic loading, or schema-evolution semantics. - `withDeserializeUnknownClass(false)` avoids materializing unknown classes from metadata. - `checkJdkClassSerializable(true)` keeps the JDK serializability check for `java.*` classes. - Class registration warnings can be useful during security audits; use diff --git a/docs/guide/javascript/configuration.md b/docs/guide/javascript/configuration.md index e4a0fb3bd9..058bccf4b3 100644 --- a/docs/guide/javascript/configuration.md +++ b/docs/guide/javascript/configuration.md @@ -43,18 +43,26 @@ const fory = new Fory({ ref: true, compatible: true, maxDepth: 100, + maxTypeFields: 512, + maxTypeMetaBytes: 4096, + maxSchemaVersionsPerType: 10, + maxAverageSchemaVersionsPerType: 3, hps, }); ``` -| Option | Default | Description | -| -------------------------- | ------- | ------------------------------------------------------------------------------------- | -| `ref` | `false` | Enable reference tracking for shared or circular object graphs | -| `compatible` | `true` | Allow field additions/removals without breaking existing messages | -| `maxDepth` | `50` | Maximum nesting depth. Must be `>= 2`. Increase for deeply nested structures | -| `useSliceString` | `false` | Optional string-reading optimization for Node.js. Leave at default unless benchmarked | -| `hps` | unset | Optional fast string helper from `@apache-fory/hps` (Node.js 20+) | -| `hooks.afterCodeGenerated` | unset | Callback to inspect the generated serializer code, useful for debugging | +| Option | Default | Description | +| --------------------------------- | ------- | ------------------------------------------------------------------------------------- | +| `ref` | `false` | Enable reference tracking for shared or circular object graphs | +| `compatible` | `true` | Allow field additions/removals without breaking existing messages | +| `maxDepth` | `50` | Maximum nesting depth. Must be `>= 2`. Increase for deeply nested structures | +| `maxTypeFields` | `512` | Maximum fields accepted in one received remote struct metadata body | +| `maxTypeMetaBytes` | `4096` | Maximum encoded body bytes accepted for one received TypeMeta body | +| `maxSchemaVersionsPerType` | `10` | Maximum accepted remote metadata versions for one logical type | +| `maxAverageSchemaVersionsPerType` | `3` | Average accepted remote metadata versions across accepted remote types | +| `useSliceString` | `false` | Optional string-reading optimization for Node.js. Leave at default unless benchmarked | +| `hps` | unset | Optional fast string helper from `@apache-fory/hps` (Node.js 20+) | +| `hooks.afterCodeGenerated` | unset | Callback to inspect the generated serializer code, useful for debugging | ## Reference Tracking @@ -102,6 +110,11 @@ Security-related configuration: - Register only the expected schemas before deserializing untrusted payloads. - Set `maxDepth` for the maximum nesting depth your service accepts. +- Keep `maxTypeFields` and `maxTypeMetaBytes` at their defaults unless the data + is not malicious and a trusted peer sends larger remote metadata. +- Keep `maxSchemaVersionsPerType` and + `maxAverageSchemaVersionsPerType` at their defaults unless the data is not + malicious and a trusted peer sends many remote schema versions. - Prefer explicit `Type.struct(...)` schemas over `Type.any()` for untrusted input. - Pass `hps` only from the official package version you deploy with Fory. diff --git a/docs/guide/kotlin/configuration.md b/docs/guide/kotlin/configuration.md index 8c40d6ea6e..061f14a7f8 100644 --- a/docs/guide/kotlin/configuration.md +++ b/docs/guide/kotlin/configuration.md @@ -135,6 +135,8 @@ and any untrusted payload source: val fory = ForyKotlin.builder() .requireClassRegistration(true) .withMaxDepth(50) + .withMaxTypeFields(512) + .withMaxTypeMetaBytes(4096) .build() ``` @@ -142,5 +144,8 @@ Security-related configuration: - Keep `requireClassRegistration(true)` and register application classes or generated modules. - Use `withMaxDepth(...)` to reject unexpectedly deep object graphs. +- Keep `withMaxTypeFields(...)`, `withMaxTypeMetaBytes(...)`, and the remote schema-version limits + at their defaults unless the data is not malicious and a trusted peer sends larger metadata or + many schema versions. - Follow [Java Configuration](../java/configuration.md#security) for allow-listing and unknown-class controls. diff --git a/docs/guide/python/configuration.md b/docs/guide/python/configuration.md index 02c61eb113..fdd6459fea 100644 --- a/docs/guide/python/configuration.md +++ b/docs/guide/python/configuration.md @@ -36,6 +36,10 @@ class Fory: strict: bool = True, compatible: Optional[bool] = None, max_depth: int = 50, + max_type_fields: int = 512, + max_type_meta_bytes: int = 4096, + max_schema_versions_per_type: int = 10, + max_average_schema_versions_per_type: int = 3, policy: DeserializationPolicy = None, field_nullable: bool = False, meta_compressor=None, @@ -55,17 +59,21 @@ class ThreadSafeFory: ## Parameters -| Parameter | Type | Default | Description | -| ----------------- | ------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `xlang` | `bool` | `True` | Use xlang mode. Set `False` for Python native mode. | -| `ref` | `bool` | `False` | Enable reference tracking for shared/circular references. Disable for better performance if your data has no shared references. | -| `strict` | `bool` | `True` | Require type registration for security. Keep this enabled for production unless a policy owns trust decisions. | -| `compatible` | `bool \| None` | `None` | Schema evolution mode. `None` enables compatible mode in both xlang and native mode. Set `False` only when every reader and writer uses the same schema. | -| `max_depth` | `int` | `50` | Maximum deserialization depth for security, preventing stack overflow attacks. | -| `policy` | `DeserializationPolicy \| None` | `None` | Deserialization policy used for security checks. Strongly recommended when `strict=False`. | -| `field_nullable` | `bool` | `False` | Treat dataclass fields as nullable by default. | -| `meta_compressor` | `Any` | `None` | Optional metadata compressor used for compatible-mode metadata encoding. | -| `fory_factory` | `Callable \| None` | `None` | `ThreadSafeFory` factory hook. When set, `ThreadSafeFory` creates instances via this callback; otherwise it forwards `**kwargs` to `Fory` construction. | +| Parameter | Type | Default | Description | +| -------------------------------------- | ------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `xlang` | `bool` | `True` | Use xlang mode. Set `False` for Python native mode. | +| `ref` | `bool` | `False` | Enable reference tracking for shared/circular references. Disable for better performance if your data has no shared references. | +| `strict` | `bool` | `True` | Require type registration for security. Keep this enabled for production unless a policy owns trust decisions. | +| `compatible` | `bool \| None` | `None` | Schema evolution mode. `None` enables compatible mode in both xlang and native mode. Set `False` only when every reader and writer uses the same schema. | +| `max_depth` | `int` | `50` | Maximum deserialization depth for security, preventing stack overflow attacks. | +| `max_type_fields` | `int` | `512` | Maximum fields accepted in one received remote struct metadata body. | +| `max_type_meta_bytes` | `int` | `4096` | Maximum encoded body bytes accepted for one received TypeDef body, excluding the 8-byte header and any extended-size varint. | +| `max_schema_versions_per_type` | `int` | `10` | Maximum accepted remote metadata versions for one logical type. | +| `max_average_schema_versions_per_type` | `int` | `3` | Average accepted remote metadata versions across accepted remote types. The effective global floor is `8192` schemas. | +| `policy` | `DeserializationPolicy \| None` | `None` | Deserialization policy used for security checks. Strongly recommended when `strict=False`. | +| `field_nullable` | `bool` | `False` | Treat dataclass fields as nullable by default. | +| `meta_compressor` | `Any` | `None` | Optional metadata compressor used for compatible-mode metadata encoding. | +| `fory_factory` | `Callable \| None` | `None` | `ThreadSafeFory` factory hook. When set, `ThreadSafeFory` creates instances via this callback; otherwise it forwards `**kwargs` to `Fory` construction. | ## Key Methods @@ -185,6 +193,10 @@ fory = pyfory.Fory( ref=False, strict=True, max_depth=50, + max_type_fields=512, + max_type_meta_bytes=4096, + max_schema_versions_per_type=10, + max_average_schema_versions_per_type=3, ) fory.register(UserModel, name="example.User") @@ -204,6 +216,16 @@ fory = pyfory.Fory( ) ``` +Received remote metadata is also limited: + +- `max_type_fields` limits the number of fields accepted in one received struct metadata body. +- `max_type_meta_bytes` limits the encoded body bytes accepted for one received TypeDef body. +- `max_schema_versions_per_type` limits accepted remote metadata versions for one logical type. +- `max_average_schema_versions_per_type` limits the average across accepted remote types. + +These limits do not change `strict`, `policy`, dynamic loading, unknown-class handling, or +schema-evolution semantics. + ### DeserializationPolicy When `strict=False` is necessary, use `DeserializationPolicy` to restrict the dynamic types and diff --git a/docs/guide/rust/configuration.md b/docs/guide/rust/configuration.md index 4d93c53056..58bd070567 100644 --- a/docs/guide/rust/configuration.md +++ b/docs/guide/rust/configuration.md @@ -88,6 +88,28 @@ let fory = Fory::builder().max_dyn_depth(10).build(); // Allow up to 10 levels Note: Static data types (non-dynamic types) are secure by nature and not subject to depth limits, as their structure is known at compile time. +### Remote Schema Metadata Limits + +Compatible mode can receive remote metadata for schema evolution. These limits +bound metadata size and accepted schema versions: + +```rust +let fory = Fory::builder() + .max_type_fields(512) + .max_type_meta_bytes(4096) + .max_schema_versions_per_type(10) + .max_average_schema_versions_per_type(3) + .build(); +``` + +- `max_type_fields` defaults to `512` and limits fields in one received struct metadata body. +- `max_type_meta_bytes` defaults to `4096` and limits encoded body bytes in one received TypeDef or + TypeMeta body, excluding the 8-byte header and any extended-size varint. +- `max_schema_versions_per_type` defaults to `10` and limits accepted remote metadata versions for + one logical type. +- `max_average_schema_versions_per_type` defaults to `3` and limits the average across accepted + remote types. The effective global floor is `8192` schemas. + ### Explicit Xlang Examples Set `.xlang(true)` explicitly for xlang serialization examples: @@ -122,11 +144,15 @@ let fory = Fory::builder() ## Configuration Summary -| Option | Description | Default | -| -------------------- | --------------------------------------- | ------- | -| `compatible(bool)` | Enable schema evolution | `true` | -| `xlang(bool)` | Use xlang mode | `true` | -| `max_dyn_depth(u32)` | Maximum nesting depth for dynamic types | `5` | +| Option | Description | Default | +| --------------------------------------------- | ------------------------------------------------- | ------- | +| `compatible(bool)` | Enable schema evolution | `true` | +| `xlang(bool)` | Use xlang mode | `true` | +| `max_dyn_depth(u32)` | Maximum nesting depth for dynamic types | `5` | +| `max_type_fields(usize)` | Max fields in one received struct metadata body | `512` | +| `max_type_meta_bytes(usize)` | Max encoded bytes in one received metadata body | `4096` | +| `max_schema_versions_per_type(usize)` | Max remote metadata versions for one logical type | `10` | +| `max_average_schema_versions_per_type(usize)` | Average remote metadata versions across types | `3` | ## Compatible Mode @@ -143,6 +169,8 @@ Security-related configuration: - Register application structs and trait-object implementations before deserializing untrusted payloads. - Use `max_dyn_depth(...)` to reject unexpectedly deep dynamic object graphs. +- Keep the remote schema metadata limits at their defaults unless the data is not malicious and a + trusted peer sends larger metadata or many schema versions. - Prefer concrete typed fields over `dyn Any` or broad trait-object fields for untrusted input. ## Related Topics diff --git a/docs/guide/scala/configuration.md b/docs/guide/scala/configuration.md index d78e648d28..397657d873 100644 --- a/docs/guide/scala/configuration.md +++ b/docs/guide/scala/configuration.md @@ -179,6 +179,8 @@ and any untrusted payload source: val fory = ForyScala.builder() .requireClassRegistration(true) .withMaxDepth(50) + .withMaxTypeFields(512) + .withMaxTypeMetaBytes(4096) .build() ``` @@ -186,5 +188,8 @@ Security-related configuration: - Keep `requireClassRegistration(true)` and register application classes or generated modules. - Use `withMaxDepth(...)` to reject unexpectedly deep object graphs. +- Keep `withMaxTypeFields(...)`, `withMaxTypeMetaBytes(...)`, and the remote schema-version limits + at their defaults unless the data is not malicious and a trusted peer sends larger metadata or + many schema versions. - Follow [Java Configuration](../java/configuration.md#security) for allow-listing and unknown-class controls. diff --git a/docs/guide/swift/configuration.md b/docs/guide/swift/configuration.md index 85c1e33257..e3a0478817 100644 --- a/docs/guide/swift/configuration.md +++ b/docs/guide/swift/configuration.md @@ -31,6 +31,10 @@ public struct Config { public let compatible: Bool public let checkClassVersion: Bool public let maxDepth: Int + public let maxTypeFields: Int + public let maxTypeMetaBytes: Int + public let maxSchemaVersionsPerType: Int + public let maxAverageSchemaVersionsPerType: Int } ``` @@ -86,10 +90,25 @@ let fory = Fory(compatible: false, checkClassVersion: true) ### Size and Depth Limits -`maxDepth` bounds decoded payload nesting depth. +`maxDepth` bounds decoded payload nesting depth. Compatible-mode remote metadata +is also limited: + +- `maxTypeFields` defaults to `512` and limits fields in one received struct metadata body. +- `maxTypeMetaBytes` defaults to `4096` and limits encoded body bytes in one received TypeMeta body, + excluding the 8-byte header and any extended-size varint. +- `maxSchemaVersionsPerType` defaults to `10` and limits accepted remote metadata versions for one + logical type. +- `maxAverageSchemaVersionsPerType` defaults to `3` and limits the average across accepted remote + types. The effective global floor is `8192` schemas. ```swift -let fory = Fory(maxDepth: 5) +let fory = Fory( + maxDepth: 5, + maxTypeFields: 512, + maxTypeMetaBytes: 4096, + maxSchemaVersionsPerType: 10, + maxAverageSchemaVersionsPerType: 3 +) ``` ## Recommended Presets @@ -121,3 +140,5 @@ Security-related configuration: - Register only the expected generated models before deserializing untrusted payloads. - Use `checkClassVersion` with `compatible: false` for intentional same-schema payloads. - Set `maxDepth` for the largest nesting depth your service accepts. +- Keep the remote schema metadata limits at their defaults unless the data is not malicious and a + trusted peer sends larger metadata or many schema versions. diff --git a/docs/guide/xlang/serialization.md b/docs/guide/xlang/serialization.md index 338f58fcb6..cdf136a353 100644 --- a/docs/guide/xlang/serialization.md +++ b/docs/guide/xlang/serialization.md @@ -23,6 +23,41 @@ This page demonstrates common cross-language serialization patterns. Data serial supported language can be deserialized in any other supported language when peers use matching type identity, field schema, and compatibility settings. +## Remote Schema Metadata Limits + +Compatible mode may receive remote metadata (`TypeDef` or `TypeMeta`) for types that are not already +known by the reader. Fory limits how many distinct remote metadata versions can be accepted, and +also limits the size of each received metadata body: + +- `maxSchemaVersionsPerType`: maximum accepted remote metadata versions for one logical type. The + default is `10`. +- `maxAverageSchemaVersionsPerType`: average accepted remote metadata versions across all accepted + remote types. The default is `3`; the effective global floor is `8192` metadata entries. +- `maxTypeFields`: maximum fields declared by one received struct metadata body. The default is + `512`. +- `maxTypeMetaBytes`: maximum encoded metadata body bytes for one received TypeDef or TypeMeta body, + excluding the 8-byte header and any extended-size varint. The default is `4096`. + +These limits are resource protections. They do not change wire format, registration requirements, +dynamic type loading, unknown-type handling, or schema-evolution compatibility. + +Raise these values only when the data is not malicious and a trusted peer sends larger metadata or +many schema versions. + +| Language | Field-count option | Metadata-bytes option | Per-type option | Average option | +| --------------------- | ------------------- | ---------------------- | ------------------------------ | -------------------------------------- | +| Java | `withMaxTypeFields` | `withMaxTypeMetaBytes` | `withMaxSchemaVersionsPerType` | `withMaxAverageSchemaVersionsPerType` | +| Scala | `withMaxTypeFields` | `withMaxTypeMetaBytes` | `withMaxSchemaVersionsPerType` | `withMaxAverageSchemaVersionsPerType` | +| Kotlin | `withMaxTypeFields` | `withMaxTypeMetaBytes` | `withMaxSchemaVersionsPerType` | `withMaxAverageSchemaVersionsPerType` | +| Python | `max_type_fields` | `max_type_meta_bytes` | `max_schema_versions_per_type` | `max_average_schema_versions_per_type` | +| JavaScript/TypeScript | `maxTypeFields` | `maxTypeMetaBytes` | `maxSchemaVersionsPerType` | `maxAverageSchemaVersionsPerType` | +| C++ | `max_type_fields` | `max_type_meta_bytes` | `max_schema_versions_per_type` | `max_average_schema_versions_per_type` | +| Go | `WithMaxTypeFields` | `WithMaxTypeMetaBytes` | `WithMaxSchemaVersionsPerType` | `WithMaxAverageSchemaVersionsPerType` | +| Rust | `max_type_fields` | `max_type_meta_bytes` | `max_schema_versions_per_type` | `max_average_schema_versions_per_type` | +| C# | `MaxTypeFields` | `MaxTypeMetaBytes` | `MaxSchemaVersionsPerType` | `MaxAverageSchemaVersionsPerType` | +| Swift | `maxTypeFields` | `maxTypeMetaBytes` | `maxSchemaVersionsPerType` | `maxAverageSchemaVersionsPerType` | +| Dart | `maxTypeFields` | `maxTypeMetaBytes` | `maxSchemaVersionsPerType` | `maxAverageSchemaVersionsPerType` | + ## Serialize Built-in Types Common types can be serialized automatically without registration: primitive numeric types, string, binary, array, list, map, and more. --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
