← Sandbox SDK / sandbox / concepts
Модель безопасности
Sandbox SDK работает на основе Containers, которые запускают каждую песочницу в отдельной VM для надежной изоляции.
Изоляция контейнера
Каждый sandbox выполняется в отдельной VM, обеспечивая полную изоляцию:
- Изоляция файловой системы - Песочницы не имеют доступа к файлам других песочниц
- Изоляция процессов - Процессы в одной песочнице не видят другие и не влияют на них
- Сетевая изоляция - У песочниц отдельные сетевые стеки
- Ограничения ресурсов - Квоты CPU, памяти и диска применяются для каждой песочницы
Полное описание вопросов безопасности базовой платформы контейнеризации см. в Архитектура контейнеров.
Внутри sandbox
Весь код в рамках одного sandbox использует общие ресурсы:
- Файловая система - Все процессы видят одни и те же файлы
- Процессы - Все сессии видят все процессы
- Сеть - Процессы могут взаимодействовать через localhost
Для полной изоляции используйте отдельную песочницу для каждого пользователя:
// Good - Each user in separate sandbox
const userSandbox = getSandbox(env.Sandbox, `user-${userId}`);
// Bad - Users sharing one sandbox
const shared = getSandbox(env.Sandbox, 'shared');
// Users can read each other's files!Валидация ввода
Внедрение команд
Всегда проверяйте пользовательский ввод, прежде чем использовать его в командах:
// Dangerous - user input directly in command
const filename = userInput;
await sandbox.exec(`cat ${filename}`);
// User could input: "file.txt; rm -rf /"
// Safe - validate input
const filename = userInput.replace(/[^a-zA-Z0-9._-]/g, '');
await sandbox.exec(`cat ${filename}`);
// Better - use file API
await sandbox.writeFile('/tmp/input', userInput);
await sandbox.exec('cat /tmp/input');Аутентификация
Доступ к песочнице
ID песочниц обеспечивают базовый контроль доступа, но не являются криптографически надёжными. Добавьте аутентификацию на уровне приложения:
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const userId = await authenticate(request);
if (!userId) {
return new Response('Unauthorized', { status: 401 });
}
// User can only access their sandbox
const sandbox = getSandbox(env.Sandbox, userId);
return Response.json({ authorized: true });
}
};Preview URLs
Preview URL содержат случайно сгенерированные токены. Любой, у кого есть этот URL, может получить доступ к сервису.
Чтобы отозвать доступ, закройте доступ к порту:
await sandbox.unexposePort(8080);URL быстрых туннелей
Быстрые туннели (sandbox.tunnels.get(port)) возвращают *.trycloudflare.com URL со случайным именем хоста, которое присваивает Cloudflare: отдельного токена доступа не существует. Само имя хоста и служит контролем доступа, поскольку сервис доступен любому, кто знает URL. Чтобы отозвать доступ, удалите туннель:
await sandbox.tunnels.destroy(8080);URL-адреса не сохраняются при перезапуске контейнера, поэтому перезапуск фактически меняет имя хоста. Как и в случае с preview URL-адресами, добавляйте аутентификацию на уровне приложения для любого чувствительного сервиса. См. Tunnels API для получения подробностей.
from flask import Flask, request, abort
import os
app = Flask(__name__)
def check_auth():
token = request.headers.get('Authorization')
if token != f"Bearer {os.environ['AUTH_TOKEN']}":
abort(401)
@app.route('/api/data')
def get_data():
check_auth()
return {'data': 'protected'}Управление секретами
Используйте переменные окружения, а не жёстко заданные секреты, для значений, которые процесс песочницы должен получать напрямую:
// Bad - hardcoded in file
await sandbox.writeFile('/workspace/config.js', `
const API_KEY = 'sk_live_abc123';
`);
// Good - use environment variables for values the sandbox process needs
await sandbox.startProcess('node app.js', {
env: {
API_KEY: env.API_KEY, // From Worker environment binding
}
});Учётные данные внешнего API, которые песочнице не нужно читать напрямую, храните в Worker и передавайте через обработчик исходящих запросов.
Очистка временных конфиденциальных данных:
try {
await sandbox.writeFile('/tmp/sensitive.txt', secretData);
await sandbox.exec('python process.py /tmp/sensitive.txt');
} finally {
await sandbox.deleteFile('/tmp/sensitive.txt');
}Обработка исходящего трафика
Если передавать внешние учётные данные API в песочницу напрямую, например через переменные окружения или файлы, процесс песочницы получает действующий доступ к учётным данным, который может прочитать любой код, выполняющийся внутри неё. Исходящие обработчики устраняют этот риск: они хранят учётные данные в Worker и добавляют их в исходящие запросы уже там.
Процесс выглядит следующим образом:
Sandbox request → Outbound handler (injects real credentials) → External APIПесочница никогда не видит реальные учётные данные. Обновите секрет в окружении вашего Worker, и каждый запрос будет использовать новое значение.
Такой подход полезен при обращении к GitHub для операций с приватными репозиториями, к сервисам ИИ или к объектному хранилищу, если вы не хотите, чтобы учётные данные попадали в контейнер. Подробности реализации см. в Обработка исходящего трафика.
От чего защищает SDK
- Доступ между песочницами (изоляция VM)
- Исчерпание ресурсов (принудительные квоты)
- Побег из контейнера (изоляция на основе виртуальных машин)
Что нужно реализовать
- Аутентификация и авторизация
- Валидация и санитизация ввода
- Ограничение скорости запросов
- Безопасность на уровне приложения (SQL-инъекции, XSS и другое)
Рекомендации
Используйте отдельные песочницы для изоляции:
const sandbox = getSandbox(env.Sandbox, `user-${userId}`);Проверяйте все входные данные:
const safe = input.replace(/[^a-zA-Z0-9._-]/g, '');
await sandbox.exec(`command ${safe}`);Используйте переменные окружения для секретов:
await sandbox.startProcess('node app.js', {
env: { API_KEY: env.API_KEY }
});Очистка временных ресурсов:
try {
const sandbox = getSandbox(env.Sandbox, sessionId);
await sandbox.exec('npm test');
} finally {
await sandbox.destroy();
}Дополнительные материалы
- Архитектура контейнеров - Безопасность базовой платформы
- Жизненный цикл песочницы - Управление ресурсами