سیاست Same-Origin در مرورگرها به طور پیش‌فرض دسترسی به localStorage را فقط به دامنه‌ای که داده را در آن ذخیره کرده محدود می‌کند. اما در توسعه وب مدرن، گاهی نیاز است بین زیردامنه‌ها (مثلا app.example.com و api.example.com) یا حتی دامنه‌های مجزا، داده‌هایی مانند توکن احراز هویت، تنظیمات کاربر یا وضعیت سبد خرید را به اشتراک بگذاریم. در این مقاله، سه روش کاربردی و تست‌شده برای حل این چالش را بررسی می‌کنیم که به راحتی می‌توانید در پروژه خود از آن استفاده کنید.

جاوااسکریپت

روش اول - ارتباط امن با postMessage و iframe

این روش، استانداردترین و منعطف‌ترین راه برای ارتباط بین دامنه‌ای است. در این الگو، شما یک فایل HTML سبک (به نام Hub) روی دامنه مقصد (مثلا storage.example.com) میزبانی می‌کنید که وظیفه تعامل مستقیم با localStorage را دارد. دامنه اصلی (Client) این فایل را در یک iframe نامرئی بارگذاری کرده و با استفاده از postMessage درخواست خواندن یا نوشتن داده را ارسال می‌کند.

// کد داخل iframe (دامنه مقصد: storage.example.com)
window.addEventListener("message", function(event) {
  // بررسی امنیتی origin بسیار حیاتی است
  if (event.origin !== "https://main-domain.com") return;

  if (event.data.method === "get") {
    const value = localStorage.getItem(event.data.key);
    event.source.postMessage({ key: event.data.key, value: value }, event.origin);
  } else if (event.data.method === "set") {
    localStorage.setItem(event.data.key, event.data.value);
  }
}, false);

در سمت دامنه اصلی، به این صورت عمل می‌کنیم:

// کد دامنه اصلی (main-domain.com)
const iframe = document.getElementById("storage-frame");
iframe.contentWindow.postMessage(
  { method: "set", key: "auth_token", value: "xyz123" }, 
  "https://storage.example.com"
);

روش دوم - استفاده از کتابخانه Cross-Storage

اگر می‌خواهید از یک روش آماده استفاده کنید، کتابخانه متن‌باز cross-storage شرکت Zendesk برای این هدف پیاده‌سازی شده است. این کتابخانه بر پایه همان منطق postMessage ساخته شده، اما مدیریت اتصال، Promiseها و مجوزهای دسترسی (Permissions) را به شکلی حرفه‌ای و تمیز مدیریت می‌کند.

در دامنه مرکزی (Hub)، مجوزها را بر اساس Regex تعریف می‌کنید تا کنترل دقیقی روی دسترسی‌ها داشته باشید:

// در دامنه مرکزی (hub.example.com)
CrossStorageHub.init([
  { origin: /\.example\.com$/, allow: ['get', 'set', 'del'] },
  { origin: /:\/\/(www\.)?trusted-domain\.com$/, allow: ['get'] }
]);

سپس در سمت کلاینت، به راحتی و با استفاده از Promiseها با آن ارتباط برقرار می‌کنید:

// در دامنه کلاینت
const storage = new CrossStorageClient('https://hub.example.com/hub.html');

storage.onConnect().then(function() {
  return storage.set('user_prefs', JSON.stringify({ theme: 'dark' }));
}).then(function() {
  return storage.get('user_prefs');
}).then(function(res) {
  console.log('داده دریافت شد:', res);
}).catch(function(err) {
  console.error('خطا در دسترسی:', err);
});

نکته مهم در مورد مرورگر سافاری

در مرورگر سافاری (نسخه ۷ به بعد)، دسترسی به ذخیره‌سازی بین دامنه‌ای به دلیل تنظیمات حریم خصوصی ("Block cookies and other website data") به طور پیش‌فرض مسدود است. در این شرایط، iframe فقط به یک فضای ایزوله دسترسی خواهد داشت و ممکن است نیاز به راهکار جایگزین مانند کوکی‌های دامنه ریشه (Root Cookies) داشته باشید.

ترفند انتقال یک‌باره داده با پروتکل javascript

اگر هدف شما اشتراک‌گذاری دائمی نیست و فقط می‌خواهید داده‌ها را یک‌بار از یک دامنه قدیمی به دامنه جدید مهاجرت دهید (بدون نیاز به باز کردن کنسول توسعه‌دهنده)، می‌توانید از یک ترفند خلاقانه در نوار آدرس مرورگر استفاده کنید. این روش برای مهاجرت داده‌های کاربران موبایل بسیار کارآمد است.

کد زیر را در نوار آدرس دامنه مبدأ اجرا کنید تا داده را خوانده و به دامنه مقصد منتقل کند:

javascript:window.location.href = "https://new-domain.com/migrate?data=" + encodeURIComponent(localStorage.getItem("my_data"));

سپس در دامنه جدید (new-domain.com)، اسکریپت زیر داده را از URL خوانده و در localStorage جدید ذخیره می‌کند:

<script>
  if (location.search.includes("data=")) {
    const params = new URLSearchParams(location.search);
    const data = params.get("data");
    if (data) {
      localStorage.setItem("my_data", decodeURIComponent(data));
      alert("انتقال داده با موفقیت انجام شد!");
    }
  }
</script>

خلاصه و نکات امنیتی

  • روش postMessage و کتابخانه Cross-Storage برای ارتباطات دائمی و بلادرنگ بهترین گزینه‌ها هستند.
  • همیشه در postMessage مقدار event.origin را بررسی کنید تا از حملات XSS و تزریق داده جلوگیری شود.
  • تنظیم document.domain برای یکسان‌سازی زیردامنه‌ها منسوخ شده و به دلایل امنیتی دیگر توصیه نمی‌شود.
  • ترفند javascript: فقط برای مهاجرت یک‌باره مناسب است و نباید به عنوان یک معماری ارتباطی در نظر گرفته شود.

با انتخاب روش مناسب بر اساس نیاز پروژه، می‌توانید محدودیت‌های Same-Origin را به شکلی امن و کارآمد مدیریت کنید.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *