| title | sidebar_position | id | license |
|---|---|---|---|
Security Best Practices |
9 |
security |
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
|
This page covers security best practices and DeserializationPolicy.
Never disable strict=True in production unless your environment is completely trusted:
import pyfory
# Recommended production settings
f = pyfory.Fory(
xlang=False, # or True for cross-language
ref=True, # Handle circular references
strict=True, # IMPORTANT: Prevent malicious data
max_depth=100 # Prevent deep recursion attacks
)
# Explicitly register allowed types
f.register(UserModel, type_id=100)
f.register(OrderModel, type_id=101)
# Never set strict=False in production with untrusted data!Use environment variables to switch between configurations:
import pyfory
import os
# Development configuration
if os.getenv('ENV') == 'development':
fory = pyfory.Fory(
xlang=False,
ref=True,
strict=False, # Allow any type for development
max_depth=1000 # Higher limit for development
)
else:
# Production configuration (security hardened)
fory = pyfory.Fory(
xlang=False,
ref=True,
strict=True, # CRITICAL: Require registration
max_depth=100 # Reasonable limit
)
# Register only known safe types
for idx, model_class in enumerate([UserModel, ProductModel, OrderModel]):
fory.register(model_class, type_id=100 + idx)When strict=False is necessary (e.g., deserializing functions/lambdas), use DeserializationPolicy to implement fine-grained security controls during deserialization.
Why use DeserializationPolicy?
- Block dangerous classes/modules (e.g.,
subprocess.Popen) - Intercept and validate
__reduce__callables before invocation - Sanitize sensitive data during
__setstate__ - Replace or reject deserialized objects based on custom rules
import pyfory
from pyfory import DeserializationPolicy
dangerous_modules = {'subprocess', 'os', '__builtin__'}
class SafeDeserializationPolicy(DeserializationPolicy):
"""Block potentially dangerous classes during deserialization."""
def validate_class(self, cls, is_local, **kwargs):
# Block dangerous modules
if cls.__module__ in dangerous_modules:
raise ValueError(f"Blocked dangerous class: {cls.__module__}.{cls.__name__}")
return None
def intercept_reduce_call(self, callable_obj, args, **kwargs):
# Block specific callable invocations during __reduce__
if getattr(callable_obj, '__name__', "") == 'Popen':
raise ValueError("Blocked attempt to invoke subprocess.Popen")
return None
def intercept_setstate(self, obj, state, **kwargs):
# Sanitize sensitive data
if isinstance(state, dict) and 'password' in state:
state['password'] = '***REDACTED***'
return None
# Create Fory with custom security policy
policy = SafeDeserializationPolicy()
fory = pyfory.Fory(xlang=False, ref=True, strict=False, policy=policy)
# Now deserialization is protected by your custom policy
data = fory.serialize(my_object)
result = fory.deserialize(data) # Policy hooks will be invoked| Hook | Description |
|---|---|
validate_class(cls, is_local) |
Validate/block class types during deserialization |
validate_module(module, is_local) |
Validate/block module imports |
validate_function(func, is_local) |
Validate/block function references |
intercept_reduce_call(callable_obj, args) |
Intercept __reduce__ invocations |
inspect_reduced_object(obj) |
Inspect/replace objects created via __reduce__ |
intercept_setstate(obj, state) |
Sanitize state before __setstate__ |
authorize_instantiation(cls, args, kwargs) |
Control class instantiation |
See also: pyfory/policy.py contains detailed documentation and examples for each hook.
- Always use
strict=Truein production - Use
DeserializationPolicywhenstrict=Falseis necessary - Block dangerous modules (subprocess, os, etc.)
- Set appropriate
max_depthto prevent stack overflow - Validate data sources before deserialization
- Log security events for auditing
- Type Registration - Registration and strict mode
- Configuration - Fory parameters
- Python Native Mode - Functions and lambdas