الأمان والأداء

التسجيل ومراقبة الأمان

16 دقيقة الدرس 14 من 35

فهم تسجيل ومراقبة الأمان

لا يمكنك حماية ما لا يمكنك رؤيته. يتيح لك تسجيل ومراقبة الأمان اكتشاف الهجمات والتحقيق في الحوادث وإثبات الامتثال والاستجابة للتهديدات في الوقت الفعلي. بدون تسجيل شامل، أنت تطير أعمى.

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

ماذا نسجل للأمان

سجل الأحداث ذات الصلة بالأمان التي تساعد على اكتشاف الحوادث الأمنية والتحقيق فيها والاستجابة لها:

// تسجيل أحداث الأمان في Node.js مع Winston
const winston = require('winston');
const path = require('path');

// إنشاء مسجل الأمان
const securityLogger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
defaultMeta: { service: 'security-service' },
transports: [
// ملف منفصل لأحداث الأمان
new winston.transports.File({
filename: 'logs/security.log',
maxsize: 10485760, // 10MB
maxFiles: 10
}),
// تنبيهات حرجة إلى ملف منفصل
new winston.transports.File({
filename: 'logs/security-alerts.log',
level: 'error',
maxsize: 10485760,
maxFiles: 5
})
]
});

// تسجيل أحداث المصادقة
function logAuthEvent(eventType, userId, ip, success, details = {}) {
securityLogger.info({
event: 'authentication',
type: eventType, // login, logout, password_reset, etc.
userId: userId,
ip: ip,
success: success,
userAgent: details.userAgent,
timestamp: new Date().toISOString(),
...details
});
}

// تسجيل فشل التفويض
function logAuthzFailure(userId, resource, action, ip) {
securityLogger.warn({
event: 'authorization_failure',
userId: userId,
resource: resource,
action: action,
ip: ip,
timestamp: new Date().toISOString()
});
}

// تسجيل النشاط المشبوه
function logSuspiciousActivity(type, details) {
securityLogger.error({
event: 'suspicious_activity',
type: type, // brute_force, sql_injection, xss, etc.
details: details,
timestamp: new Date().toISOString()
});
}
تحذير الخصوصية: لا تسجل أبداً البيانات الحساسة: كلمات المرور، بطاقات الائتمان، أرقام الضمان الاجتماعي، رموز الجلسة الكاملة. سجل فقط ما هو ضروري للتحقيق الأمني. التزم بقواعد الاحتفاظ بالبيانات GDPR و CCPA.

أحداث الأمان للمراقبة

// مراقبة شاملة لأحداث الأمان

// 1. أحداث المصادقة
- تسجيلات دخول ناجحة (مع الطابع الزمني، IP، وكيل المستخدم)
- محاولات تسجيل دخول فاشلة (تتبع المحاولات الفاشلة لكل IP/مستخدم)
- قفل الحساب
- تغييرات كلمة المرور
- طلبات إعادة تعيين كلمة المرور
- أحداث MFA (نجاح/فشل)

// 2. أحداث التفويض
- أحداث رفض الوصول (403)
- محاولات تصعيد الامتيازات
- تغييرات الدور/الأذونات
- الوصول إلى الموارد الحساسة

// 3. أحداث الوصول للبيانات
- صادرات البيانات الجماعية
- الوصول إلى PII/البيانات الحساسة
- أنماط استعلام قاعدة البيانات (استعلامات غير عادية)
- الوصول إلى الملفات (خاصة الملفات الحساسة)

// 4. تغييرات التكوين
- إنشاء/حذف المستخدم
- تعديلات الدور/الأذونات
- تغييرات تكوين النظام
- تغييرات إعدادات الأمان

// 5. أخطاء التطبيق
- استثناءات غير متوقعة
- فشل التحقق من صحة الإدخال
- انتهاكات حد معدل API
- فشل رمز CSRF

// 6. أحداث الشبكة
- أنماط حركة غير عادية
- شذوذ جغرافي
- عناوين IP متعددة لكل مستخدم
- محاولات فحص المنافذ

التسجيل المنظم لتحليل الأمان

