blob: 5338d7c2defbc17259d8c926ca5d078cab641ab0 [file] [log] [blame] [view]
---
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
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.
## Production Configuration
Never disable `strict=True` in production unless your environment is completely trusted:
```python
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!
```
## Development vs Production
Use environment variables to switch between configurations:
```python
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)
```
## DeserializationPolicy
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
### Blocking Dangerous Classes
```python
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
```
## Available Policy Hooks
| 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.
## Best Practices
1. **Always use `strict=True` in production**
2. **Use `DeserializationPolicy`** when `strict=False` is necessary
3. **Block dangerous modules** (subprocess, os, etc.)
4. **Set appropriate `max_depth`** to prevent stack overflow
5. **Validate data sources** before deserialization
6. **Log security events** for auditing
## Related Topics
- [Type Registration](type-registration.md) - Registration and strict mode
- [Configuration](configuration.md) - Fory parameters
- [Python Native Mode](python-native.md) - Functions and lambdas