توليد السلاسل النصية العشوائية مهمة شائعة في تطوير الويب - سواء كنت تقوم بإنشاء معرفات فريدة، رموز مميزة آمنة، كلمات مرور، أو معرفات جلسات. في هذا الدليل الشامل، سنستكشف جميع الطرق الحديثة لتوليد السلاسل النصية العشوائية في JavaScript، سواء على جانب العميل أو الخادم، مع التركيز على الأمان والأداء.
ستتعلم:
- طرق آمنة مشفرة (لكلمات المرور، الرموز المميزة)
- طرق سريعة (لحالات الاستخدام غير الحساسة أمنياً)
- تقنيات ES6+ حديثة
- مقارنات الأداء
- حالات الاستخدام الواقعية وأفضل الممارسات
متى تحتاج سلاسل نصية عشوائية؟#
قبل الغوص في الكود، دعنا نفهم حالات الاستخدام الشائعة:
حساسة أمنياً (استخدم طرق آمنة مشفرة):
- توليد كلمات المرور - كلمات مرور أولية للمستخدمين
- رموز API - رموز المصادقة التي تدوم أسابيع/أشهر
- معرفات الجلسات - معرفات فريدة لجلسات المستخدم
- رموز إعادة تعيين كلمة المرور - رموز محدودة زمنياً ترسل عبر البريد الإلكتروني
- رموز CSRF - حماية من تزوير الطلبات عبر المواقع
غير حساسة أمنياً (Math.random() مناسب):
- معرفات العناصر الفريدة - مفاتيح React، معرفات عناصر DOM
- كسر الذاكرة المؤقتة - معاملات استعلام عشوائية للموارد
- أسماء الملفات المؤقتة - رفع الملفات قبل المعالجة
- بيانات الاختبار - توليد بيانات وهمية للاختبار
جدول مقارنة سريع#
| الطريقة | حالة الاستخدام | الأمان | السرعة | المتصفح | Node.js |
|---|---|---|---|---|---|
crypto.randomBytes() | رموز API، كلمات المرور | ✅ عالي | سريع | ❌ | ✅ |
crypto.getRandomValues() | رموز جانب العميل | ✅ عالي | سريع | ✅ | ❌ |
crypto.randomUUID() | معرفات فريدة | ✅ عالي | أسرع | ✅ (>15) | ✅ (>14) |
Math.random() | غير أمني | ❌ منخفض | أسرع | ✅ | ✅ |
nanoid | معرفات فريدة قصيرة | ✅ عالي | سريع جداً | ✅ | ✅ |
طرق Node.js (جانب الخادم)#
1. سلسلة hex آمنة مشفرة#
مثالية لرموز API ومعرفات الجلسات:
import crypto from 'crypto';
function generateToken(length = 32) {
return crypto
.randomBytes(Math.ceil(length / 2))
.toString('hex')
.slice(0, length);
}
console.log(generateToken(32));
// الناتج: "a7f5c3e9d2b1a4f6c8e0d9b2a5f7c3e1"
متى تستخدم: رموز API، معرفات الجلسات، معرفات قاعدة البيانات
المزايا:
- آمنة مشفرة
- لا تبعيات خارجية
- أداء سريع
العيوب:
- تعمل فقط في Node.js
- محدودة بحروف hex (0-9، a-f)
2. سلسلة Base64 آمنة مشفرة#
أكثر إحكاماً من hex، جيد للروابط:
import crypto from 'crypto';
function generateUrlSafeToken(length = 32) {
return crypto
.randomBytes(length)
.toString('base64url')
.slice(0, length);
}
console.log(generateUrlSafeToken(32));
// الناتج: "K7xP-zQ2mR8vN5tL3wY6jF9cH4dS1aE0"
متى تستخدم: رموز آمنة للروابط، رموز التحقق من البريد الإلكتروني
المزايا:
- آمن للروابط (لا يحتاج ترميز خاص)
- أكثر إحكاماً من hex
- آمن مشفرة
3. مجموعة أحرف مخصصة#
لكلمات المرور أو المتطلبات المحددة:
import crypto from 'crypto';
function generatePassword(
length = 16,
charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()'
) {
const randomBytes = crypto.randomBytes(length);
const result = [];
for (let i = 0; i < length; i++) {
const randomIndex = randomBytes[i] % charset.length;
result.push(charset[randomIndex]);
}
return result.join('');
}
console.log(generatePassword(16));
// الناتج: "X7$mK#9pL2@vR5tQ"
// أبجدي رقمي فقط
console.log(generatePassword(12, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'));
// الناتج: "K7xPzQ2mR8vN"
متى تستخدم: توليد كلمات المرور، رموز بتنسيق مخصص
المزايا:
- تحكم كامل في مجموعة الأحرف
- عشوائية آمنة
- مرن لأي حالة استخدام
4. UUID v4 (معرف فريد عالمياً)#
المتصفحات الحديثة وNode.js تدعم هذا محلياً الآن:
import crypto from 'crypto';
// طريقة crypto محلية (Node.js 14.17+)
const id = crypto.randomUUID();
console.log(id);
// الناتج: "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"
متى تستخدم: مفاتيح أساسية لقاعدة البيانات، معرفات فريدة
المزايا:
- تنسيق قياسي (RFC 4122)
- فريد عالمياً
- دعم محلي (لا حاجة لحزم)
العيوب:
- تنسيق ثابت (36 حرف مع شرطات)
- غير قابل للتخصيص
طرق المتصفح (جانب العميل)#
1. سلسلة عشوائية آمنة مشفرة#
باستخدام Web Crypto API (متوفر في جميع المتصفحات الحديثة):
function generateSecureToken(length = 32) {
const array = new Uint8Array(length / 2);
crypto.getRandomValues(array);
return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');
}
console.log(generateSecureToken(32));
// الناتج: "7a3f9e2d8c1b6a4f7e0d9c2b5a8f3e1c"
متى تستخدم: رموز جانب العميل، معرفات جلسات مؤقتة
المزايا:
- تعمل في جميع المتصفحات الحديثة
- آمنة مشفرة
- لا تبعيات
2. مجموعة أحرف مخصصة (المتصفح)#
function generateRandomString(length, charset) {
const array = new Uint8Array(length);
crypto.getRandomValues(array);
return Array.from(array, byte => charset[byte % charset.length]).join('');
}
// الاستخدام
const alphanumeric = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
console.log(generateRandomString(16, alphanumeric));
// الناتج: "K7xPzQ2mR8vNtL3w"
3. UUID في المتصفح#
// طريقة محلية (Chrome 92+، Firefox 95+، Safari 15.4+)
const id = crypto.randomUUID();
console.log(id);
// الناتج: "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"
// Polyfill للمتصفحات القديمة
function generateUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
const r = (crypto.getRandomValues(new Uint8Array(1))[0] & 0x0f) | (c === 'x' ? 0 : 0x08);
return r.toString(16);
});
}
4. معرفات سريعة غير آمنة (عناصر DOM، مفاتيح React)#
عندما لا يهم الأمان:
// بسيط وسريع
function generateId() {
return Date.now().toString(36) + Math.random().toString(36).substring(2);
}
console.log(generateId());
// الناتج: "ld3x7q9m5k2p8"
// أبسط لمفاتيح React
const key = `item-${Date.now()}-${Math.random()}`;
⚠️ تحذير: لا تستخدم أبداً Math.random() للتطبيقات الحساسة أمنياً!
طرق عالمية (تعمل في كل مكان)#
استخدام Nano ID (موصى به لمعظم الحالات)#
npm install nanoid
import { nanoid } from 'nanoid';
// افتراضي: 21 حرف، آمن للروابط
console.log(nanoid());
// الناتج: "V1StGXR8_Z5jdHi6B-myT"
// طول مخصص
console.log(nanoid(10));
// الناتج: "IRFa-VaY2b"
// أبجدية مخصصة
import { customAlphabet } from 'nanoid';
const nanoid = customAlphabet('0123456789abcdef', 16);
console.log(nanoid());
// الناتج: "4f90d13a42"
لماذا Nano ID رائع:
- ✅ أصغر 60% من UUID
- ✅ أسرع 2x من UUID
- ✅ يعمل في المتصفح وNode.js
- ✅ آمن للروابط افتراضياً
- ✅ آمن مشفرة
- ✅ قابل للتخصيص
أمثلة واقعية#
مولد كلمات المرور#
import crypto from 'crypto';
class PasswordGenerator {
static generate(options = {}) {
const {
length = 16,
numbers = true,
symbols = true,
lowercase = true,
uppercase = true,
excludeSimilar = true // استثناء i, l, 1, L, o, 0, O
} = options;
let charset = '';
if (lowercase) charset += 'abcdefghijkmnpqrstuvwxyz';
if (uppercase) charset += 'ABCDEFGHJKLMNPQRSTUVWXYZ';
if (numbers) charset += excludeSimilar ? '23456789' : '0123456789';
if (symbols) charset += '!@#$%^&*()-_=+[]{}|;:,.<>?';
if (charset.length === 0) {
throw new Error('يجب تحديد نوع حرف واحد على الأقل');
}
const password = [];
const randomBytes = crypto.randomBytes(length);
for (let i = 0; i < length; i++) {
password.push(charset[randomBytes[i] % charset.length]);
}
return password.join('');
}
}
// الاستخدام
console.log(PasswordGenerator.generate({ length: 20, symbols: true }));
// الناتج: "K7$mP#9L2@vR5tQ$X3nF"
مولد رموز API#
import crypto from 'crypto';
class TokenGenerator {
static generateApiKey(prefix = 'sk') {
const token = crypto.randomBytes(32).toString('base64url');
return `${prefix}_${token}`;
}
static generateSessionId() {
return crypto.randomBytes(32).toString('hex');
}
static generateResetToken() {
// قصير الأمد، تنتهي صلاحيته بعد الاستخدام
return crypto.randomBytes(32).toString('hex');
}
}
// الاستخدام
console.log(TokenGenerator.generateApiKey('pk'));
// الناتج: "pk_K7xP-zQ2mR8vN5tL3wY6jF9cH4dS1aE0K7xPzQ2m"
console.log(TokenGenerator.generateSessionId());
// الناتج: "a7f5c3e9d2b1a4f6c8e0d9b2a5f7c3e1a7f5c3e9d2b1a4f6c8e0d9b2a5f7c3e1"
مولد روابط قصيرة#
import { customAlphabet } from 'nanoid';
// استخدم فقط أحرف آمنة للروابط، استثنِ المربكة
const generateShortId = customAlphabet(
'abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789',
8
);
function createShortUrl(longUrl) {
const shortId = generateShortId();
const shortUrl = `https://myapp.com/${shortId}`;
// احفظ في قاعدة البيانات: { shortId, longUrl }
return shortUrl;
}
console.log(createShortUrl('https://example.com/very/long/url'));
// الناتج: "https://myapp.com/K7xPzQ2m"
أسماء ملفات فريدة للرفع#
import crypto from 'crypto';
import path from 'path';
function generateUniqueFilename(originalFilename) {
const timestamp = Date.now();
const randomString = crypto.randomBytes(8).toString('hex');
const extension = path.extname(originalFilename);
const nameWithoutExt = path.basename(originalFilename, extension);
// التنسيق: originalname_timestamp_random.ext
return `${nameWithoutExt}_${timestamp}_${randomString}${extension}`;
}
console.log(generateUniqueFilename('photo.jpg'));
// الناتج: "photo_1704931200000_a7f5c3e9d2b1.jpg"
مقارنة الأداء#
إليك معيار للطرق المختلفة (100,000 تكرار):
import crypto from 'crypto';
import { nanoid } from 'nanoid';
function benchmark(fn, iterations = 100000) {
const start = performance.now();
for (let i = 0; i < iterations; i++) {
fn();
}
const end = performance.now();
return `${(end - start).toFixed(2)}ms`;
}
console.log('crypto.randomUUID():', benchmark(() => crypto.randomUUID()));
// الناتج: ~45ms (أسرع!)
console.log('crypto.randomBytes(16).toString("hex"):', benchmark(() =>
crypto.randomBytes(16).toString('hex')
));
// الناتج: ~60ms
console.log('nanoid():', benchmark(() => nanoid()));
// الناتج: ~75ms
console.log('Math.random() (غير آمن!):', benchmark(() =>
Math.random().toString(36).substring(2, 15)
));
// الناتج: ~25ms (أسرع لكن غير آمن!)
أفضل ممارسات الأمان#
✅ افعل:#
// استخدم طرق آمنة مشفرة للرموز
const token = crypto.randomBytes(32).toString('hex');
// استخدم طول كافي (32 حرف كحد أدنى للرموز)
const sessionId = nanoid(32);
// استخدم base64url للرموز الآمنة للروابط
const resetToken = crypto.randomBytes(32).toString('base64url');
❌ لا تفعل:#
// لا تستخدم Math.random() للأمان
const insecureToken = Math.random().toString(36); // ⚠️ أبداً!
// لا تستخدم أطوال قصيرة للرموز الأمنية
const weakToken = crypto.randomBytes(4).toString('hex'); // ⚠️ قصير جداً!
// لا تستخدم Date.now() وحده للفرادة
const notUnique = Date.now().toString(); // ⚠️ تصادمات ممكنة!
أي طريقة يجب أن تستخدمها؟#
لرموز API / معرفات الجلسات:#
// Node.js
crypto.randomBytes(32).toString('hex')
// المتصفح
crypto.getRandomValues(new Uint8Array(32))
لمعرفات قاعدة البيانات / روابط قصيرة:#
// عالمي (Node.js + المتصفح)
import { nanoid } from 'nanoid';
nanoid(10); // سريع، قصير، آمن
للـ UUID (المفاتيح الأساسية):#
// Node.js حديث (14.17+) / المتصفح (Chrome 92+)
crypto.randomUUID()
لكلمات المرور:#
// مجموعة أحرف مخصصة مع crypto
const charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()';
crypto.randomBytes(16).map(byte => charset[byte % charset.length]).join('');
لغير الأمني (مفاتيح React، معرفات مؤقتة):#
// سريع وبسيط
`${Date.now()}-${Math.random().toString(36)}`
الخاتمة#
توليد السلاسل النصية العشوائية في JavaScript أمر مباشر عندما تفهم المقايضات:
- للأمان: استخدم دائماً
crypto(Node.js) أوcrypto.getRandomValues()(المتصفح) - للراحة: استخدم
nanoid- سريع، آمن، ويعمل في كل مكان - للمعايير: استخدم
crypto.randomUUID()لمعرفات قاعدة البيانات - للسرعة (غير أمني):
Math.random()مناسب لمفاتيح React والمعرفات المؤقتة
لا تستخدم أبداً Math.random() لكلمات المرور، الرموز المميزة، أو أي تطبيق حساس أمنياً!
نظام JavaScript الحديث يمنحك أدوات قوية لتوليد السلاسل النصية العشوائية. اختر الأداة المناسبة لحالة الاستخدام الخاصة بك، ودائماً أولوية الأمان عندما يهم الأمر.
