پروتکل امنیتی لایه انتقال TLS 1.3 محرمانگی محتوای بسته‌ها را در برابر استراق سمع گره‌های میانی اینترنت حفظ می‌کند. با این حال، در سطوح زیرین رمزنگاری، یک آسیب‌پذیری ساختاری در بخش متادیتا وجود دارد: سرور مقصد همواره آدرس IP فرستنده اصلی را مشاهده می‌کند.

در تراکنش‌های معمول وب، این موضوع به عنوان بخشی از ماهیت مسیریابی پذیرفته شده است. اما در تعاملات بسیار حساس — مانند ارسال پرامپت‌ها به مدل‌های هوش مصنوعی (LLM)، ارسال گزارش‌های تشخیصی سیستم، اعتبارسنجی‌های زیست‌سنجی یا موقعیت‌یابی — آدرس IP نقشی پایدار در ردگیری هویت ایفا می‌کند. سرورها می‌توانند با تطبیق زمان و آدرس‌های شبکه، پروفایل دقیقی از رفتارهای دیجیتال کاربر بسازند حتی اگر کاربر وارد حسابی نشده باشد.

پروکسی‌های متداول صرفاً نقطه نظارت را جابجا می‌کنند، زیرا اپراتور پروکسی هم IP کاربر و هم سرور مقصد را می‌بیند. کارگروه مهندسی اینترنت (IETF) برای پایان دادن به این وابستگی، استاندارد RFC 9458 (Oblivious HTTP یا OHTTP) را به همراه RFC 9180 (Hybrid Public Key Encryption یا HPKE) و RFC 9292 (Binary HTTP) تصویب کرده است.

+--------------------------------------------------------------------------+
|                  معماری استاندارد RFC 9458 OBLIVIOUS HTTP                |
+--------------------------------------------------------------------------+
|                                                                          |
|    +------------+        1. ارسال درخواست رمزگذاری شده    +------------+ |
|    |            | --------------------------------------> |   سرور     | |
|    |   کلاینت   | <-------------------------------------- | بازپخش رله | |
|    | (مرورگر /  |        4. دریافت پاسخ رمزگذاری شده      |  (Relay)   | |
|    | عامل AI)   |                                         +------------+ |
|    +------------+                                               |        |
|          |                                            2. هدایت  |3. ارسال|
|          | (آدرس IP کلاینت فقط برای سرور رله آشکار است)  داده   |پاسخ    |
|          | (محتوا با کلید عمومی سرور مقصد قفل شده است)   رمز شده|رمز شده |
|          |                                                      v        |
|          |                                                +------------+ |
|          +----------------------------------------------> |   سرور     | |
|                 (مرز رمزنگاری شده سرتاسری)                |   مقصد     | |
|                 سرور مقصد داده را با کلید HPKE باز می کند |  (Target)  | |
|                 سرور مقصد فقط IP سرور رله را مشاهده میکند +------------+ |
|                                                                          |
+--------------------------------------------------------------------------+

پایه‌های رمزنگاری: ساختار HPKE و فریم‌بندی Binary HTTP

استاندارد RFC 9458 بر پایه اصل عدم تبانی میان دو نهاد زیرساختی عمل می‌کند: سرور رله (Relay) و سرور مقصد (Target). سرور رله بسته‌های رمزگذاری شده را بدون توانایی باز کردن هدایت می‌کند؛ در حالی که سرور مقصد محتوا را پردازش کرده اما تنها آدرس شبکه سرور رله را می‌بیند.

این ساختار امنیتی متکی بر دو مولفه است:

1. ساختار باینری پیام‌های وب (RFC 9292)

در OHTTP، تمامی اجزای یک درخواست وب شامل متد، مسیر، سرآیندها و بدنه، به یک آرایه فشرده و استاندارد از بایت‌ها به نام Binary HTTP (یا BHTTP) تبدیل می‌شوند:

+--------------------+--------------------------------+--------------------+
| فیلدهای کنترل فریم | سرآیندهای فهرست شده            | بدنه داده باینری   |
| (GET /api/v1/query)| (Host: target.example.com ...) | (Binary payload)   |
+--------------------+--------------------------------+--------------------+

این فرمت باینری هرگونه ناهماهنگی در تحلیل متنی داده‌ها را پیش از اجرای محاسبات رمزنگاری برطرف می‌سازد.

2. رمزنگاری ترکیبی کلید عمومی (HPKE, RFC 9180)

