title: Security Best Practices sidebar_position: 9 id: security license: | 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
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?
subprocess.Popen)__reduce__ callables before invocation__setstate__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.
strict=True in productionDeserializationPolicy when strict=False is necessarymax_depth to prevent stack overflow