رسائل OTP والتحقق عبر البريد الإلكتروني: السرعة والأمان وأفضل الممارسات

كيف تولّد رموز التحقق لمرة واحدة وروابط التأكيد وتخزّنها وترسلها بالبريد الإلكتروني بأمان، مع تسليم سريع وصلاحية معقولة وحدود معدّل وقالب يثق به المستخدمون.

رسالة الرمز لمرة واحدة هي أكثر رسالة ينتظرها المستخدم بفارغ الصبر من بين كل ما سيرسله منتجك. فالمستخدم يحدّق في شاشة تقول “أدخل الرمز المكوّن من 6 أرقام الذي أرسلناه إليك”، وكل ثانية تتأخرها الرسالة هي ثانية يتساءل فيها إن كان عليه أن يستسلم.

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

رموز أم روابط؟

هناك شكلان شائعان:

  • الرموز لمرة واحدة (OTP): رقم قصير مثل 482913 يُكتب في تطبيقك. مناسبة لتسجيل الدخول والتحقق بخطوتين، وتعمل حين يقرأ المستخدم بريده على جهاز آخر.
  • روابط التحقق: رمز مميّز عشوائي طويل داخل عنوان URL. مناسبة لتأكيد عنوان البريد عند التسجيل أو إعادة تعيين كلمة المرور، لأن نقرة واحدة تُكمل العملية.

كل ما يلي ينطبق على الشكلين. والفرق في الغالب هو الطول: يمكن للروابط أن تحمل رمزًا مميّزًا طويلًا، أما الرموز فيجب أن تكون قصيرة بما يكفي لكتابتها.

ولّد الرموز بأمان

استخدم مولّد الأرقام العشوائية الآمن تشفيريًا في لغتك. فـ Math.random() ووحدة random في Python قابلان للتنبؤ، ويجب ألا يُستخدما أبدًا لرموز الأمان.

// Node.js
import { randomInt, createHmac } from 'node:crypto';

const code = String(randomInt(0, 1_000_000)).padStart(6, '0'); // "048213"
// Keyed hash: OTP_SECRET lives in your secrets manager, never in the database.
const codeHash = createHmac('sha256', process.env.OTP_SECRET).update(`${user.id}:${code}`).digest('hex');
# Python
import hashlib
import hmac
import os
import secrets

code = f"{secrets.randbelow(1_000_000):06d}"
# Keyed hash: OTP_SECRET lives in your secrets manager, never in the database.
code_hash = hmac.new(os.environ["OTP_SECRET"].encode(), f"{user_id}:{code}".encode(), hashlib.sha256).hexdigest()

لا تخزّن إلا تجزئة بمفتاح (HMAC)، مع معرّف المستخدم ووقت انتهاء الصلاحية وعدّاد المحاولات. فتجزئة SHA-256 العادية لا تكفي: مع مليون رمز ممكن فقط، يستطيع أي شخص يملك قاعدة البيانات تجربتها كلها في أقل من ثانية. أما HMAC فتحتاج إلى سرّ محفوظ خارج قاعدة البيانات، فلا يكشف تسرّب قاعدة البيانات وحده الرموز السارية.

صلاحية قصيرة ومحاولات محدودة

للرمز المكوّن من ستة أرقام مليون احتمال. وهذا كافٍ فقط إذا لم يتمكن المهاجمون من مواصلة التخمين:

الضابط القيمة الموصى بها
مدة صلاحية الرمز 10 دقائق لرموز تسجيل الدخول؛ وحتى 24 ساعة لروابط تأكيد البريد الإلكتروني
المحاولات الخاطئة لكل رمز 5، ثم يصبح الرمز غير صالح
الرموز المُرسلة لكل عنوان نحو 3 كل 15 دقيقة، مع فترة انتظار ظاهرة على زر “إعادة الإرسال”
الرموز المُرسلة لكل عنوان IP حدّ أعلى، لمنع مهاجم واحد من التنقّل بين عناوين كثيرة
الاستخدام لمرة واحدة: احذف الرمز أو علّمه مستخدمًا لحظة نجاحه

قارن الرموز دائمًا في زمن ثابت (crypto.timingSafeEqual في Node.js وhmac.compare_digest في Python)، ويجب أن يُبطل إصدارُ رمز جديد الرمزَ السابق.

أرسله فورًا

يجب أن تُرسل رسائل OTP ضمن الطلب نفسه الذي طلبها، لا في مهمة دفعية تعمل كل دقيقة. ومع Inbixio يكفي استدعاء واحد:

await fetch('https://backend.inbixio.com/api/send-email/', {
  method: 'POST',
  headers: { 'X-API-Key': process.env.INBIXIO_API_KEY, 'Content-Type': 'application/json' },
  body: JSON.stringify({
    to_email: user.email,
    subject: `${code} is your YourApp sign-in code`,
    message: otpTemplate({ code, minutes: 10 }),
  }),
  signal: AbortSignal.timeout(10_000),
});