کلاینت برای مصون نگه‌داشتن داده‌ها از سرور رله، پیام Binary HTTP را با کلید عمومی سرور مقصد رمزنگاری می‌کند. سرور مقصد یک پیکربندی کلید OHTTP منتشر می‌کند که شامل موارد زیر است:

  • key_id: شناسه یک بایتی برای تمایز کلیدها در زمان چرخش دوره‌ای؛
  • kem_id: ساختار بسته‌بندی کلید (0x0020 برای منحنی Curve25519)؛
  • kdf_id: تابع مشتق‌سازی کلید (0x0001 برای HKDF-SHA256)؛
  • aead_id: الگوریتم رمزنگاری احراز اصالت شده (0x0001 برای AES-128-GCM یا 0x0003 برای ChaCha20-Poly1305)؛
  • public_key: بایت‌های اصلی کلید عمومی سرور مقصد.

کلاینت با استفاده از حالت پایه HPKE، یک جفت کلید موقت $(sk_E, pk_E)$ می‌سازد و کلید مشترک را محاسبه می‌کند:

$$ ext{SharedSecret} = ext{DH}(sk_E, pk_T)$$

سپس با استفاده از الگوریتم HKDF، کلید رمزگذاری $K_{ ext{req}}$ و بردار تصادفی $N_{ ext{req}}$ به دست می‌آید:

$$(K_{ ext{req}}, N_{ ext{req}}) = ext{KeyDerivation}( ext{SharedSecret}, ext{info})$$

سپس کل پیام باینری مهر و موم شده و به متن رمز شده $C_{ ext{req}}$ تبدیل می‌شود:

$$C_{ ext{req}} = ext{Seal}(K_{ ext{req}}, N_{ ext{req}}, ext{aad}, ext{BinaryHTTPRequest})$$

این بسته با برچسب رسانه‌ای message/ohttp-req و ساختار زیر ارسال می‌شود: [KeyID (1 بایت)] || [KEM (2 بایت)] || [KDF (2 بایت)] || [AEAD (2 بایت)] || [enc (32 بایت)] || [متن رمز]

از آنجا که کلید خصوصی متناظر تنها در اختیار سرور مقصد است، سرور رله قادر به خواندن یا دستکاری محتوا نخواهد بود.

+--------------------------------------------------------------------------+
|                      جدول دسترسی به اطلاعات در شبکه                      |
+--------------------------------------------------------------------------+
| نهاد فعال    | آدرس IP واقعی را می‌بیند؟ | محتوای درخواست را می‌بیند؟| پاسخ؟   |
+--------------+---------------------------+---------------------------+---------+
| ارائه‌دهنده وب| بله                       | خیر (تونل TLS)            | خیر     |
| سرور رله     | بله (یا IP وی‌پی‌ان)       | خیر (متن رمز HPKE)        | خیر     |
| سرور مقصد    | خیر (فقط IP رله را می‌بیند)| بله (داده بازگشایی شده)   | بله     |
+--------------------------------------------------------------------------+

چرخه اجرای تراکنش در پروتکل Oblivious HTTP

فرآیند تبادل داده در این پروتکل در پنج گام اجرایی خلاصه می‌شود:

  1. دریافت اطلاعات کلید مقصد: کلاینت اطلاعات کلید عمومی سرور مقصد را از طریق رکوردهای DNS HTTPS یا مسیرهای مورد اعتماد دریافت می‌کند.
  2. کپسوله‌سازی و قفل داده: کلاینت پیام را به BHTTP تبدیل کرده، جفت کلید موقت را ایجاد می‌کند و بسته message/ohttp-req را می‌سازد.
  3. ارسال از طریق رله: بسته از طریق HTTPS POST /relay به سرور رله فرستاده می‌شود. سرور رله متادیتاهای فرستنده را پاک کرده و بسته را برای سرور مقصد ارسال می‌کند.
  4. گشایش رمز در مقصد: سرور مقصد بر اساس key_id بسته را باز کرده و عملیات لازم (نظیر پردازش هوش مصنوعی) را انجام می‌دهد.
  5. ارسال پاسخ رمزنگاری شده: سرور مقصد داده‌های پاسخ را با کلید استخراج شده $K_{ ext{res}}$ رمز کرده و در قالب message/ohttp-res برای سرور رله می‌فرستد تا به کلاینت تحویل داده شود.

هماهنگی با پروتکل RiceGuard و شبکه‌های لایه ۳

اگرچه OHTTP در لایه کاربرد (L7) فعالیت دارد، ترکیب آن با تونل‌های شبکه لایه ۳ (L3) نظیر معماری RiceGuard در VPNRice سطح ایمنی را دوچندان می‌کند:

  1. حذف ردگیری در سرور رله: هنگام ارسال ترافیک از بستر RiceGuard، سرور رله آدرس فرستنده را یک گیت‌وی تجمیعی VPN می‌بیند نه آدرس شبکه خانگی، در نتیجه امکان ردیابی کاربران سلب می‌شود.
  2. امنیت در استعلام نام دامنه (DNS): کلیه مراحل ترجمه آدرس‌های رله و سرور مقصد در فضای ایزوله شده RiceGuard انجام می‌پذیرد.
  3. پوشش داده‌های عامل‌های هوش مصنوعی (AI Agents): نرم‌افزارهای پردازش محلی که به ابزارهای ابری متصل می‌شوند، می‌توانند با هدایت داده‌ها از بستر OHTTP بر روی RiceGuard، از عدم ذخیره‌سازی آدرس IP خود توسط ارائه‌دهندگان مدل اطمینان یابند.