// استخدم التسجيل المنظم لتحليل أسهل
const { createLogger, format, transports } = require('winston');
const { combine, timestamp, json, errors } = format;

const logger = createLogger({
format: combine(
errors({ stack: true }),
timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
json()
),
defaultMeta: {
service: 'my-app',
environment: process.env.NODE_ENV
},
transports: [
new transports.File({ filename: 'logs/app.log' })
]
});

// مثال: تسجيل فشل تسجيل الدخول مع السياق
logger.warn({
event_type: 'authentication_failure',
event_category: 'security',
user_id: req.body.email,
ip_address: req.ip,
user_agent: req.headers['user-agent'],
request_id: req.id,
failure_reason: 'invalid_password',
attempt_number: 3,
geo_location: await getGeoLocation(req.ip),
timestamp: new Date().toISOString()
});
أفضل ممارسة: استخدم التسجيل المنظم (JSON) بدلاً من النص العادي. السجلات المنظمة أسهل في التحليل والبحث والتحليل باستخدام أدوات آلية مثل ELK Stack أو Splunk أو Datadog.

ارتباط السجل والسياق

// أضف معرفات الارتباط لتتبع الطلبات عبر الخدمات
const { v4: uuidv4 } = require('uuid');

// وسيطة لإضافة معرف الطلب
app.use((req, res, next) => {
req.id = uuidv4();
res.setHeader('X-Request-ID', req.id);
next();
});

// قم بتضمين معرف الطلب في جميع السجلات
logger.info({
request_id: req.id,
event: 'user_login',
user_id: user.id,
ip: req.ip
});

// لاحقاً، في خدمة/خدمة صغيرة أخرى
logger.info({
request_id: req.headers['x-request-id'],
event: 'data_access',
resource: 'user_profile',
user_id: user.id
});

// الآن يمكنك تتبع تدفق الطلب بالكامل:
// تسجيل الدخول → الوصول إلى الملف الشخصي → تصدير البيانات

التنبيه الأمني في الوقت الفعلي

// التنبيه على الأنماط المشبوهة
const nodemailer = require('nodemailer');
const redis = require('redis');
const client = redis.createClient();

// تتبع محاولات تسجيل الدخول الفاشلة
async function trackFailedLogin(email, ip) {
const key = `failed_login:${email}:${ip}`;
const attempts = await client.incr(key);
await client.expire(key, 3600); // نافذة ساعة واحدة

// التنبيه بعد 5 محاولات فاشلة
if (attempts === 5) {
await sendSecurityAlert({
type: 'brute_force_attempt',
email: email,
ip: ip,
attempts: attempts,
severity: 'high'
});
}

// الحظر بعد 10 محاولات
if (attempts >= 10) {
await blockIP(ip, 3600);
await sendSecurityAlert({
type: 'ip_blocked',
ip: ip,
reason: 'brute_force',
severity: 'critical'
});
}
}

// إرسال تنبيهات الأمان
async function sendSecurityAlert(alertData) {
const transporter = nodemailer.createTransporter({
host: process.env.SMTP_HOST,
port: 587,
secure: false,
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS
}
});

await transporter.sendMail({
from: 'security@example.com',
to: 'security-team@example.com',
subject: `[${alertData.severity.toUpperCase()}] تنبيه أمني: ${alertData.type}`,
text: JSON.stringify(alertData, null, 2)
});

// التسجيل أيضاً في مسجل الأمان
securityLogger.error({
event: 'security_alert',
...alertData
});
}

اكتشاف الشذوذ

