الانتقال إلى المحتوى الرئيسي

Documentation Index

Fetch the complete documentation index at: https://docs.oneclickdz.com/llms.txt

Use this file to discover all available pages before exploring further.

أمان مفاتيح API

التخزين

لا تُضمِّن مفاتيح API في نظام التحكم بالإصدار أو تعرِّضها في كود جانب العميل أبداً.
// ❌ Bad: Hardcoded in source code
const API_KEY = "sk_live_abc123";

// ✅ Good: Use environment variables
const API_KEY = process.env.FLEXY_API_KEY;

متغيرات البيئة

# .env file
FLEXY_API_KEY=sk_live_your_key_here
FLEXY_SANDBOX_KEY=sk_test_your_sandbox_key
API_BASE_URL=https://api.oneclickdz.com
// Load environment variables
require("dotenv").config();

const apiKey = process.env.FLEXY_API_KEY;

تدوير المفاتيح

// Support multiple keys for zero-downtime rotation
const API_KEYS = {
  primary: process.env.FLEXY_API_KEY_PRIMARY,
  secondary: process.env.FLEXY_API_KEY_SECONDARY,
};

async function callApiWithRotation(endpoint, data) {
  try {
    return await callApi(endpoint, data, API_KEYS.primary);
  } catch (error) {
    if (error.status === 401) {
      // Try secondary key
      return await callApi(endpoint, data, API_KEYS.secondary);
    }
    throw error;
  }
}

فرض HTTPS

// Always use HTTPS
const API_BASE_URL = "https://api.oneclickdz.com";

// Reject self-signed certificates in production
const axios = require("axios");
const https = require("https");

const client = axios.create({
  baseURL: API_BASE_URL,
  httpsAgent: new https.Agent({
    rejectUnauthorized: process.env.NODE_ENV === "production",
  }),
});

التحقق من صحة الطلبات

// Validate all inputs before sending to API
const Joi = require("joi");

const mobileTopupSchema = Joi.object({
  plan_code: Joi.string().required(),
  MSSIDN: Joi.string()
    .pattern(/^0[567][0-9]{8}$/)
    .required(),
  amount: Joi.number()
    .min(50)
    .max(5000)
    .when("plan_code", {
      is: Joi.string().pattern(/^DYN/),
      then: Joi.required(),
      otherwise: Joi.forbidden(),
    }),
  reference: Joi.string().max(100).required(),
});

function validateTopupRequest(data) {
  const { error, value } = mobileTopupSchema.validate(data);
  if (error) {
    throw new Error(`Validation error: ${error.message}`);
  }
  return value;
}

التعامل مع البيانات الحساسة

لا تسجِّل البيانات الحساسة

// ❌ Bad: Logs API key
console.log("Request:", {
  headers: { "X-Access-Token": apiKey },
  body: data,
});

// ✅ Good: Redact sensitive info
function sanitizeLog(data) {
  const sanitized = { ...data };
  if (sanitized.headers?.["X-Access-Token"]) {
    sanitized.headers["X-Access-Token"] = "***REDACTED***";
  }
  return sanitized;
}

console.log("Request:", sanitizeLog(request));

حماية أرقام الهاتف

// Mask phone numbers in logs/UI
function maskPhone(phone) {
  if (phone.length !== 10) return phone;
  return phone.slice(0, 4) + "****" + phone.slice(-2);
}

console.log("Top-up sent to:", maskPhone("0551234567")); // 0551****67

تأمين أكواد البطاقات

// Never log full card codes
function maskCardCode(code) {
  if (code.length <= 4) return "****";
  return "****" + code.slice(-4);
}

// Store securely
await db.orders.create({
  data: {
    userId: user.id,
    cardCode: encrypt(cardCode), // Encrypt sensitive data
    cardCodeMasked: maskCardCode(cardCode),
  },
});

تحديد معدل الطلبات

// Implement client-side rate limiting
const rateLimit = require("express-rate-limit");

const apiLimiter = rateLimit({
  windowMs: 60 * 1000, // 1 minute
  max: 60, // Max 60 requests per minute
  message: "Too many requests, please try again later",
});

app.use("/api/topup", apiLimiter, topupHandler);

القائمة البيضاء لعناوين IP

تواصل مع الدعم لإضافة عناوين IP الخاصة بخادمك إلى القائمة البيضاء لأمان إضافي.
// Make requests from whitelisted IPs only
const WHITELISTED_IPS = ["192.168.1.100", "10.0.0.50"];

function isWhitelisted(ip) {
  return WHITELISTED_IPS.includes(ip);
}

app.use((req, res, next) => {
  const clientIp = req.ip;
  if (!isWhitelisted(clientIp)) {
    return res.status(403).json({ error: "Forbidden" });
  }
  next();
});