نمونه کد کلاینت به زبان Go

قطعه کد زیر پیاده‌سازی ساخت بسته باینری و رمزنگاری آن با HPKE را به زبان Go نشان می‌دهد:

package main

import (
	"bytes"
	"crypto/rand"
	"fmt"
	"io"
	"net/http"

	"github.com/cloudflare/circl/hpke"
)

type OHTTPEncapsulator struct {
	suite    hpke.Suite
	targetPK hpke.PublicKey
	keyID    uint8
}

func NewOHTTPEncapsulator(keyID uint8, kemID hpke.KEM, kdfID hpke.KDF, aeadID hpke.AEAD, rawPubKey []byte) (*OHTTPEncapsulator, error) {
	suite := hpke.NewSuite(kemID, kdfID, aeadID)
	pk, err := suite.KEM().Scheme().UnmarshalBinaryPublicKey(rawPubKey)
	if err != nil {
		return nil, fmt.Errorf("خطا در خواندن کلید عمومی: %w", err)
	}
	return &OHTTPEncapsulator{
		suite:    suite,
		targetPK: pk,
		keyID:    keyID,
	}, nil
}

// EncapsulateRequest بسته باینری را در قالب message/ohttp-req رمز میکند
func (oe *OHTTPEncapsulator) EncapsulateRequest(bhttpReq []byte) ([]byte, hpke.Context, error) {
	sender, err := oe.suite.NewSender(oe.targetPK, []byte("message/bhttp request"))
	if err != nil {
		return nil, nil, fmt.Errorf("خطا در ایجاد فرستنده HPKE: %w", err)
	}

	enc, ctx, err := sender.Setup(rand.Reader)
	if err != nil {
		return nil, nil, fmt.Errorf("خطا در آماده سازی HPKE: %w", err)
	}

	ciphertext, err := ctx.Seal(nil, bhttpReq)
	if err != nil {
		return nil, nil, fmt.Errorf("خطا در قفل داده ها: %w", err)
	}

	var buf bytes.Buffer
	buf.WriteByte(oe.keyID)
	buf.Write([]byte{0x00, 0x20}) // DHKEM(X25519, HKDF-SHA256)
	buf.Write([]byte{0x00, 0x01}) // HKDF-SHA256
	buf.Write([]byte{0x00, 0x01}) // AES-128-GCM
	buf.Write(enc)
	buf.Write(ciphertext)

	return buf.Bytes(), ctx, nil
}

func SendToRelay(relayURL string, targetURL string, ohttpPayload []byte) ([]byte, error) {
	req, err := http.NewRequest("POST", relayURL, bytes.NewReader(ohttpPayload))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "message/ohttp-req")
	req.Header.Set("Target", targetURL)

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("خطا در ارسال بسته به رله: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("پذیرفته نشدن توسط رله: کد HTTP %d", resp.StatusCode)
	}

	return io.ReadAll(resp.Body)
}

ملاحظات اجرایی و چشم‌انداز آینده

استقرار عملیاتی این استاندارد متضمن در نظر گرفتن نکات زیر است:

  • تاخیر شبکه: عبور از دو سرور مجزا (کلاینت $ o$ رله $ o$ مقصد) باعث افزایش زمان رفت و برگشت به میزان ۲۰ الی ۴۵ میلی‌ثانیه می‌شود، بنابراین این سیستم برای تبادلات API و تلمتری بهینه است نه وبگردی‌های سنگین.
  • تطبیق حافظه موقت (Cache): شبکه‌های CDN محتوا را با تکیه بر آدرس URL ذخیره می‌کنند. به دلیل کدر بودن داده‌های OHTTP، اعمال کش نیازمند برچسب‌های اختصاصی خواهد بود.
  • جداسازی کامل مدیریت: سرورهای رله و مقصد حتماً باید تحت نظارت سازمان‌های کاملاً جداگانه فعالیت کنند تا امکان تبادل لاگ‌ها به صفر برسد.

استاندارد RFC 9458 نشان می‌دهد که جداسازی قطعی هویت از اطلاعات با تکیه بر رمزنگاری مدرن مسیری مطمئن برای حفاظت از حریم شخصی است.