
sandbox-runtime v0.0.74
أداة عزل (sandboxing) خفيفة الوزن لفرض قيود على نظام الملفات والشبكة على أي عملية على مستوى نظام التشغيل، دون الحاجة إلى حاوية (container).
بيئة تشغيل الحماية (srt)
أداة حماية خفيفة الوزن لفرض قيود على نظام الملفات والشبكة على العمليات التعسفية على مستوى نظام التشغيل، دون الحاجة إلى حاوية.
تستخدم srt بدائيات الحماية الأصلية لنظام التشغيل (sandbox-exec على macOS، bubblewrap على لينكس) وتصفية الشبكة القائمة على الوكيل. يمكن استخدامها لحماية سلوك الوكلاء، وخوادم MCP المحلية، وأوامر bash، والعمليات التعسفية.
معاينة بحثية تجريبية
بيئة تشغيل الحماية هي معاينة بحثية تم تطويرها لـ Claude Code لتمكين وكلاء ذكاء اصطناعي أكثر أمانًا. يتم توفيرها كمعاينة مفتوحة المصدر مبكرة لمساعدة النظام البيئي الأوسع في بناء أنظمة وكيلة أكثر أمانًا. نظرًا لأن هذه معاينة بحثية مبكرة، فقد تتطور واجهات برمجة التطبيقات وتنسيقات التكوين. نرحب بالملاحظات والمساهمات لجعل وكلاء الذكاء الاصطناعي أكثر أمانًا افتراضيًا!
التثبيت```bash
npm install -g @anthropic-ai/sandbox-runtime
## الاستخدام الأساسي```bash
# Network restrictions
$ srt "curl anthropic.com"
Running: curl anthropic.com
<html>...</html> # Request succeeds
$ srt "curl example.com"
Running: curl example.com
Connection blocked by network allowlist # Request blocked
# Filesystem restrictions
$ srt "cat README.md"
Running: cat README.md
# Anthropic Sandb... # Current directory access allowed
$ srt "cat ~/.ssh/id_rsa"
Running: cat ~/.ssh/id_rsa
cat: /Users/ollie/.ssh/id_rsa: Operation not permitted # Specific file blocked
نظرة عامة
توفر هذه الحزمة تنفيذًا مستقلاً لبيئة الحماية (sandbox) يمكن استخدامها كأداة سطر أوامر (CLI) وكأداة مكتبة في نفس الوقت. صُممت بفلسفة آمنة افتراضيًا مصممة خصيصًا لحالات الاستخدام الشائعة للمطورين: تبدأ العمليات بصلاحيات وصول ضئيلة، وتقوم أنت بفتح الثغرات التي تحتاجها فقط بشكل صريح.
القدرات الرئيسية:
- قيود الشبكة: التحكم في المضيفات/النطاقات التي يمكن الوصول إليها عبر HTTP/HTTPS والبروتوكولات الأخرى
- قيود نظام الملفات: التحكم في الملفات/المجلدات التي يمكن قراءتها/كتابتها
- قيود مآخذ Unix: التحكم في الوصول إلى مآخذ IPC المحلية
- مراقبة الانتهاكات: على macOS، يمكن الوصول إلى مخزن سجلات انتهاكات الحماية في النظام للحصول على تنبيهات في الوقت الفعلي
مثال على حالة الاستخدام: عزل خوادم MCP
حالة استخدام رئيسية هي عزل خوادم بروتوكول سياق النموذج (MCP) لتقييد قدراتها. على سبيل المثال، لعزل خادم MCP الخاص بنظام الملفات:
بدون عزل (.mcp.json):```json
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem"]
}
}
}
**مع العزل (sandboxing)** (`.mcp.json`):```json
{
"mcpServers": {
"filesystem": {
"command": "srt",
"args": ["npx", "-y", "@modelcontextprotocol/server-filesystem"]
}
}
}
ثم قم بتكوين القيود في ~/.srt-settings.json:```json
{
"filesystem": {
"denyRead": [],
"allowWrite": ["."],
"denyWrite": ["~/sensitive-folder"]
},
"network": {
"allowedDomains": [],
"deniedDomains": []
}
}
الآن سيتم حظر خادم MCP من الكتابة إلى المسار المرفوض:```
> Write a file to ~/sensitive-folder
✗ Error: EPERM: operation not permitted, open '/Users/ollie/sensitive-folder/test.txt'
كيف يعمل
يستخدم الصندوق الرملي (sandbox) بدائيات على مستوى نظام التشغيل لفرض قيود تنطبق على شجرة العمليات بأكملها:
- macOS: يستخدم
sandbox-execمع ملفات تعريف Seatbelt المولّدة ديناميكيًا - Linux: يستخدم bubblewrap للحاويات مع عزل مساحة اسم الشبكة
- Windows: يشغّل العملية المعزولة تحت حساب مستخدم محلي مخصص باسم
srt-sandbox، مع منصة تصفية Windows (WFP) لمنع حركة الخروج (egress) مرتبطة بـ SID الخاص بهذا الحساب، بالإضافة إلى قوائم تحكم وصول صريحة (ACEs) لكل جلسة على شجرة العمل
0d1c612947c798aef48e6ab4beb7e8544da9d41a-4096x2305
نموذج العزل المزدوج
يُعد كل من عزل نظام الملفات وعزل الشبكة ضروريين لتحقيق صندقة رمليّة فعّالة. بدون عزل الملفات، قد تقوم عملية مخترقة بتسريب مفاتيح SSH أو ملفات حساسة أخرى. بدون عزل الشبكة، قد تهرب العملية من الصندوق الرملي وتحصل على وصول غير مقيد إلى الشبكة.
عزل نظام الملفات يفرض قيود القراءة والكتابة:
- القراءة (نمط الرفض ثم السماح): افتراضيًا، يُسمح بالوصول للقراءة في كل مكان. يمكنك رفض مناطق واسعة (مثل
/Users) ثم إعادة السماح بمسارات محددة داخلها (مثل.).allowReadله الأولوية علىdenyRead— عكس الكتابة، حيث يكون لـdenyWriteالأولوية علىallowWrite. أي إدخالdenyReadأكثر تحديدًا من منطقةallowReadالتي يقع داخلها (مثلdenyRead: ["**/.env"]أو["./secrets"]معallowRead: ["."]) يظل مرفوضًا. - الكتابة (نمط السماح فقط): افتراضيًا، يُرفض الوصول للكتابة في كل مكان. يجب عليك السماح صراحةً بمسارات (مثل
.،/tmp). قائمة السماح الفارغة تعني عدم وجود وصول للكتابة.
عزل الشبكة (نمط السماح فقط): افتراضيًا، يُرفض جميع الوصول إلى الشبكة. يجب عليك السماح صراحةً بالنطاقات. قائمة allowedDomains الفارغة تعني عدم وجود وصول إلى الشبكة. يتم توجيه حركة مرور الشبكة عبر خوادم بروكسي تعمل على المضيف:
-
Linux: يتم توجيه الطلبات عبر نظام الملفات باستخدام مقبس نطاق Unix (Unix domain socket). تتم إزالة مساحة اسم الشبكة الخاصة بالعملية المعزولة بالكامل، لذا يجب أن تمر جميع حركة مرور الشبكة عبر البروكسيات التي تعمل على المضيف (التي تستمع على مقابس Unix مثبّتة بالربط داخل الصندوق الرملي)
-
macOS: يسمح ملف تعريف Seatbelt بالاتصال فقط بمنفذ محدد على localhost. تستمع البروكسيات على هذا المنفذ، مما ينشئ قناة محكومة لجميع الوصول إلى الشبكة
-
Windows: مجموعة مرشحات WFP على مستوى الجهاز تمنع جميع الاتصالات الصادرة الناشئة من حساب
srt-sandboxباستثناء الحلقة المحلية (loopback) إلى نطاق منافذ البروكسي. تستمع البروكسيات داخل هذا النطاق، مما ينشئ قناة محكومة لجميع الوصول إلى الشبكة
يتم التوسط في كل من حركة HTTP/HTTPS (عبر بروكسي HTTP) وحركة TCP الأخرى (عبر بروكسي SOCKS5) بواسطة هذه البروكسيات، التي تفرض قوائم السماح والرفض الخاصة بالنطاقات لديك.
لمزيد من التفاصيل حول الصندقة الرمليّة في Claude Code، انظر:
- توثيق الصندقة الرمليّة في Claude Code
- ما وراء مطالبات الأذونات: جعل Claude Code أكثر أمانًا واستقلالية
البنية المعمارية```
src/ ├── index.ts # Library exports ├── cli.ts # CLI entrypoint (srt command) ├── utils/ # Shared utilities │ ├── debug.ts # Debug logging │ ├── settings.ts # Settings reader (permissions + sandbox config) │ ├── platform.ts # Platform detection │ └── exec.ts # Command execution utilities └── sandbox/ # Sandbox implementation ├── sandbox-manager.ts # Main sandbox manager ├── sandbox-schemas.ts # Zod schemas for validation ├── sandbox-violation-store.ts # Violation tracking ├── sandbox-utils.ts # Shared sandbox utilities ├── http-proxy.ts # HTTP/HTTPS proxy for network filtering ├── socks-proxy.ts # SOCKS5 proxy for network filtering ├── linux-sandbox-utils.ts # Linux bubblewrap sandboxing ├── macos-sandbox-utils.ts # macOS sandbox-exec sandboxing └── windows-sandbox-utils.ts # Windows srt-win sandboxing
## الاستخدام
### كأداة سطر أوامر
أمر `srt` (بيئة تشغيل Anthropic Sandbox) يغلّف أي أمر بحدود أمنية:```bash
# Run a command in the sandbox
srt echo "hello world"
# With debug logging
srt --debug curl https://example.com
# Specify custom settings file
srt --settings /path/to/srt-settings.json npm install
كمكتبة```typescript
import { SandboxManager, type SandboxRuntimeConfig, } from '@anthropic-ai/sandbox-runtime' import { spawn } from 'child_process'
// Define your sandbox configuration const config: SandboxRuntimeConfig = { network: { allowedDomains: ['example.com', 'api.github.com'], deniedDomains: [], }, filesystem: { denyRead: ['~/.ssh'], allowWrite: ['.', '/tmp'], denyWrite: ['.env'], }, }
// Initialize the sandbox (starts proxy servers, etc.) await SandboxManager.initialize(config)
// Wrap a command with sandbox restrictions const sandboxedCommand = await SandboxManager.wrapWithSandbox( 'curl https://example.com', )
// Execute the sandboxed command const child = spawn(sandboxedCommand, { shell: true, stdio: 'inherit' })
// Handle exit and cleanup after child process completes
child.on('exit', async code => {
console.log(Command exited with code ${code})
// Cleanup when done (optional, happens automatically on process exit)
await SandboxManager.reset()
})
**إسناد الانتهاكات (`commandId` / `commandText`).** يتم تخزين الانتهاكات التي تُلاحظ أثناء تشغيل أمر مُغلّف (سجلات seatbelt، أحداث seccomp، رفض الوكيل) تحت مفتاح إسناد، وتقوم `annotateStderrWithSandboxFailures(key, stderr)` / `getViolationsForCommand(key)` بالبحث عنها باستخدام نفس المفتاح. افتراضيًا، يكون المفتاح هو السلسلة المُغلّفة نفسها. مرّر `commandId` معتمًا خاصًا بكل استدعاء (مثل معرف استخدام أداة) للربط بذلك بدلاً من ذلك — موصى به: تُقارن المفاتيح على أول 100 حرف منها، لذا فإن الأوامر الطويلة التي تشترك في بادئة قد تُسند بشكل متقاطع، وإعادة تشغيل نفس النص سترث أحداث التشغيل السابق. إذا كانت السلسلة التي *تنفّذها* ليست الأمر الذي *يمثّله* الاستدعاء (مثلًا، تُغلّف `source <snapshot> && eval '<cmd>'` مُجمّعًا)، مرّر أيضًا `commandText: '<cmd>'`: فهو ما تتطابق معه أنماط أوامر `ignoreViolations` وما يُبلغ عنه كل انتهاك كـ `command` خاص به.```typescript
const wrapped = await SandboxManager.wrapWithSandbox(
assembledCommand, // what actually runs
undefined,
undefined,
undefined,
{ commandId: invocationId, commandText: rawCommand },
)
// ... run it ...
const annotated = SandboxManager.annotateStderrWithSandboxFailures(invocationId, stderr)
الصادرات المتاحة```typescript
// Main sandbox manager export { SandboxManager } from '@anthropic-ai/sandbox-runtime'
// Violation tracking export { SandboxViolationStore } from '@anthropic-ai/sandbox-runtime'
// TypeScript types export type { SandboxRuntimeConfig, NetworkConfig, FilesystemConfig, IgnoreViolationsConfig, SandboxAskCallback, FsReadRestrictionConfig, FsWriteRestrictionConfig, NetworkRestrictionConfig, } from '@anthropic-ai/sandbox-runtime'
## الإعدادات
### موقع ملف الإعدادات
افتراضيًا، يبحث وقت تشغيل بيئة الاختبار المعزولة عن الإعدادات في `~/.srt-settings.json`. يمكنك تحديد مسار مخصص باستخدام علامة `--settings`:```bash
srt --settings /path/to/srt-settings.json <command>
مثال تكوين كامل```json
{ "network": { "allowedDomains": [ "github.com", ".github.com", "lfs.github.com", "api.github.com", "npmjs.org", ".npmjs.org" ], "deniedDomains": ["malicious.com"], "allowUnixSockets": ["/var/run/docker.sock"], "allowLocalBinding": false }, "filesystem": { "denyRead": ["~/.ssh"], "allowRead": [], "allowWrite": [".", "src/", "test/", "/tmp"], "denyWrite": [".env", "config/production.json"] }, "ignoreViolations": { "*": ["/usr/bin", "/System"], "git push": ["/usr/bin/nc"], "npm": ["/private/tmp"] }, "enableWeakerNestedSandbox": false, "enableWeakerNetworkIsolation": false, "allowAppleEvents": false }
### خيارات التهيئة
#### تهيئة الشبكة
يستخدم **نمط السماح فقط** - جميع الوصول إلى الشبكة مرفوض افتراضيًا.
- `network.allowedDomains` - مصفوفة من النطاقات المسموح بها (تدعم أحرف البدل مثل `*.example.com`). مصفوفة فارغة = لا وصول إلى الشبكة. لاحقة `:port` اختيارية (`api.example.com:443`, `*.example.com:8443`) تقيّد الإدخال بمنفذ الوجهة ذلك؛ الإدخالات بدون منفذ تطابق أي منفذ.
- يجب وضع عناوين IPv6 بين أقواس مربعة، بنمط RFC 3986: `[::1]`, `[2001:db8::1]:443`. يُرفض الإدخال متعدد النقطتين بدون أقواس باعتباره غامضًا (`2001:db8::1:443` هو بحد ذاته عنوان صالح).
- `network.deniedDomains` - مصفوفة من النطاقات المرفوضة (تُفحص أولاً، وتتجاوز allowedDomains). نفس لاحقة `:port`، ويُقبل `*` المجرد (أو `*:22`) للرفض الكامل.
- `network.deniedDomainReasons` - خريطة اختيارية من إدخال `deniedDomains` (مطابقًا بالسلسلة النصية الدقيقة) إلى سبب موجه للنموذج يظهر في سطر `<sandbox_violations>` عندما يرفض ذلك الإدخال اتصالًا — اذكر ما تم حظره والبديل المعتمد (مثل `{"github.com:22": "SSH pushes to GitHub are blocked; use an https:// remote"}`). الإدخالات بدون سبب تُبلغ عن سبب عام. لوجهات SSH (المنفذ 22)، يُسلَّم السبب أيضًا داخل النطاق: عميل SSH مُمرَّر عبر ProxyCommand SOCKS بدون مصادقة (مثل BSD `nc -X 5`) يستقبل قطع اتصال SSH قبل تبادل المفاتيح يكون وصفه هو السبب، والذي يطبعه OpenSSH حرفيًا — أبقِ هذه الأسباب تحت ~400 حرف ASCII، بصيغة الأمر أولاً، لأن OpenSSH يقتطع ويهرب غير ASCII.
- `network.allowLocalBinding` - السماح بالربط بالمنافذ المحلية (قيمة منطقية، الافتراضي: false)
**إنهاء TLS** (`network.tlsTerminate`, تجريبي): عند تعيينه، تُنهى اتصالات HTTPS CONNECT داخل العملية بحيث يمكن لـ SRT رؤية (وتصفية، عبر `network.filterRequest`) الطلبات المفكوكة التشفير. يُوجَّه العملية المعزولة إلى حزمة ثقة تحتوي على شهادة MITM CA (`caCertPath`/`caKeyPath`، أو CA مؤقت إذا حُذفت) بالإضافة إلى الجذور المعتادة للمضيف، بحيث تتحقق كل من الشهادات المصكوكة من الوكيل والشهادات الحقيقية من المنبع.
- `network.tlsTerminate.excludeDomains` - أنماط النطاقات (نفس صيغة `allowedDomains`) التي **لا** تُنهى. تُمرَّر اتصالات CONNECT المطابقة كنفق معتم بدلاً من ذلك: فهي لا تزال خاضعة لقائمة النطاقات المسموح بها، لكن العميل داخل الصندوق الرملي يُكمل مصافحة TLS الخاصة به مع المنبع الحقيقي، ولا تنطبق `filterRequest` / حقن بيانات الاعتماد على حركة HTTPS الخاصة بها. استخدم هذا للحالتين اللتين يكسر فيهما إنهاء TLS بشكل أساسي:
- **منابع mTLS** - فقط العميل داخل الصندوق الرملي يحمل شهادة العميل، لذا لا يمكن للوكيل إعادة إنشاء الاتصال نيابةً عنه.
- **عملاء تثبيت الشهادات** - العملاء الذين يتحققون من هوية المنبع بأنفسهم (شهادات CA مخصصة، تثبيت SAN) ويرفضون شهادة MITM.
- `network.tlsTerminate.extraCaCertPaths` - مسارات لملفات شهادات CA بصيغة PEM تُضاف إلى حزمة الثقة تلك، بعد MITM CA والجذور المعتادة للمضيف. تُتحقق المضيفات المستثناة (غير المُنهية) بواسطة العميل داخل الصندوق الرملي، ومتغيرات بيئة الثقة التي يضبطها SRT (`SSL_CERT_FILE`, `GIT_SSL_CAINFO`, ...) _تستبدل_ تهيئة الثقة الخاصة بكل أداة، لذا يجب أن يكون الجذر المحلي للموقع (مثل CA mTLS داخلي) في الحزمة أو لا يمكن التحقق من تلك المضيفات أبدًا. تُنسخ فقط كتل `CERTIFICATE` من كل ملف إلى الحزمة (أي شيء آخر، مثل مفتاح خاص في PEM مدمج، لا يُكشف أبدًا للصندوق الرملي)؛ الملفات المفقودة أو غير القابلة للقراءة أو التي لا تحتوي على كتلة PEM `CERTIFICATE` تُتخطى، لذا من الآمن سرد مسارات موجودة على بعض المضيفات فقط.```json
{
"network": {
"allowedDomains": ["*.example.com", "internal-mtls.example.net"],
"deniedDomains": [],
"tlsTerminate": {
"excludeDomains": ["internal-mtls.example.net"],
"extraCaCertPaths": ["/etc/internal-mtls-roots.pem"]
}
}
}
إعدادات مقابس Unix (سلوك خاص بالمنصة):
| الإعداد | macOS | Linux |
|---|---|---|
allowUnixSockets: string[] | قائمة السماح لمسارات المقابس | مُتجاهَل (لا يمكن لـ seccomp التصفية حسب المسار) |
allowAllUnixSockets: boolean | السماح بجميع المقابس | تعطيل حظر seccomp |
مقابس Unix محظورة افتراضيًا على كلتا المنصتين.
- macOS: استخدم
allowUnixSocketsللسماح بمسارات محددة (مثل["/var/run/docker.sock"])، أوallowAllUnixSockets: trueللسماح بجميع المقابس. - Linux: يعتمد الحظر على مرشحات seccomp (x64/arm64 فقط). إذا لم يكن seccomp متاحًا، تصبح المقابس غير مقيدة ويظهر تحذير. استخدم
allowAllUnixSockets: trueلتعطيل الحظر صراحةً.
إعداد نظام الملفات
يستخدم نمطين مختلفين:
قيود القراءة (نمط المنع ثم السماح) - جميع عمليات القراءة مسموحة افتراضيًا:
filesystem.denyRead- مصفوفة من المسارات لمنع الوصول للقراءة. مصفوفة فارغة = وصول كامل للقراءة.filesystem.allowRead- مصفوفة من المسارات لإعادة السماح بالوصول للقراءة داخل المناطق الممنوعة (تأخذ الأولوية على denyRead). ملاحظة: هذا عكس الكتابة، حيث يأخذdenyWriteالأولوية علىallowWrite.
قيود الكتابة (نمط السماح فقط) - جميع عمليات الكتابة ممنوعة افتراضيًا:
filesystem.allowWrite- مصفوفة من المسارات للسماح بالوصول للكتابة. مصفوفة فارغة = لا وصول للكتابة.filesystem.denyWrite- مصفوفة من المسارات لمنع الوصول للكتابة داخل المسارات المسموحة (تأخذ الأولوية على allowWrite)
صيغة المسار (macOS):
تدعم المسارات أنماط glob بأسلوب git على macOS، مشابهة لصيغة .gitignore:
*- يطابق أي أحرف باستثناء/(مثل*.tsيطابقfoo.tsلكن ليسfoo/bar.ts)**- يطابق أي أحرف بما في ذلك/(مثلsrc/**/*.tsيطابق جميع ملفات.tsفيsrc/)?- يطابق أي حرف واحد باستثناء/(مثلfile?.txtيطابقfile1.txt)[abc]- يطابق أي حرف في المجموعة (مثلfile[0-9].txtيطابقfile3.txt)
أمثلة:
"allowWrite": ["src/"]- السماح بالكتابة إلى دليلsrc/بالكامل"allowWrite": ["src/**/*.ts"]- السماح بالكتابة إلى جميع ملفات.tsفيsrc/والدلائل الفرعية"denyRead": ["~/.ssh"]- منع القراءة من دليل SSH"denyRead": ["/Users"], "allowRead": ["."]- منع القراءة من/Usersبالكامل، لكن إعادة السماح للدليل الحالي"denyWrite": [".env"]- منع الكتابة إلى ملف.env(حتى لو كان الدليل الحالي مسموحًا)
صيغة المسار (Linux):
لا يدعم Linux حاليًا مطابقة glob. استخدم المسارات الحرفية فقط:
"allowWrite": ["src/"]- السماح بالكتابة إلى دليلsrc/"denyRead": ["/home/user/.ssh"]- منع القراءة من دليل SSH"denyRead": ["/home"], "allowRead": ["."]- منع القراءة من/homeبالكامل، لكن إعادة السماح للدليل الحالي
جميع المنصات:
- يمكن أن تكون المسارات مطلقة (مثل
/home/user/.ssh) أو نسبية إلى دليل العمل الحالي (مثل./src) ~يتم توسيعه إلى الدليل الرئيسي للمستخدم
إعدادات أخرى
ignoreViolations- كائن يربط أنماط الأوامر بمصفوفات من المسارات حيث يجب تجاهل الانتهاكاتenableWeakerNestedSandbox- تفعيل وضع الصندوق الرملي الأضعف لبيئات Docker (قيمة منطقية، الافتراضي: false)enableWeakerNetworkIsolation- السماح بالوصول إلىcom.apple.trustd.agentفي صندوق الرمل الخاص بـ macOS (قيمة منطقية، الافتراضي: false). هذا مطلوب لبرامج Go (gh,gcloud,terraform,kubectl, إلخ) للتحقق من شهادات TLS عند استخدامhttpProxyPortمع وكيل MITM وشهادة CA مخصصة. تحذير أمني: تفعيل هذا يفتح ناقلًا محتملًا لتسريب البيانات عبر خدمة trustd.allowAppleEvents- السماح بإرسال Apple Events وطلبات فتح Launch Services من صندوق الرمل الخاص بـ macOS (قيمة منطقية، الافتراضي: false). بدون هذا، تفشل الأوامر مثلopenوosascriptوأي شيء يفتح عناوين URL أو نصوصًا لتطبيقات أخرى عبر AppleScript مع خطأ AppleScript-600("التطبيق لا يعمل") أو أخطاء LaunchServices (-10822,-54). تحذير أمني: تفعيل هذا يعني أن الصندوق الرملي لم يعد يوفر عزل تنفيذ الكود. يمكن لأمر داخل الصندوق الرملي تشغيل تطبيقات أخرى عبرopenدون مطالبة المستخدم، وأي شيء يتم تشغيله يعمل خارج قيود نظام الملفات والشبكة الخاصة بالصندوق الرملي؛ كما أن كتابة النصوص للتطبيقات قيد التشغيل عبر Apple Events تخضع إضافيًا لموافقة أتمتة TCC الخاصة بالمستخدم لكل تطبيق. يجب على المدمجين الحصول على هذا الخيار فقط من إعدادات موثوقة على مستوى المستخدم — وليس أبدًا من ملفات محلية للمشروع في مستودع مُسحوب، مما قد يسمح لمشروع كتبه مهاجم برفع صلاحيات صندوق الرمل الخاص به.
وصفات إعداد شائعة
السماح بالوصول إلى GitHub (جميع نقاط النهاية الضرورية):```json { "network": { "allowedDomains": [ "github.com", "*.github.com", "lfs.github.com", "api.github.com" ], "deniedDomains": [] }, "filesystem": { "denyRead": [], "allowWrite": ["."], "denyWrite": [] } }
**تقييد إلى مجلدات محددة:**```json
{
"network": {
"allowedDomains": [],
"deniedDomains": []
},
"filesystem": {
"denyRead": ["~/.ssh"],
"allowWrite": [".", "src/", "test/"],
"denyWrite": [".env", "secrets/"]
}
}
وصول إلى نظام الملفات مقتصر على مساحة العمل فقط (منع القراءة خارج مساحة العمل):```json { "network": { "allowedDomains": [], "deniedDomains": [] }, "filesystem": { "denyRead": ["/Users"], "allowRead": ["."], "allowWrite": ["."], "denyWrite": [] } }
يمنع هذا قراءة أي شيء تحت `/Users` (أو `/home` على لينكس)، ثم يعيد السماح بدليل العمل الحالي. تبقى مسارات النظام (`/usr`، `/lib`، إلخ) قابلة للقراءة.
### المشكلات الشائعة والنصائح
**تشغيل Jest:** استخدم علامة `--no-watchman` لتجنب انتهاكات وضع الحماية (sandbox):```bash
srt "jest --no-watchman"
يصل Watchman إلى ملفات خارج حدود الصندوق الرملي، مما سيؤدي إلى أخطاء في الأذونات. تعطيله يسمح لـ Jest بالعمل مع مراقب الملفات المدمج بدلاً من ذلك.
دعم المنصات
- macOS: يستخدم
sandbox-execمع ملفات تعريف مخصصة (بدون تبعيات إضافية) - Linux: يستخدم
bubblewrap(bwrap) للحاويات - Windows: ألفا — يستخدم ملف مساعد مدمج
srt-win.exe(بدون تبعيات إضافية). راجع Windows (ألفا) أدناه للإعداد ونموذج الأمان والقيود المعروفة
التبعيات الخاصة بالمنصات
يتطلب Linux:
bubblewrap- بيئة تشغيل الحاويات- Ubuntu/Debian:
apt-get install bubblewrap - Fedora:
dnf install bubblewrap - Arch:
pacman -S bubblewrap
- Ubuntu/Debian:
socat- مرحّل المقابس لربط الوكيل- Ubuntu/Debian:
apt-get install socat - Fedora:
dnf install socat - Arch:
pacman -S socat
- Ubuntu/Debian:
ripgrep- أداة بحث سريعة لاكتشاف المسارات المحظورة- Ubuntu/Debian:
apt-get install ripgrep - Fedora:
dnf install ripgrep - Arch:
pacman -S ripgrep
- Ubuntu/Debian:
ملاحظة Ubuntu 24.04+: تُمكّن هذه الإصدارات kernel.apparmor_restrict_unprivileged_userns افتراضيًا، مما يسمح بـ unshare(CLONE_NEWUSER) لكنه يجرّد الصلاحيات من مساحة الأسماء الناتجة. يحتاج كل من bubblewrap وطبقة عزل seccomp إلى مساحات أسماء مستخدمين تحمل صلاحيات. عطّل هذا التقييد باستخدام:```bash
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
أو أضف ملف تعريف AppArmor يمنح `userns` للملفات الثنائية ذات الصلة.
**التبعيات الاختيارية لنظام Linux (للتخفيض الاحتياطي لـ seccomp):**
تتضمن الحزمة مرشحات seccomp BPF مولّدة مسبقًا لمعماريتي x86-64 وarm. هذه التبعيات مطلوبة فقط إذا كنت على معمارية مختلفة حيث لا تتوفر المرشحات المولّدة مسبقًا:
- `gcc` أو `clang` - مترجم C
- `libseccomp-dev` - ملفات تطوير مكتبة Seccomp
- Ubuntu/Debian: `apt-get install gcc libseccomp-dev`
- Fedora: `dnf install gcc libseccomp-devel`
- Arch: `pacman -S gcc libseccomp`
**يتطلب macOS:**
- `ripgrep` - أداة بحث سريعة لاكتشاف مسارات الحظر
- التثبيت عبر Homebrew: `brew install ripgrep`
- أو التنزيل من: https://github.com/BurntSushi/ripgrep/releases
**يتطلب Windows:**
- لا توجد تبعيات إضافية. يتم تضمين الأداة المساعدة `srt-win.exe` (x64 وarm64) مع حزمة npm. يلزم تنفيذ خطوة `windows-install` بصلاحيات مرتفعة لمرة واحدة — انظر أدناه.
## Windows (ألفا)
دعم Windows هو **ألفا**. تعمل العملية المعزولة تحت حساب مستخدم محلي مخصص باسم `srt-sandbox`، معزولة عن المستخدم المُستدعي بواسطة بدائيات أمان Windows الأصلية — سياج خروج من Windows Filtering Platform (WFP) مرتبط بـ SID لحساب الصندوق الرملي، وACEs صريحة لكل جلسة تمنح أو تحرم ذلك SID من الوصول إلى مسارات نظام الملفات المكوّنة.
### الإعداد
نفّذ مرة واحدة لكل جهاز (يرفع الصلاحيات ذاتيًا؛ موجه UAC واحد):```powershell
npx @anthropic-ai/sandbox-runtime windows-install
This provisions the srt-sandbox local user account (with a random password stored DPAPI-encrypted in HKLM\SOFTWARE\sandbox-runtime — machine-wide, so fleet installs running as SYSTEM work and one user's rotation updates the copy the others read), the sandbox-runtime-users local group, and installs a machine-wide WFP filter set keyed on the srt-sandbox SID. It is idempotent — re-running it rotates the sandbox account's password and reconciles the filter set.
No logout is required. The WFP filters key on the dedicated sandbox account's SID, so your own network, services, and every other principal on the machine are unaffected.
After install, SandboxManager.initialize() and the srt CLI work as on other platforms. initialize() verifies the sandbox account and WFP fence are live, and fails with an actionable error if not.
Programmatic install/uninstall are exported as installWindowsSandbox() / uninstallWindowsSandbox().
Security model
The sandboxed command runs as the srt-sandbox account, not as the calling user. The bundled srt-win.exe helper does a two-hop launch: the broker calls CreateProcessWithLogonW to start a runner as srt-sandbox, and the runner spawns the target under a restricted token inside a job object. The child inherits the sandbox account's isolated profile (%USERPROFILE%, %TEMP%, HKCU) and a fresh environment overlaid with only the broker's PATH and the generated proxy variables.
Running under a distinct user SID structurally closes the surrogate-spawn class of escape (Task Scheduler, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS onto a broker-owned process, BITS, out-of-process COM with RunAs="Interactive User"): any process the child manages to spawn out-of-band still carries the srt-sandbox SID, so it remains subject to the WFP egress fence and has no rights on the calling user's files.
Network isolation is a two-filter WFP set at FWPM_LAYER_ALE_AUTH_CONNECT_V4/V6: a PERMIT for loopback destinations inside the configured proxy port range (default 60080–60089), and a BLOCK for any connect whose token carries the srt-sandbox SID. The sandboxed process reaches the internet only via the JS HTTP/SOCKS5 proxies listening in that range; a process that strips its proxy environment and connects directly is blocked at the kernel.
Filesystem isolation is enforced by NTFS discretionary ACLs. The srt-sandbox account has no inherent rights on the calling user's files, so at initialize() the sandbox writes additive, inheriting explicit ACEs for the srt-sandbox SID only — it never rewrites or replaces a path's existing security descriptor:
filesystem.allowWrite→ an inheritingMODIFYALLOW ACE (READ|WRITE|EXECUTE|DELETE, withFILE_DELETE_CHILDwithheld). The sandboxed process can create, modify, and delete files inside the working tree; withholdingFILE_DELETE_CHILDfrom the grant is defense-in-depth for the deny stamps below, not a guard on the tree root.filesystem.allowRead→ an inheritingREAD|EXECUTEALLOW ACEfilesystem.denyRead/filesystem.denyWrite→ an inheriting DENY ACE on the target, plus an inheritingFILE_DELETE_CHILDDENY on its parent — together with the withheldFILE_DELETE_CHILDon the working-tree grant, this stops the sandboxed process from renaming or deleting a denied path via its parent directory
reset() removes every ACE this session added (refcounted across this user's concurrent hosts via the per-user session DB; a crash-recovery pass on the next initialize() cleans up after an unclean exit). Directory targets are supported (the ACEs inherit to the whole subtree). Glob patterns are expanded to concrete paths at initialize() time — a matching path that appears later is not covered.
TLS termination on Windows
network.tlsTerminate requires the MITM CA to be present in the sandbox user's CurrentUser\Root certificate store (schannel — the TLS backend used by System32\curl.exe, PowerShell Invoke-WebRequest, .NET, and default-backend git — trusts only the OS store, not environment variables). This is an install-time step, separate from windows-install:```typescript
import { windowsTrustCa } from '@anthropic-ai/sandbox-runtime'
windowsTrustCa('/path/to/mitm-ca.crt') // or: srt-win user trust-ca
`initialize()` تقارن بصمة شهادة CA الخاصة بالجلسة مع تلك المثبتة وتفشل برسالة قابلة للتنفيذ عند عدم التطابق، بحيث لا يمكن لشهادة CA قديمة من وقت التثبيت أن تكسر TLS بصمت داخل بيئة الحماية.
العملاء المعتمدون على OpenSSL (مثل `curl` في msys2، و`git -c http.sslBackend=openssl`، وNode، وPython، وcargo) مشمولون بطبقة الثقة عبر متغيرات البيئة: يتم تمرير نفس حزمة الثقة المستخدمة على macOS/Linux إلى بيئة الحماية عبر `NODE_EXTRA_CA_CERTS`، و`SSL_CERT_FILE`، و`CURL_CA_BUNDLE`، و`GIT_SSL_CAINFO`، و`CARGO_HTTP_CAINFO`، وغيرها، ويُضاف مسار الحزمة إلى منح `allowRead` الخاص بالجلسة حتى يتمكن حساب بيئة الحماية من فتحها.
### إعداد خاص بنظام Windows
تنطبق كتل `filesystem` و`network` عبر المنصات كما هو موضح أعلاه. الإعدادات الخاصة بنظام Windows فقط تقع تحت `windows`:
- `windows.proxyPortRange` — نطاق المنافذ الشامل `[low, high]` الذي ترتبط به بروكسيات JS داخليًا. **يجب أن يطابق** النطاق المُمرر إلى `windows-install --proxy-port-range` (الافتراضي `[60080, 60089]`) — إذ أن تصريح WFP loopback PERMIT يغطي هذا النطاق فقط.
- `windows.sublayerGuid` — GUID للطبقة الفرعية WFP التي تم تثبيت عوامل التصفية تحتها. احذفه لاستخدام الافتراضي في وقت الترجمة؛ اضبطه فقط عندما تقوم أدوات المؤسسات بتثبيت عوامل التصفية تحت طبقة فرعية مخصصة.
- `windows.srtWin.path` — المسار إلى ثنائي `srt-win`. احذفه لاستخدام `vendor/srt-win/<arch>/srt-win.exe` المرفق. اضبطه عند تضمين واجهة سطر الأوامر الخاصة بـ `srt-win` في ثنائي متعدد الاستدعاءات؛ عندها تمرر عمليات الإطلاق `--srt-win` كـ `argv[1]` بحيث يمكن لموزع المُضمّن توجيهها إلى `srt_win::run_from_args`.
### القيود المعروفة
- **إبطال الشهادات تحت schannel.** يتم جلب CRL/OCSP الخاص بـ CryptoAPI عبر WinHTTP تحت رمز المستدعي، متجاهلاً بيئة البروكسي، لذا يتم حظره بواسطة سياج WFP للاتصالات الصادرة. الأدوات التي تستخدم schannel مع تفعيل فحص الإبطال افتراضيًا تفشل مع `CRYPT_E_REVOCATION_OFFLINE` (`0x80092013`) ما لم يتم تعطيل الإبطال لكل أداة: `curl --ssl-no-revoke`، و`git -c http.schannelCheckRevoke=false`، و`CARGO_HTTP_CHECK_REVOKE=false`. لا تفحص `Invoke-WebRequest` و`HttpClient` في .NET و`gh` الإبطال افتراضيًا وبالتالي لا تتأثر. من المخطط تقديم نقطة توزيع CRL تُخدم من البروكسي loopback لإزالة هذا الحل البديل.
- **تثبيتات الأدوات لكل مستخدم غير قابلة للوصول.** تعمل العملية المعزولة كـ `srt-sandbox` وليس كأنت، لذا فإن الأدوات المثبتة تحت ملفك الشخصي (Node المُدار عبر nvm/fnm، وحزم `winget`/Scoop لكل مستخدم، و`pip install --user`، و`%LOCALAPPDATA%\Programs\…`) تُحل على `PATH` الموروث لكن لا يمكن لحساب بيئة الحماية فتحها. يُفضل التثبيتات على مستوى الجهاز (`Program Files`، أو `choco`/`winget --scope machine`)، أو أضف مسارات الملف الشخصي المحددة إلى `filesystem.allowRead`.
- **تجاوزات `filesystem.allowRead` / `filesystem.allowWrite` لكل تنفيذ غير مدعومة.** تعمل `allowRead`/`allowWrite` على مستوى الجلسة (في الإعداد المُمرر إلى `initialize()`) كما هو موضح أعلاه؛ تمريرها لكل أمر في `customConfig` الخاص بـ `wrapWithSandbox` يرمي خطأً — تُطبق المنح على مستوى الجلسة عبر `srt-win acl grant` في `initialize()`، و`exec` الخاص بـ `srt-win` يعرض فقط حالات الرفض لكل تنفيذ.
- **`proxyAuthToken` مرئي في سطر أوامر المُشغّل.** تُمرر بيئة البروكسي (بما في ذلك `HTTP_PROXY=http://srt:<token>@127.0.0.1:…`) إلى المُشغّل ثنائي القفز كوسائط `--env` على argv الخاص بـ `srt-win exec`، لذا يمكن لأي كيان محلي يمكنه فتح عملية المُشغّل مع `PROCESS_QUERY_LIMITED_INFORMATION` قراءة الرمز. الرمز موجود ليتمكن العملية المعزولة من المصادقة على البروكسي loopback، لذا فهو ليس سرًا من بيئة الحماية نفسها؛ على جهاز تطوير أحادي المستخدم هذا مقبول عمومًا، لكن على مضيف مشترك تعامل مع قائمة السماح الخاصة بالبروكسي على أنها قابلة للوصول من كيانات أخرى في نفس الجلسة.
- **حل DNS عبر محلل النظام غير مُسيَّج.** يتم خدمة `getaddrinfo()` بواسطة خدمة `Dnscache` التي تعمل كـ `NETWORK SERVICE`، لذا ينجح تحليل الأسماء حتى لو تم حظر `connect()` اللاحق من العملية المعزولة. الأدوات التي تقوم بحل DNS الخاص بها عبر UDP/53 (`nslookup`، `dig`) مُسيَّجة. هذا يعكس سلوك macOS.
### إلغاء التثبيت```powershell
npx @anthropic-ai/sandbox-runtime windows-uninstall
يزيل مجموعة عوامل تصفية WFP، وحساب srt-sandbox وملفه الشخصي، ومجموعة sandbox-runtime-users، ويزيل مفتاح HKLM\SOFTWARE\sandbox-runtime (بيانات الاعتماد، العلامة، سجل المرجع المصدق CA) — مع موجه UAC واحد. يُترك %ProgramData%\sandbox-runtime (مادة مفتاح المرجع المصدق CA) في مكانه؛ احذفه يدويًا (وكذلك %LOCALAPPDATA%\sandbox-runtime لكل مستخدم) لإجراء تنظيف شامل.
التطوير```bash
Install dependencies
npm install
Build the project
npm run build
Run tests
npm test
Type checking
npm run typecheck
Lint code
npm run lint
Format code
npm run format
### بناء ثنائيات Seccomp
يتم تجميع مرشح BPF ومُحمّل `apply-seccomp` من كود C المصدر في `vendor/seccomp-src/` عبر `npm run build:seccomp` (لينكس فقط؛ يتطلب `gcc` و`libseccomp-dev`). يشغّله CI قبل الاختبارات على كل بنية لينكس، ويقوم سير عمل الإصدار ببناء البنيتين وضمّهما إلى الحزمة المنشورة.
## تفاصيل التنفيذ
### بنية عزل الشبكة
يشغّل الصندوق الرملي خوادم بروكسي HTTP وSOCKS5 على الجهاز المضيف تقوم بتصفية جميع طلبات الشبكة بناءً على قواعد الأذونات:
1. **حركة HTTP/HTTPS**: يلتقط خادم بروكسي HTTP الطلبات ويتحقق من صحتها مقابل النطاقات المسموح بها/المرفوضة
2. **حركة الشبكة الأخرى**: يتعامل بروكسي SOCKS5 مع جميع اتصالات TCP الأخرى (SSH، اتصالات قواعد البيانات، إلخ)
3. **فرض الأذونات**: تفرض البروكسيات قواعد `permissions` من إعداداتك
**اتصال البروكسي الخاص بالمنصة:**
- **لينكس**: يتم توجيه الطلبات عبر نظام الملفات فوق مقابس نطاق يونكس (باستخدام `socat` للربط). تتم إزالة مساحة اسم الشبكة من حاوية bubblewrap، مما يضمن أن جميع حركة الشبكة يجب أن تمر عبر البروكسيات.
- **macOS**: يسمح ملف تعريف Seatbelt بالاتصال فقط بمنافذ localhost محددة حيث تستمع البروكسيات. يتم حظر جميع وصول الشبكة الآخر.
- **ويندوز**: يحظر مرشح WFP `ALE_AUTH_CONNECT` كل اتصال صادر من حساب `srt-sandbox` باستثناء الحلقة المحلية إلى نطاق منافذ البروكسي المكوّن. ترتبط البروكسيات داخل هذا النطاق. تشير متغيرات البيئة (`HTTP_PROXY`، `HTTPS_PROXY`، `ALL_PROXY`، …) بالأدوات إلى البروكسيات، لكن مرشح WFP هو الحد الفاصل — العملية التي تتجاهلها أو تلغيها تظل محاطة بسياج.
### عزل نظام الملفات
يتم فرض قيود نظام الملفات على مستوى نظام التشغيل:
- **macOS**: يستخدم `sandbox-exec` مع ملفات تعريف Seatbelt مولّدة ديناميكيًا تحدد مسارات القراءة/الكتابة المسموح بها
- **لينكس**: يستخدم `bubblewrap` مع عمليات ربط، مع تحديد الدلائل كقراءة فقط أو قراءة-كتابة بناءً على الإعدادات
- **ويندوز**: يكتب ACEs صريحة إضافية `(OI)(CI)` لـ SID الخاص بـ `srt-sandbox` على المسارات المكوّنة (ALLOW على `allowRead`/`allowWrite`، DENY على `denyRead`/`denyWrite`)، ثم يزيلها عند `reset()`
**أذونات نظام الملفات الافتراضية:**
- **القراءة** (رفض-ثم-سماح): مسموح بها في كل مكان افتراضيًا. يمكنك رفض مناطق واسعة، ثم إعادة السماح بمسارات محددة داخلها. `allowRead` له الأولوية على `denyRead`.
- مثال: `denyRead: ["~/.ssh"]` لمنع الوصول إلى مفاتيح SSH
- مثال: `denyRead: ["/Users"], allowRead: ["."]` لمنع كل `/Users` باستثناء مساحة العمل
- `denyRead: []` فارغ = وصول قراءة كامل (لا شيء مرفوض)
- **الكتابة** (سماح فقط): مرفوضة في كل مكان افتراضيًا. يجب عليك السماح بالمسارات صراحةً.
- مثال: `allowWrite: [".", "/tmp"]` للسماح بالكتابة إلى الدليل الحالي و/tmp
- `allowWrite: []` فارغ = لا وصول كتابة (لا شيء مسموح)
- ينشئ `denyWrite` استثناءات داخل المسارات المسموح بها (الرفض له الأولوية)
**الأولوية معاكسة عمدًا للقراءة مقابل الكتابة:** يتجاوز `allowRead` `denyRead`، بينما يتجاوز `denyWrite` `allowWrite`. يتيح لك هذا اقتطاع مناطق قابلة للقراءة داخل مناطق مرفوضة، واقتطاع مناطق محمية داخل مناطق قابلة للكتابة.
### مسارات الرفض الإلزامية (الملفات المحمية تلقائيًا)
يتم **حظر الكتابة دائمًا** إلى بعض الملفات والدلائل الحساسة، حتى لو كانت ضمن مسار كتابة مسموح. يوفر هذا دفاعًا متعمقًا ضد هروب الصندوق الرملي والتلاعب بالإعدادات.
**الملفات المحظورة دائمًا:**
- ملفات إعدادات الصدفة: `.bashrc`، `.bash_profile`، `.zshrc`، `.zprofile`، `.profile`
- ملفات إعدادات Git: `.gitconfig`، `.gitmodules`
- ملفات حساسة أخرى: `.ripgreprc`، `.mcp.json`
**الدلائل المحظورة دائمًا:**
- دلائل IDE: `.vscode/`، `.idea/`
- دلائل إعدادات Claude: `.claude/commands/`، `.claude/agents/`
- خطافات Git والإعدادات: `.git/hooks/`، `.git/config`
يتم حظر هذه المسارات تلقائيًا — لا تحتاج إلى إضافتها إلى `denyWrite`. على سبيل المثال، حتى مع `allowWrite: ["."]`، ستفشل الكتابة إلى `.bashrc` أو `.git/hooks/pre-commit`:```bash
$ srt 'echo "malicious" >> .bashrc'
/bin/bash: .bashrc: Operation not permitted
$ srt 'echo "bad" > .git/hooks/pre-commit'
/bin/bash: .git/hooks/pre-commit: Operation not permitted
ملاحظة (لينكس): على لينكس، مسارات الرفض الإلزامية تحظر فقط الملفات الموجودة بالفعل. لا يمكن حظر الملفات غير الموجودة ضمن هذه الأنماط عبر نهج التركيب المرتبط (bind-mount) الخاص بـ bubblewrap. يستخدم macOS أنماط glob التي تحظر الملفات الموجودة والجديدة معًا.
عمق البحث في لينكس: على لينكس، يستخدم صندوق الحماية ripgrep لفحص الملفات الخطرة في المجلدات الفرعية ضمن مسارات الكتابة المسموح بها. افتراضيًا، يبحث حتى عمق 3 مستويات لتحسين الأداء. يمكنك ضبط ذلك عبر mandatoryDenySearchDepth:```json
{
"mandatoryDenySearchDepth": 5,
"filesystem": {
"allowWrite": ["."]
}
}
- الافتراضي: `3` (يبحث حتى عمق 3 مستويات)
- النطاق: من `1` إلى `10`
- القيم الأعلى توفر حماية أكبر لكن بأداء أبطأ
- الملفات في دليل العمل الحالي (CWD) (العمق 0) محمية دائمًا بغض النظر عن هذا الإعداد
### قيود مقابس يونكس (Linux)
على نظام Linux، يستخدم صندوق الرمل **seccomp BPF (Berkeley Packet Filter)** لحظر إنشاء مقابس نطاق يونكس (Unix domain sockets) على مستوى استدعاءات النظام. يوفر هذا طبقة إضافية من الأمان لمنع العمليات من إنشاء مقابس نطاق يونكس جديدة للاتصال بين العمليات المحلي (IPC) (ما لم يُسمح بذلك صراحةً).
**كيف يعمل:**
1. **مرشح BPF مدمج**: تشحن الحزمة ثنائي `apply-seccomp` ثابتًا لمعماريتي x64 وarm64 مع مرشح seccomp BPF مضمّن فيه. المرشح خاص بالمعمارية لكنه مستقل عن libc، لذا يعمل الثنائي مع كل من glibc وmusl.
2. **الاكتشاف في وقت التشغيل**: يكتشف صندوق الرمل تلقائيًا معمارية نظامك ويستخدم ثنائي `apply-seccomp` المطابق.
3. **تصفية استدعاءات النظام**: يعترض مرشح BPF استدعاء النظام `socket()` ويمنع إنشاء مقابس `AF_UNIX` بإرجاع `EPERM`. يمنع هذا الكود المعزول من إنشاء مقابس نطاق يونكس جديدة.
4. **تطبيق على مرحلتين باستخدام ثنائي apply-seccomp**:
- ينشئ bwrap الخارجي صندوق الرمل مع قيود نظام الملفات والشبكة ومساحة أسماء PID
- تبدأ عمليات جسر الشبكة (socat) داخل صندوق الرمل (تحتاج إلى مقابس يونكس)
- ينشئ apply-seccomp مساحة أسماء متداخلة user+PID+mount ويعيد تركيب `/proc`
- داخل مساحة الأسماء المتداخلة، يعمل apply-seccomp كـ PID 1 (init/reaper غير قابل للتفريغ)
- يتفرع apply-seccomp، ويطبق مرشح seccomp عبر `prctl()`، وينفذ أمر المستخدم
- يعمل أمر المستخدم مع جميع قيود صندوق الرمل بالإضافة إلى حظر إنشاء مقابس يونكس
**عزل مساحة أسماء PID**: تضمن مساحة أسماء PID المتداخلة أن أمر المستخدم لا يمكنه رؤية أو مخاطبة أي عملية تعمل بدون مرشح seccomp (init الخاص بـ bwrap، أو غلاف الصدفة، أو مساعدات socat). يحافظ هذا على حدود seccomp سليمة بغض النظر عن `kernel.yama.ptrace_scope`، لأن المساعدات غير المفلترة لا يمكن الوصول إليها عبر `ptrace` أو `/proc/N/mem`. يضبط PID 1 الداخلي `PR_SET_DUMPABLE=0` بحيث لا يكون قابلًا للتتبع عبر ptrace أيضًا. إذا فشل إنشاء مساحة الأسماء المتداخلة، يتوقف apply-seccomp بدلاً من التشغيل بدون عزل.
**القيود الأمنية**: يحظر المرشح `socket(AF_UNIX, ...)` واستدعاءات النظام `io_uring_setup`/`io_uring_enter`/`io_uring_register` (الثلاثة الأخيرة لأن `IORING_OP_SOCKET` على Linux 5.19+ سيتجاوز قاعدة `socket()` بخلاف ذلك). لا يمنع العمليات على واصفات ملفات مقابس يونكس الموروثة من العمليات الأصلية أو الممررة عبر `SCM_RIGHTS`. في معظم سيناريوهات صناديق الرمل، يكفي حظر إنشاء المقابس لمنع الاتصال بين العمليات غير المصرح به.
**صفر تبعيات وقت التشغيل**: يتم تضمين ثنائيات apply-seccomp الثابتة المبنية مسبقًا ومرشحات BPF المولدة مسبقًا لمعماريتي x64 وarm64. لا حاجة لأدوات تجميع أو تبعيات خارجية في وقت التشغيل.
**دعم المعماريات**: معماريتا x64 وarm64 مدعومتان بالكامل مع ثنائيات مبنية مسبقًا. المعماريات الأخرى غير مدعومة حاليًا. لاستخدام صندوق الرمل بدون حظر مقابس يونكس على معماريات غير مدعومة، اضبط `allowAllUnixSockets: true` في إعداداتك.
### اكتشاف الانتهاكات ومراقبتها
عندما تحاول عملية معزولة الوصول إلى مورد مقيد:
1. **يحظر العملية** على مستوى نظام التشغيل (يرجع خطأ `EPERM`)
2. **يسجل الانتهاك** (آليات خاصة بالمنصة)
3. **يخطر المستخدم** (في Claude Code، يؤدي هذا إلى ظهور مطالبة إذن)
**macOS**: يستفيد وقت تشغيل صندوق الرمل من مخزن سجل انتهاكات صندوق الرمل الخاص بنظام macOS. يوفر هذا إشعارات في الوقت الفعلي مع معلومات مفصلة حول ما تمت محاولته ولماذا تم حظره. هذه هي نفس الآلية التي يستخدمها Claude Code لاكتشاف الانتهاكات.```bash
# View sandbox violations in real-time
log stream --predicate 'process == "sandbox-exec"' --style syslog
Linux: لا يوفر Bubblewrap تقارير مدمجة عن الانتهاكات. استخدم strace لتتبع استدعاءات النظام وتحديد العمليات المحظورة:```bash
Trace all denied operations
strace -f srt 2>&1 | grep EPERM
Trace specific file operations
strace -f -e trace=open,openat,stat,access srt 2>&1 | grep EPERM
Trace network operations
strace -f -e trace=network srt 2>&1 | grep EPERM
### متقدم: إحضار وكيلك الخاص
لتصفية شبكة أكثر تطورًا، يمكنك تكوين بيئة الاختبار لاستخدام وكيلك الخاص بدلاً من الوكلاء المدمجين. يتيح ذلك:
- **فحص حركة المرور**: استخدم أدوات مثل [mitmproxy](https://mitmproxy.org/) لفحص وتعديل حركة المرور
- **منطق تصفية مخصص**: تنفيذ قواعد معقدة تتجاوز قوائم النطاقات المسموح بها البسيطة
- **تسجيل التدقيق**: تسجيل جميع طلبات الشبكة لأغراض الامتثال أو تصحيح الأخطاء
**مثال مع mitmproxy:**```bash
# Start mitmproxy with custom filtering script
mitmproxy -s custom_filter.py --listen-port 8888
ملاحظة: لا يدعم تنسيق التكوين الجديد التكوين المخصص للوكيل بعد. ستتم إضافة هذه الميزة في إصدار مستقبلي.
اعتبار أمني مهم: حتى مع قوائم النطاقات المسموح بها، قد توجد نواقل لسرقة البيانات. على سبيل المثال، السماح بـ github.com يتيح للعملية الدفع إلى أي مستودع. باستخدام وكيل MITM مخصص وإعداد شهادات مناسب، يمكنك فحص وتصفية استدعاءات API محددة لمنع ذلك.
القيود الأمنية
- قيود عزل الشبكة: يعمل نظام تصفية الشبكة عن طريق تقييد النطاقات التي يُسمح للعمليات بالاتصال بها. ولا يقوم بفحص حركة المرور المارة عبر الوكيل بخلاف ذلك، ويتحمل المستخدمون مسؤولية ضمان السماح فقط بالنطاقات الموثوقة في سياساتهم.
- تصعيد الامتيازات عبر مقابس Unix: يمكن لإعداد
allowUnixSocketsأن يمنح وصولًا غير مقصود إلى خدمات نظام قوية قد تؤدي إلى تجاوزات في العزل. على سبيل المثال، إذا تم استخدامه للسماح بالوصول إلى/var/run/docker.sock، فإن ذلك سيمنح فعليًا وصولًا إلى النظام المضيف من خلال استغلال مقبس docker. يُشجع المستخدمون على النظر بعناية في أي مقابس Unix يسمحون بها عبر العزل. - تصعيد صلاحيات نظام الملفات: يمكن لصلاحيات الكتابة الواسعة بشكل مفرط في نظام الملفات أن تتيح هجمات تصعيد الامتيازات. السماح بالكتابة إلى الدلائل التي تحتوي على ملفات تنفيذية في
$PATH، أو دلائل تكوين النظام، أو ملفات تكوين قشرة المستخدم (.bashrc,.zshrc) يمكن أن يؤدي إلى تنفيذ كود في سياقات أمنية مختلفة عندما يصل مستخدمون آخرون أو عمليات نظام إلى هذه الملفات. - قوة عزل Linux: يوفر تطبيق Linux عزلًا قويًا لنظام الملفات والشبكة ولكنه يتضمن وضع
enableWeakerNestedSandboxالذي يتيح العمل داخل بيئات Docker بدون مساحات أسماء مميزة. يضعف هذا الخيار الأمان بشكل كبير ويجب استخدامه فقط في الحالات التي يتم فيها فرض عزل إضافي بوسائل أخرى. - عزل شبكة أضعف (macOS): يعيد خيار
enableWeakerNetworkIsolationتمكين الوصول إلىcom.apple.trustd.agent، وهو مطلوب لبرامج Go للتحقق من شهادات TLS عبر إطار عمل الأمان في macOS. يفتح هذا ناقلًا محتملًا لسرقة البيانات عبر خدمة trustd ويجب تمكينه فقط عند الحاجة إلى التحقق من TLS لـ Go (على سبيل المثال، عند استخدامhttpProxyPortمع وكيل MITM وشهادة CA مخصصة). - أحداث Apple (macOS): يعيد خيار
allowAppleEventsتمكين إرسال أحداث Apple وطلبات فتح Launch Services ((allow appleevent-send),(allow lsopen)، وعمليات mach-lookup لـcom.apple.coreservices.appleevents، وcom.apple.CoreServices.coreservicesd، وcom.apple.coreservices.quarantine-resolver)، والتي تتطلبهاopenوosascriptوأدوات فتح عناوين URL. مع السماح بهذه، يمكن لأمر معزول تشغيل تطبيقات عشوائية بدون مطالبة المستخدم، ويتم تشغيل التطبيقات التي تم إطلاقها خارج العزل تمامًا — لذا يزيل هذا الخيار عزل تنفيذ الكود، وليس مجرد إضعافه. كتابة سكربتات للتطبيقات التي تعمل بالفعل عبر أحداث Apple تخضع أيضًا لموافقة أتمتة TCC في macOS، لكن التشغيل عبرopenلا يخضع لها. قم بتمكين هذا فقط عندما تحتاج الأوامر داخل العزل فعليًا إلى فتح عناوين URL أو تطبيقات.
القيود المعروفة والعمل المستقبلي
تجاوز الوكيل في Linux: يستخدم حاليًا متغيرات البيئة (HTTP_PROXY, HTTPS_PROXY, ALL_PROXY) لتوجيه حركة المرور عبر الوكلاء. يعمل هذا مع معظم التطبيقات ولكن قد يتم تجاهله بواسطة البرامج التي لا تحترم هذه المتغيرات، مما يؤدي إلى عدم قدرتها على الاتصال بالإنترنت.
تحسينات مستقبلية:
-
دعم Proxychains: إضافة دعم لـ
proxychainsمعLD_PRELOADعلى Linux لاعتراض استدعاءات الشبكة على مستوى أدنى، مما يجعل التجاوز أكثر صعوبة -
مراقبة الانتهاكات في Linux: تنفيذ كشف تلقائي للانتهاكات قائم على
straceلنظام Linux، مدمج مع مخزن الانتهاكات. حاليًا، يجب على مستخدمي Linux تشغيلstraceيدويًا لرؤية الانتهاكات، على عكس macOS الذي يحتوي على مراقبة تلقائية للانتهاكات عبر مخزن سجل النظام