Secure path sandboxing for untrusted environments
Project description
BoxedPath and SandboxPath: Secure File Path Handling
The Need
In modern applications, especially those handling untrusted code or user-uploaded files, secure access to the file system is critical. Unrestricted access can lead to vulnerabilities such as:
- Accessing sensitive files outside the intended directory.
- Exploiting path traversal to manipulate or steal data.
To mitigate these risks, applications need a mechanism to enforce strict constraints on file paths, ensuring they remain within a designated secure directory or "sandbox."
The Solution
The BoxedPath and Sandbox classes provide a robust solution for secure file path management:
-
BoxedPath:
- Ensures any file path manipulation stays within a predefined sandbox directory.
- Validates paths during initialization and every operation to prevent unauthorized access.
- Supports common file operations like opening files, checking existence, and retrieving metadata.
-
Sandbox:
- A specialized form of
BoxedPaththat represents the root of a sandbox. - Simplifies creating a constrained environment by setting the sandbox and path to the same directory.
- A specialized form of
Key Features
- Path Validation: Ensures the real path of any file operation remains within the sandbox.
- Path Composition: Allows safe concatenation of path segments while maintaining constraints.
- Common Operations: Supports file operations like opening, checking existence, and accessing metadata within the sandbox.
- Security Overrides: Provides explicit methods to access real paths when necessary but warns of security implications.
Sample Code
Here’s an example demonstrating the use of BoxedPath and Sandbox:
from boxedpath import BoxedPath, Sandbox
# Define a secure sandbox directory
sandbox = Sandbox('/secure/sandbox')
# Create a path within the sandbox
file_path = sandbox / 'example.txt'
# Check if the file exists
if file_path.exists():
print(f"File found: {file_path}")
# Open the file for reading
with file_path.open('r') as f:
content = f.read()
print("File Content:", content)
else:
print(f"File does not exist: {file_path}")
# Attempting to create a path outside the sandbox will raise a PermissionError
try:
invalid_path = sandbox / '../outside.txt'
except PermissionError as e:
print("Security Error:", e)
Benefits
- Enhanced Security: Restricts file operations to a designated sandbox, preventing unauthorized access.
- Ease of Use: Provides intuitive APIs for path manipulation and file operations.
- Flexibility: Handles complex path manipulations while maintaining security constraints.
These classes are essential tools for any application needing controlled access to the file system, ensuring security without compromising functionality.
Migration from Path to BoxedPath
Migrating from Python's built-in pathlib.Path to BoxedPath involves understanding and adapting to the security constraints that BoxedPath enforces. While pathlib.Path offers a versatile API for file system path manipulation, it does not inherently enforce security boundaries. BoxedPath, on the other hand, ensures all operations remain within a defined sandbox for enhanced security.
Steps for Migration
-
Initialization: Replace
pathlib.Pathinstances withBoxedPath. You must specify the sandbox directory as part of theBoxedPathinitialization.Before:
from pathlib import Path path = Path('/secure/sandbox/example.txt')
After:
from boxedpath import BoxedPath path = BoxedPath('/secure/sandbox/example.txt', '/secure/sandbox')
-
Path Joining: Use
/for joining paths, which is consistent withpathlib.Path. Ensure that all resulting paths stay within the sandbox.Before:
path = Path('/secure/sandbox') / 'example.txt'
After:
sandbox = Sandbox('/secure/sandbox') # shorthand for BoxedPath('/secure/sandbox', '/secure/sandbox') path = sandbox / 'example.txt'
-
Validation: Paths outside the sandbox are automatically blocked. This is a significant change from
pathlib.Path, which allows unrestricted path traversal.Before:
path = Path('/secure/sandbox') / '../outside.txt' # No validation print(path.resolve()) # This resolves to a path outside the sandbox
After:
try: path = sandbox / '../outside.txt' # Raises PermissionError except PermissionError as e: print(f"Security Error: {e}")
-
Common File Operations: Operations like opening a file, checking if it exists, or retrieving metadata work similarly but are constrained by the sandbox.
Before:
with path.open('r') as file: content = file.read() exists = path.exists() stats = path.stat()
After:
with path.open('r') as file: content = file.read() exists = path.exists() stats = path.stat()
-
Real Path Access: If your application requires access to the real (absolute) path, use
BoxedPath.insecure_unrestrained_realpath()cautiously. This bypasses sandbox constraints and should only be used in trusted scenarios.Before:
real_path = path.resolve()
After:
real_path = path.insecure_unrestrained_realpath()
Benefits of Migration
- Security First: Automatically prevents directory traversal and access to unintended parts of the file system.
- Minimal Changes: Retains the familiar API of
pathlib.Path, easing the transition. - Controlled Operations: Enforces path validation at every operation, reducing potential vulnerabilities.
Migration Example
Original Code Using pathlib.Path:
from pathlib import Path
base_path = Path('/secure/sandbox')
file_path = base_path / 'example.txt'
if file_path.exists():
with file_path.open('r') as f:
print(f.read())
Updated Code Using BoxedPath:
from boxedpath import BoxedPath
sandbox = BoxedPath('/secure/sandbox', '/secure/sandbox')
file_path = sandbox / 'example.txt'
if file_path.exists():
with file_path.open('r') as f:
print(f.read())
This structured migration ensures the application benefits from the enhanced security provided by BoxedPath without significant code rewrites.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file owasp_untrust_boxedpath-0.1.0.tar.gz.
File metadata
- Download URL: owasp_untrust_boxedpath-0.1.0.tar.gz
- Upload date:
- Size: 9.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e6b4d16db435dfa670119889c75a85ce0f19a0b5354ab667dc706a5dca8d0dff
|
|
| MD5 |
8a6ea3215337516e13573e559898dfa9
|
|
| BLAKE2b-256 |
c4e71a4eaad962e14ba431b8d95828d2f972cf3d3edfee0af64cbf6f6e8ab9ae
|
File details
Details for the file owasp_untrust_boxedpath-0.1.0-py3-none-any.whl.
File metadata
- Download URL: owasp_untrust_boxedpath-0.1.0-py3-none-any.whl
- Upload date:
- Size: 10.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8ebb46d89e9fa5ff1e4308ac4e81efad44aab442b4c30f0ca00b5017bcd59aae
|
|
| MD5 |
98b36cdc1882f252bb9abf73c11e4762
|
|
| BLAKE2b-256 |
f0c71e0350bb0276e20c4d3a9d7f8e7317decefcd159d87912c8351bc7c2ae0a
|