تسجيل المراجعة

// Log all API interactions for audit
async function auditLog(event, data) {
  await db.auditLogs.create({
    data: {
      timestamp: new Date(),
      event,
      userId: data.userId,
      action: data.action,
      ipAddress: data.ip,
      userAgent: data.userAgent,
      requestId: data.requestId,
      success: data.success,
      // Don't log sensitive data
      metadata: sanitize(data.metadata),
    },
  });
}

// Usage
await auditLog("topup_sent", {
  userId: user.id,
  action: "SEND_MOBILE_TOPUP",
  ip: req.ip,
  userAgent: req.get("user-agent"),
  requestId: response.requestId,
  success: true,
});

رسائل الخطأ

// Don't expose internal details in error messages
function getSafeErrorMessage(error) {
  // Internal errors
  if (error.status >= 500) {
    return {
      message: "An error occurred. Please try again later.",
      code: "INTERNAL_ERROR",
      requestId: error.requestId, // Include for support
    };
  }

  // Client errors - be specific but safe
  return {
    message: error.message,
    code: error.code,
  };
}

الإعداد الآمن

// Separate configs for sandbox/production
const config = {
  sandbox: {
    apiKey: process.env.FLEXY_SANDBOX_KEY,
    baseUrl: "https://api.oneclickdz.com",
    testMode: true,
    logLevel: "debug",
  },
  production: {
    apiKey: process.env.FLEXY_API_KEY,
    baseUrl: "https://api.oneclickdz.com",
    testMode: false,
    logLevel: "error",
  },
};

const env = process.env.NODE_ENV || "sandbox";
const currentConfig = config[env];

أمان التبعيات

# Regularly audit dependencies
npm audit

# Update vulnerable packages
npm audit fix

# Use tools like Snyk
npm install -g snyk
snyk test

التشفير في وقت الراحة

// Encrypt sensitive data before storing
const crypto = require("crypto");

const ENCRYPTION_KEY = process.env.ENCRYPTION_KEY; // 32-byte key
const IV_LENGTH = 16;

function encrypt(text) {
  const iv = crypto.randomBytes(IV_LENGTH);
  const cipher = crypto.createCipheriv(
    "aes-256-cbc",
    Buffer.from(ENCRYPTION_KEY),
    iv
  );
  let encrypted = cipher.update(text);
  encrypted = Buffer.concat([encrypted, cipher.final()]);
  return iv.toString("hex") + ":" + encrypted.toString("hex");
}

function decrypt(text) {
  const parts = text.split(":");
  const iv = Buffer.from(parts.shift(), "hex");
  const encrypted = Buffer.from(parts.join(":"), "hex");
  const decipher = crypto.createDecipheriv(
    "aes-256-cbc",
    Buffer.from(ENCRYPTION_KEY),
    iv
  );
  let decrypted = decipher.update(encrypted);
  decrypted = Buffer.concat([decrypted, decipher.final()]);
  return decrypted.toString();
}

// Usage
const cardCode = "1234-5678-9012";
const encrypted = encrypt(cardCode);
await db.orders.create({ data: { cardCode: encrypted } });

قائمة التحقق الأمني

1

مفاتيح API

✓ مخزّنة في متغيرات البيئة ✓ غير ملتزم بها في نظام إدارة الإصدارات ✓ يتم تدويرها دورياً
2

HTTPS

✓ جميع الطلبات تستخدم HTTPS ✓ التحقق من الشهادة مفعّل
3

التحقق من المدخلات

✓ جميع المدخلات يتم التحقق منها قبل استدعاءات API ✓ التحقق بالمخطط مطبّق
4

التسجيل

✓ البيانات الحساسة غير مسجّلة ✓ سجلات المراجعة مفعّلة ✓ معرّفات الطلبات مُتتبَّعة
5

تحديد معدل الطلبات

✓ تحديد من جانب العميل ✓ منطق إعادة المحاولة مع التراجع التدريجي
6

حماية البيانات

✓ البيانات الحساسة مشفّرة في وقت الراحة ✓ أرقام الهاتف مُخفاة في السجلات ✓ أكواد البطاقات محمية

ملخص أفضل الممارسات

لا تكشف المفاتيح أبداً

استخدم متغيرات البيئة

استخدم HTTPS دائماً

أمّن جميع الاتصالات

تحقق من كل شيء

افحص المدخلات قبل الإرسال

شفّر البيانات الحساسة

احمِ البيانات في وقت الراحة

ذات صلة

المصادقة

إعداد مفاتيح API

معالجة الأخطاء

التعامل مع الأخطاء بأمان