تقبل Inbixio الطلب وتضيف التسليم إلى قائمة الإرسال فورًا، فتستطيع نقطة النهاية لديك الاستجابة بسرعة. وإن فشل الاستدعاء، فأخبر المستخدم على الفور (“تعذّر إرسال رمزك. يُرجى المحاولة مجددًا بعد لحظات”) بدلًا من تركه ينتظر رسالة لن تصل أبدًا. يسرد دليل معالجة أخطاء واجهة برمجة البريد الإلكتروني الأخطاء التي تستحق إعادة محاولة تلقائية.

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

  • استخدم مُرسِلًا مخصّصًا، مثل security@yourco.com، مربوطًا خادمًا مستقلًا، مع مفتاح API مربوط به (وأعد ربط المفتاح إن أزلت ذلك الخادم يومًا). سيعتاد المستخدمون الثقة بهذا العنوان، ولن تؤثر الحملات التسويقية في سمعته.
  • وثّق نطاقك. الرموز التي تصل إلى البريد المزعج رموز لا تصل أبدًا. اتّبع قائمة التحقق من SPF وDKIM وDMARC.

اكتب رسالة لا يمكن الخلط بينها وبين التصيّد

يتنافس قالبك مع رسائل تصيّد تنسخ هذا الشكل تمامًا. فاجعل الرسالة الحقيقية سهلة التمييز:

  • ضع الرمز في سطر الموضوع، مثل “482913 هو رمز تسجيل دخولك إلى YourApp”. يستطيع المستخدم قراءته من الإشعار دون فتح الرسالة، وتستطيع لوحات مفاتيح الهواتف اقتراحه.
  • وضّح الغرض منه ومدة صلاحيته: “استخدم هذا الرمز لتسجيل الدخول إلى YourApp. تنتهي صلاحيته خلال 10 دقائق.”
  • وضّح ما يجب فعله إن لم يكن هو من طلبه: “إن لم تحاول تسجيل الدخول، يمكنك تجاهل هذه الرسالة. حسابك آمن.”
  • لا تطلب الرمز أبدًا. صرّح بذلك بوضوح: “لن تطلب منك YourApp هذا الرمز أبدًا عبر الهاتف أو البريد الإلكتروني.”
  • اجعلها قصيرة وخالية من التسويق، وقلّل الروابط إلى أدنى حدّ ممكن.

قالب HTML بسيط وسهل الوصول:

<div style="font-family:system-ui,sans-serif;max-width:480px;margin:auto;color:#111">
  <p>Use this code to sign in to YourApp:</p>
  <p style="font-size:32px;font-weight:700;letter-spacing:6px;margin:24px 0">482913</p>
  <p>It expires in 10 minutes. If you didn't try to sign in, you can ignore this email.</p>
  <p style="color:#666;font-size:13px">YourApp will never ask you for this code.</p>
</div>

الأنماط المضمّنة مقصودة. فكثير من برامج البريد تحذف كتل <style>، لذا فإن CSS المضمّنة هي أكثر الطرق موثوقية لتنسيق البريد الإلكتروني.

لا تكشف أي العناوين لديها حسابات

في شاشة تسجيل الدخول أو “أرسل لي رمزًا”، اعرض الاستجابة نفسها سواء كان العنوان مسجّلًا أم لا: “إن كان هناك حساب مرتبط بهذا العنوان، فقد أرسلنا إليه رمزًا.” وإلا أصبح نموذجك أداة مجانية لمعرفة عناوين البريد التي تستخدم منتجك.

قائمة التحقق

  • رموز من مولّد آمن تشفيريًا؛ ولا يُخزَّن إلا HMAC، مع حفظ السر خارج قاعدة البيانات
  • صلاحية 10 دقائق، واستخدام لمرة واحدة، و5 محاولات، ومقارنة في زمن ثابت
  • حدود معدّل لكل عنوان ولكل IP، مع فترة انتظار لإعادة الإرسال
  • إرسال فوري، مع رسالة خطأ واضحة إن فشل الإرسال
  • عنوان مُرسِل مخصّص وموثَّق
  • الرمز في الموضوع، والغرض والصلاحية في نص الرسالة، وإرشاد “لم تكن أنت؟”
  • الاستجابة نفسها سواء كان الحساب موجودًا أم لا

أرسلها عبر Inbixio

اربط خادم SMTP الخاص بك، وأنشئ مفتاح API بصلاحيات محدّدة، وأرسل من أي لغة برمجة بطلب HTTPS واحد.

إنشاء حساب عرض الأسعار