// اكتشاف سلوك المستخدم غير العادي
class AnomalyDetector {
async detectLoginAnomaly(userId, ip, userAgent) {
// احصل على أنماط تسجيل الدخول النموذجية للمستخدم
const recentLogins = await getUserRecentLogins(userId, 30);

const anomalies = [];

// التحقق من الشذوذ الجغرافي
const currentGeo = await getGeoLocation(ip);
const usualCountries = recentLogins.map(l => l.country);
if (!usualCountries.includes(currentGeo.country)) {
anomalies.push({
type: 'geographic_anomaly',
message: `تسجيل دخول من بلد غير عادي: ${currentGeo.country}`
});
}

// التحقق من السفر المستحيل
const lastLogin = recentLogins[0];
if (lastLogin) {
const timeDiff = Date.now() - lastLogin.timestamp;
const distance = calculateDistance(lastLogin.geo, currentGeo);
const speedKmH = distance / (timeDiff / 3600000);

if (speedKmH > 900) { // أسرع من الطائرة
anomalies.push({
type: 'impossible_travel',
message: `تسجيل دخول من ${distance} كم في ${timeDiff/60000} دقيقة`
});
}
}

// التحقق من الوقت غير العادي
const hour = new Date().getHours();
const usualHours = recentLogins.map(l => new Date(l.timestamp).getHours());
const avgHour = usualHours.reduce((a, b) => a + b, 0) / usualHours.length;
if (Math.abs(hour - avgHour) > 6) {
anomalies.push({
type: 'unusual_time',
message: `تسجيل دخول في ساعة غير عادية: ${hour}:00`
});
}

return anomalies;
}
}
التعلم الآلي: يستخدم اكتشاف الشذوذ المتقدم نماذج ML مدربة على السلوك الطبيعي. يمكن للمكتبات مثل TensorFlow.js أو خدمات السحابة (AWS GuardDuty، Azure Sentinel) اكتشاف أنماط دقيقة لا يلاحظها البشر.

أفضل ممارسات مسار التدقيق

// تنفيذ مسار تدقيق مقاوم للعبث
const crypto = require('crypto');

class AuditLog {
constructor() {
this.logs = [];
this.lastHash = '0';
}

addEntry(event, userId, details) {
const entry = {
timestamp: Date.now(),
event: event,
userId: userId,
details: details,
previousHash: this.lastHash
};

// إنشاء تجزئة لهذا الإدخال
const entryString = JSON.stringify(entry);
entry.hash = crypto
.createHash('sha256')
.update(entryString)
.digest('hex');

this.logs.push(entry);
this.lastHash = entry.hash;

// الاستمرار في التخزين غير القابل للتغيير
this.persistEntry(entry);
}

verifyIntegrity() {
let previousHash = '0';

for (let entry of this.logs) {
if (entry.previousHash !== previousHash) {
return { valid: false, tamperedEntry: entry };
}

const entryWithoutHash = { ...entry };
delete entryWithoutHash.hash;
const computedHash = crypto
.createHash('sha256')
.update(JSON.stringify(entryWithoutHash))
.digest('hex');

if (computedHash !== entry.hash) {
return { valid: false, tamperedEntry: entry };
}

previousHash = entry.hash;
}

return { valid: true };
}
}

الاحتفاظ بالسجل والإدارة

# تدوير السجل مع logrotate (Linux)
sudo nano /etc/logrotate.d/myapp

# إضافة التكوين:
/var/log/myapp/*.log {
daily # تدوير يومي
rotate 90 # احتفظ بـ 90 يوماً
compress # ضغط السجلات القديمة
delaycompress # الضغط بعد يوم واحد
notifempty # لا تدور إذا كان فارغاً
create 0640 www-data www-data
sharedscripts
postrotate
systemctl reload myapp
endscript
}

# سجلات الأمان - الاحتفاظ الأطول
/var/log/myapp/security.log {
weekly
rotate 52 # احتفظ بسنة واحدة
compress
notifempty
create 0600 root root # أذونات أكثر صرامة
}
تمرين: نفذ تسجيل أمان شامل:
  1. أنشئ مسجل أمان مع Winston أو ما شابه
  2. سجل جميع أحداث المصادقة والتفويض
  3. نفذ ارتباط الطلب مع معرفات فريدة
  4. أنشئ تنبيهات في الوقت الفعلي لمحاولات القوة الغاشمة
  5. قم ببناء اكتشاف الشذوذ للأنماط الجغرافية/الزمنية
  6. نفذ مسار تدقيق مقاوم للعبث مع التجزئة
  7. قم بتكوين تدوير السجل مع الاحتفاظ لمدة 90 يوماً