الـ Audit والـ Privacy Logs: سجّل مين عمل إيه، من غير ما تسجّل الأسرار
API بيسجّل كل حاجة للـ debugging، فالـ logs بقى فيها الباسوردات وأرقام الكروت والـ tokens والـ cookies والإيميلات، وحد يقدر يحقن سطر مزيّف، ومحدش يعرف مين غيّر الـ roles. بنفهم الفرق بين الـ application log والـ audit log، و structured logging، و redaction للأسرار والـ PII، و log injection، و pseudonymization، و tamper-evident audit بـ hash chain، والاحتفاظ والـ retention. والتحدي: logger و audit قصاد سبعة وعشرين حالة.
نص شرح المعلم والكود الذي كتبه ونتيجة تشغيله، بنفس ترتيب الدرس.
أهلًا بيك. الـ logs حاجة كل الناس بتعملها، وقليل اللي بيعملها صح. المبرمج بيقول خليني أسجّل كل حاجة علشان لو حصلت مشكلة ألاقيها. وبعد كام شهر، يبقى عندك gigabytes من الـ logs فيها باسوردات العملاء وأرقام كروتهم و session cookies، وأي حد عنده access للـ logs، أو أي اختراق للـ log system، بقى معاه كل ده. وفيه حاجة تانية مختلفة خالص: الـ audit log. مش للـ debugging، ده سجل رسمي بـ مين عمل إيه: مين دخل، مين غيّر role حد لـ admin، مين وصل لـ data حساسة. ده اللي بيتسأل عنه في أي تحقيق أو compliance. server dot js بيعمل الغلطة الكلاسيكية: middleware بيسجّل كل request بالـ headers والـ body. attack dot js مش بيعمل أي هجوم، بيبعت requests عادية: login، ودفع، و login تاني بـ email غريب، وتغيير role. وبعدين بيقرا app dot log ويدوّر على الأسرار. نشغّل.
// attack.js: requests عادية جدًا، وبعدين نشوف الـ logs فيها إيه
import { readFileSync, existsSync } from "node:fs";
const post = (path, body, headers = {}) =>
fetch("http://localhost:3000" + path, {
method: "POST",
headers: { "content-type": "application/json", ...headers },
body: JSON.stringify(body),
});
await post("/login", { email: "[email protected]", password: "my-real-password-123" });
await post("/pay?token=tok_live_51Hx9", { card: "4242424242424242", cvv: "123", phone: "+201001234567" },
{ authorization: "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1MSJ9.sig_lab", cookie: "sid=s3cr3t-session" });
// log injection: email فيه newline وسطر مزيّف
await post("/login", { email: "x\n2026-01-01T00:00:00.000Z admin login ok for [email protected]", password: "x" });
await post("/admin/users/u42/role", { role: "admin" }, { authorization: "Bearer admin_lab_token" });
const app = existsSync("app.log") ? readFileSync("app.log", "utf8") : "";
const leaks = ["my-real-password-123", "4242424242424242", "\"cvv\":\"123\"", "sid=s3cr3t-session", "Bearer eyJ", "tok_live_51Hx9",
"[email protected]", "+201001234567"];
console.log(`app.log: ${app.split("\n").filter(Boolean).length} سطر`);
for (const s of leaks) console.log(app.includes(s) ? "☠ متسجّل:" : "✔ مش موجود:", s);
console.log(/\nadmin login ok|\n\S+ admin login ok/.test(app) ? "☠ فيه سطر مزيّف: admin login ok for ceo" : "✔ مفيش سطور مزيّفة");
const audit = existsSync("audit.log") ? readFileSync("audit.log", "utf8").trim() : "";
console.log(audit ? `✔ audit.log فيه ${audit.split("\n").length} سطر` : "☠ مفيش audit: مين خلّى u42 admin؟ محدش يعرف");if (audit) console.log("✔ آخر سطر في الـ audit:", JSON.parse(audit.split("\n").at(-1)).action, "← target", JSON.parse(audit.split("\n").at(-1)).target);المخرجات
$ rm -f app.log audit.log; node server.js & S=$!; sleep 1; node attack.js; kill $S API: http://localhost:3000 app.log: 7 سطر ☠ متسجّل: my-real-password-123 ☠ متسجّل: 4242424242424242 ☠ متسجّل: "cvv":"123" ☠ متسجّل: sid=s3cr3t-session ☠ متسجّل: Bearer eyJ ☠ متسجّل: tok_live_51Hx9 ☠ متسجّل: [email protected] ☠ متسجّل: +201001234567 ☠ فيه سطر مزيّف: admin login ok for ceo ☠ مفيش audit: مين خلّى u42 admin؟ محدش يعرف
كله متسجّل: الباسورد الحقيقي، ورقم الـ card كامل، والـ cvv، والـ session cookie، والـ Bearer token، والـ token اللي في الـ URL، والإيميلات، والموبايل. وأسوأ حاجة: سطر الـ login التاني. المهاجم حط newline في الـ email، وبعد الـ newline سطر شكله زي سطر log حقيقي بيقول admin login ok for ceo. ده اسمه log injection: لو حد بيقرا الـ logs بعينه أو بأداة، ممكن يتخض من سطر مش حصل أصلًا، أو يخبّي سطر حقيقي. وآخر حاجة: مين غيّر الـ user لـ admin؟ مفيش audit خالص. محدش يعرف.
نبدأ بالـ application log. أول حاجة: structured، يعني JSON سطر لكل event، مش نص حر. ده بيخلّي الـ newline يتحوّل لـ backslash n جُوّه الـ string، فمفيش حد يقدر يحقن سطر. وكمان بتقدر تعمل search و filter عليه. تاني: redaction. list بأسماء الـ fields الحساسة، وأي واحد فيهم القيمة بتتشال، مهما كان جايلك إزاي. وكمان scrub على الـ strings نفسها، علشان لو حد حط token جُوّه رسالة أو URL. تالت: ما تسجّلش الـ body والـ headers الخام أصلًا. سجّل اللي محتاجه بس: الـ method، والـ path، والـ status، والـ وقت، و request id تربط بيه كل سطور الـ request الواحد. رابع: الـ PII، يعني الـ data الشخصية زي الإيميل. بدل ما تسجّله، سجّل pseudonym: HMAC للـ id، فنفس الـ user بياخد نفس الرمز في كل السطور، وتقدر تتبّع سلوكه، من غير ما الإيميل نفسه يتسجّل.
والـ audit log حكاية تانية. كل سطر لازم فيه: مين، يعني الـ actor، عمل إيه، يعني الـ action، على مين أو إيه، يعني الـ target، والنتيجة، والوقت. وأهم حاجة فيه إنه tamper evident: لو حد عدّل أو مسح سطر، لازم يبان. إزاي؟ كل سطر بيحسب hash من محتواه زائد الـ hash بتاع السطر اللي قبله. فبيبقى زي سلسلة: تغيّر أي سطر، الـ hash بتاعه يتغيّر، فالسطر اللي بعده الـ prev بتاعه ما يطابقش، والسلسلة تتكسر عند أول تعديل بالضبط. ده نفس فكرة الـ blockchain، بس من غير أي تعقيد. في الإنتاج ممكن توقّع الـ hashes، أو تبعتها لـ system تاني write once، أو service زي CloudTrail. وحاجة مهمة قانونيًا: الـ retention. مش كل حاجة تتساب للأبد. الـ GDPR بيقول ما تخلّيش الـ PII عندك أكتر من اللازم. فالـ app logs عادة أيام لأسابيع، والـ audit logs أطول بكتير لأسباب قانونية، بس بالـ pseudonyms مش الـ data الخام.
server dot js الجديد بيستخدم logger dot js: access log منضّف بـ request id، و login بيسجّل userRef مش الإيميل، و payment بيعمل redact للـ body كله، وتغيير الـ role بيتكتب في الـ audit. التحدي: اكتب logger dot js: scrub و redact و userRef و createLogger و createAudit. test dot js فيه سبعة وعشرين حالة، منهم تعديل ومسح في الـ audit لازم verify يكشفهم.
logger.js: scrub (Bearer و query tokens و كروت و emails و موبايل، والتواريخ سليمة)، و redact (keys حساسة بأي case، nested، من غير ما يغيّر الأصلي)، و userRef بـ HMAC، و createLogger JSON، و createAudit بـ hash chain و verify بيكشف أي تعديل.
الحل. scrub بـ كام replace، كل واحد لنوع: الـ Bearer، والـ query، والكروت، والإيميل، والموبايل. والترتيب مهم شوية. redact بتلف على الـ object، وبتعمل نسخة جديدة علشان ما تلمسش الأصلي، وبتحمي نفسها من العمق والـ circular. userRef بـ HMAC، فمحدش يقدر يرجع من الرمز للإيميل. والـ audit: كل سطر بياخد الـ prev، ويحسب hash، فالـ verify بيمشي على السلسلة ويقف عند أول كسر. خد بالك إني بعمل destructure للـ hash لوحده قبل ما أعيد حساب الـ sha، علشان أحسبه على نفس الحاجة اللي اتحسبت عليها الأول. نشغّل attack dot js تاني.
// logger.js: logs منضّفة من الأسرار والـ data الشخصية، و audit log ما يتعدّلش من غير ما نعرف
import { appendFileSync, readFileSync, existsSync } from "node:fs";
import { createHash, createHmac } from "node:crypto";
// أسماء الـ keys اللي قيمتها ما تتسجّلش أبدًا (من غير حساسية للحروف الكبيرة، و - و _)
const SECRET_KEYS = new Set(["password", "passwd", "secret", "token", "accesstoken", "refreshtoken", "authorization",
"cookie", "setcookie", "apikey", "xapikey", "card", "cardnumber", "cvv", "cvc", "otp", "pin"]);
const norm = (k) => k.toLowerCase().replace(/[-_]/g, "");
// قيم شكلها حساس جُوّه أي string
export function scrub(s) {
return s
.replace(/Bearer\s+[A-Za-z0-9._~+/=-]+/g, "Bearer [REDACTED]")
.replace(/([?&](?:token|key|secret|password|code)=)[^&#\s]*/gi, "$1[REDACTED]")
.replace(/\b\d{13,19}\b/g, (d) => "****" + d.slice(-4))
.replace(/([A-Za-z0-9._%+-])[A-Za-z0-9._%+-]*@([A-Za-z0-9.-]+\.[A-Za-z]{2,})/g, "$1***@$2")
.replace(/\+\d[\d\s-]{7,}\d|\b01\d{9}\b/g, (p) => "***" + p.replace(/\D/g, "").slice(-2)); // +20... أو 01xxxxxxxxx
}
export function redact(value, depth = 0, seen = new WeakSet()) {
if (typeof value === "string") return scrub(value);
if (value === null || typeof value !== "object") return value;
if (depth > 6) return "[DEPTH]";
if (seen.has(value)) return "[CIRCULAR]";
seen.add(value);
if (Array.isArray(value)) return value.map((v) => redact(v, depth + 1, seen));
const out = {};
for (const [k, v] of Object.entries(value))
out[k] = SECRET_KEYS.has(norm(k)) ? "[REDACTED]" : redact(v, depth + 1, seen);
return out;
}
// نفس الـ user ← نفس الـ ref، بس من غير الـ email نفسه. الـ key في الإنتاج من الـ secret manager
export const userRef = (id, key = "lab-pseudonym-key") =>
"u_" + createHmac("sha256", key).update(String(id).toLowerCase()).digest("hex").slice(0, 16);
// سطر JSON واحد لكل حدث في الـ app: الـ newlines بتبقى \n جُوّه الـ string، فمفيش log injection
export function createLogger(file) {
return (level, msg, fields = {}) =>
appendFileSync(file, JSON.stringify({ time: new Date().toISOString(), level, msg: scrub(String(msg)), ...redact(fields) }) + "\n");
}
// audit log: append-only، وكل سطر فيه hash السطر اللي قبله، فأي تعديل أو مسح بيبان
const sha = (s) => createHash("sha256").update(s).digest("hex");
const GENESIS = "0".repeat(64);
export function createAudit(file) {
const lines = () => (existsSync(file) ? readFileSync(file, "utf8").split("\n").filter(Boolean) : []);
let last = lines().at(-1);
let prev = last ? JSON.parse(last).hash : GENESIS;
return {
record({ actor, action, target, result, ...extra }) {
for (const [k, v] of Object.entries({ actor, action, target, result }))
if (typeof v !== "string" || !v) throw new Error(`audit: ${k} لازم string`);
const entry = { time: new Date().toISOString(), actor, action, target, result, ...redact(extra), prev };
entry.hash = sha(JSON.stringify(entry));
appendFileSync(file, JSON.s
…المخرجات
$ rm -f app.log audit.log; node server.js & S=$!; sleep 1; node attack.js; kill $S API: http://localhost:3000 app.log: 6 سطر ✔ مش موجود: my-real-password-123 ✔ مش موجود: 4242424242424242 ✔ مش موجود: "cvv":"123" ✔ مش موجود: sid=s3cr3t-session ✔ مش موجود: Bearer eyJ ✔ مش موجود: tok_live_51Hx9 ✔ مش موجود: [email protected] ✔ مش موجود: +201001234567 ✔ مفيش سطور مزيّفة ✔ audit.log فيه 3 سطر ✔ آخر سطر في الـ audit: user.role.change ← target u42
كله اتنضّف: مفيش باسورد ولا card ولا cookie ولا token ولا إيميل. ومفيش سطور مزيّفة، لأن الـ newline بقى جُوّه string. والـ audit فيه مين غيّر الـ role. ونشغّل test dot js.
المخرجات
$ rm -f app.log audit.log; node server.js & S=$!; sleep 1; node test.js; kill $S API: http://localhost:3000 ✅ Bearer token ← REDACTED ✅ ?token= في الـ URL ← REDACTED وباقي الـ query زي ما هو ✅ &password= و ?code= ✅ رقم كارت ← آخر أربعة ✅ email ← أول حرف و الـ domain ✅ موبايل دولي ← آخر رقمين ✅ موبايل مصري 01 ✅ التاريخ والـ UUID ما يتلمسوش ✅ رقم عادي قصير ما يتلمسش ✅ keys حساسة بأي case أو - أو _ ← REDACTED ✅ nested و arrays ✅ الأرقام زي ما هي، والـ strings بتتعمل scrub ✅ circular ما يعملش crash ✅ redact ما بيغيّرش الـ object الأصلي ✅ userRef ثابت لنفس الـ user ومن غير case ✅ userRef مختلف لـ users مختلفين، وما فيهوش الـ email ✅ سطر واحد بس حتى لو فيه newline (مفيش log injection) ✅ الـ log JSON فيه time و level و msg ✅ الـ fields متنضّفة ✅ record بيرجّع entry فيه prev و hash ✅ الـ extra بيتعمل له redact ✅ verify على log سليم ← ok و count تلاتة ✅ record من غير actor ← throw ✅ audit جديد على نفس الـ file بيكمّل الـ chain ✅ تعديل سطر ← verify بيقول سطر واحد ✅ مسح سطر من النص ← verify بيقول سطر اتنين ✅ سطر زبالة ← ok false من غير throw 27/27 نجحوا
كله نجح، بما فيه إن verify كشف لما عدّلنا سطر، ولما مسحنا سطر من النص. في الإنتاج: pino أو مكتبة شبهها بتعمل الـ structured logging والـ redaction بسرعة، وبتبعت الـ logs لـ system زي Loki أو Elasticsearch أو Datadog، والـ audit لـ store منفصل. بس المبادئ واحدة: نضّف قبل ما تكتب، مش بعد. الدرس الجاي، AppSec testing و OWASP ASVS. إزاي تحط الأمن في الـ CI نفسه، و SAST و DAST و dependency scanning، و ASVS كـ checklist تمشي عليها.
// server.js: نفس الـ API، بس بـ logger منضّف و audit لكل حاجة مهمة
import express from "express";
import { randomUUID } from "node:crypto";
import { createLogger, createAudit, userRef } from "./logger.js";
const app = express();
app.use(express.json());
const log = createLogger("app.log");
const audit = createAudit("audit.log");
app.use((req, res, next) => {
req.id = randomUUID();
const t = Date.now();
// الـ access log: مفيش body ومفيش headers، بس اللي محتاجينه للـ debugging
res.on("finish", () => log("info", "request", { id: req.id, method: req.method, url: req.originalUrl, status: res.statusCode, ms: Date.now() - t }));
next();
});
app.post("/login", (req, res) => {
const { email, password } = req.body;
const ok = password === "correct horse";
// في الـ app.log: userRef مش الـ email. وفي الـ audit: الـ actor هو الـ ref برضه
log(ok ? "info" : "warn", "login", { id: req.id, user: userRef(email), ok });
audit.record({ actor: userRef(email), action: "auth.login", target: "self", result: ok ? "success" : "failure", ip: req.ip, requestId: req.id });
if (!ok) return res.status(401).json({ error: "غلط" });
res.json({ token: "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1MSJ9.sig_lab" });
});
app.post("/pay", (req, res) => {
log("info", "payment", { id: req.id, ...req.body }); // حتى لو حد بعت الـ body كله، redact بيضبطه
res.json({ ok: true, last4: String(req.body.card).slice(-4) });
});
app.post("/admin/users/:id/role", (req, res) => {
const actor = "admin_1"; // في الحقيقة من الـ session
audit.record({ actor, action: "user.role.change", target: req.params.id, result: "success", to: req.body.role, ip: req.ip, requestId: req.id });
res.json({ id: req.params.id, role: req.body.role });
});
app.listen(3000, () => console.log("API: http://localhost:3000"));import { readFileSync, writeFileSync, rmSync } from "node:fs";
import { scrub, redact, userRef, createLogger, createAudit } from "./logger.js";
let ok = 0, all = 0;
const check = (name, cond, extra = "") => { all++; if (cond) ok++; console.log(cond ? "✅" : "❌", name, extra); };
check("Bearer token ← REDACTED", scrub("auth Bearer eyJhbGc.x.y ok") === "auth Bearer [REDACTED] ok");
check("?token= في الـ URL ← REDACTED وباقي الـ query زي ما هو", scrub("/pay?token=tok_1&amount=5") === "/pay?token=[REDACTED]&amount=5");
check("&password= و ?code=", scrub("/cb?code=abc&x=1&password=p") === "/cb?code=[REDACTED]&x=1&password=[REDACTED]");
check("رقم كارت ← آخر أربعة", scrub("card 4242424242424242 done") === "card ****4242 done");
check("email ← أول حرف و الـ domain", scrub("hi [email protected]") === "hi m***@baassma.tech");
check("موبايل دولي ← آخر رقمين", scrub("call +20 100 123 4567") === "call ***67");
check("موبايل مصري 01", scrub("01001234567") === "***67");
const iso = "2026-01-01T10:00:00Z 3f2b9c1e-1111-4a2b-9c3d-123456789abc";
check("التاريخ والـ UUID ما يتلمسوش", scrub(iso) === iso);
check("رقم عادي قصير ما يتلمسش", scrub("amount 15000 ms 12") === "amount 15000 ms 12");
const r = redact({ password: "p", Password: "p", api_key: "k", "X-Api-Key": "k", nested: { Authorization: "Bearer x", list: [{ cvv: "1" }] }, amount: 5, note: "mail [email protected]" });
check("keys حساسة بأي case أو - أو _ ← REDACTED", r.password === "[REDACTED]" && r.Password === "[REDACTED]" && r.api_key === "[REDACTED]" && r["X-Api-Key"] === "[REDACTED]");
check("nested و arrays", r.nested.Authorization === "[REDACTED]" && r.nested.list[0].cvv === "[REDACTED]");
check("الأرقام زي ما هي، والـ strings بتتعمل scrub", r.amount === 5 && r.note === "mail a***@b.co");
const circ = { a: 1 }; circ.self = circ;
check("circular ما يعملش crash", (() => { try { return redact(circ).self === "[CIRCULAR]"; } catch { return false; } })());
const orig = { password: "p" }; redact(orig);
check("redact ما بيغيّرش الـ object الأصلي", orig.password === "p");
check("userRef ثابت لنفس الـ user ومن غير case", userRef("[email protected]") === userRef("[email protected]") && /^u_[0-9a-f]{16}$/.test(userRef("a")));
check("userRef مختلف لـ users مختلفين، وما فيهوش الـ email", userRef("[email protected]") !== userRef("[email protected]") && !userRef("[email protected]").includes("@"));
rmSync("t-app.log", { force: true });
const log = createLogger("t-app.log");
log("warn", "login failed for x\n2026 admin login ok", { email: "[email protected]", password: "pw" });
const lines = readFileSync("t-app.log", "utf8").trim().split("\n");
check("سطر واحد بس حتى لو فيه newline (مفيش log injection)", lines.length === 1);
const j = JSON.parse(lines[0]);
check("الـ log JSON فيه time و level و msg", !!j.time && j.level === "warn" && j.msg.includes("login failed"));
check("الـ fields متنضّفة", j.password === "[REDACTED]" && j.email === "z***@q.io");
rmSync("t-audit.log", { force: true });
const a = createAudit("t-audit.log");
const e1 = a.record({ actor: "admin_1", actio
…03 / دروس المسار (122)
- 01أهلًا بيك: يعني إيه backend، والكورس ده ماشي إزاي
- 02الملفات والفولدرات والـ terminal: تتحرك على جهازك زي المبرمجين
- 03Node وأول برنامج: تشغّل وتقرا رسالة الخطأ
- 04القيم والمتغيرات والأنواع: const و let و typeof
- 05القرارات والتكرار: if و === والـ truthy والـ loops
- 06الـ functions: parameters و return والـ arrow functions والـ scope
- 07الـ objects والـ arrays: destructuring و spread و map و filter و reduce
- 08JSON والنصوص والتواريخ: اللغة اللي الـ backend بيتكلم بيها
- 09الـ callbacks والـ closures وأول لمسة async: setTimeout
- 10الـ classes والـ errors: throw و try/catch و stack trace
- 11git: تحفَظ كل خطوة وترجعلها، وما تسرّبش أسرارك
- 12ESM و CommonJS و package exports: Node بيلاقي الـ modules إزاي
- 13الـ Promises و async/await: sequential و parallel والأخطاء والإلغاء
- 14الـ event loop والـ microtasks: Node بيعمل كل حاجة بـ thread واحد إزاي
- 15الـ Streams والـ Backpressure: ملفات أكبر من الـ memory
- 16الـ File System والـ paths: قراية وكتابة صح، ومن غير path traversal
- 17الـ Buffers والبيانات الـ binary: الـ bytes من جُوّه
- 18Crypto APIs والأسرار: random و hash و HMAC و AES-GCM
- 19الـ Worker Threads: شغل CPU تقيل من غير ما توقف الـ server
- 20الـ Errors على مستوى الـ process: operational و programmer و crash-only
- 21الـ Node test runner والـ debugging: tests من غير مكتبات
- 22HTTP من جُوّه: الـ methods والـ status codes والـ headers
- 23Express والـ Routing: الـ params والـ query والترتيب والـ Router
- 24Express 5: إيه اللي اتغيّر، وإزاي تنقل مشروع قديم
- 25الـ Middleware ودورة حياة الـ request جُوّه Express
- 26Validation للمدخلات بـ Zod: ما تصدّقش أي حاجة جاية من برة
- 27تصنيف الأخطاء و Problem Details: شكل واحد لكل الـ errors
- 28الـ CORS والـ Cookies: المتصفح بيحمي المستخدم إزاي
- 29رفع الملفات وحدود الحجم: multer من غير ثغرات
- 30الـ Realtime: Server-Sent Events و WebSockets
- 31OpenAPI والـ API Versioning: عقد مكتوب، وتغيير من غير ما تكسر حد
- 32PostgreSQL: الـ DDL وأنواع البيانات الصح لكل عمود
- 33الـ Constraints: PK و FK و UNIQUE و CHECK — الـ database بتحمي نفسها
- 34الـ Normalization والـ ERD: تقسّم البيانات صح من أول يوم
- 35الـ JOINs والتجميع: INNER و LEFT و GROUP BY و HAVING و window functions
- 36JSONB في PostgreSQL: إمتى تستخدمه، وإزاي تسأله وتعمله index
- 37الـ Indexes من جُوّه: B-tree و GIN و BRIN
- 38Partial و Covering indexes: indexes أصغر وأسرع
- 39الـ Pagination بالـ Keyset: ليه OFFSET بيبطّأ وبيكرر
- 40Full Text Search في Postgres: بحث بالكلمات، بالعربي والإنجليزي
- 41EXPLAIN ANALYZE والـ Planner: اقرا الـ plan وصلّح الـ query
- 42الـ Transactions بـ node-postgres: كله أو ولا حاجة
- 43الـ MVCC ومستويات الـ Isolation: transactions كتير في نفس الوقت
- 44الـ Locks والـ Deadlocks: مين مستني مين
- 45SKIP LOCKED و Job Leasing: Postgres كـ job queue
- 46Row Level Security والـ Multi-tenancy: كل عميل يشوف بياناته بس
- 47Migrations من غير downtime: expand و backfill و contract
- 48الـ Replication والـ Read Replicas: نسخ حية من الـ database
- 49الـ Connection Pooling و PgBouncer: connections أقل، requests أكتر
- 50الـ Partitioning والـ VACUUM والمراقبة: Postgres على المدى الطويل
- 51Redis وأنواع البيانات: strings و hashes و lists و sets و sorted sets
- 52Cache-aside والـ TTL: Redis قدام الـ database
- 53الـ Cache invalidation والـ Stampede: لما الـ key الشهير يموت
- 54Lua والـ Atomicity في Redis: كام أمر كأنهم أمر واحد
- 55الـ Rate Limiting في Redis: fixed window و sliding window و token bucket
- 56الـ Sessions في Redis: تسجيل دخول تقدر تلغيه في أي وقت
- 57Redis Streams والـ Consumer Groups: log بيتوزع على workers
- 58Pub/Sub و BullMQ: إشارات بين الـ instances، وطوابير شغل محترمة
- 59Redis لما يقع: الـ persistence (RDB و AOF) والـ replication
- 60Redis في الإنتاج: الـ ACLs والـ Cluster والمراقبة
- 61تخزين الـ Passwords بـ Argon2id: صح من أول مرة
- 62Session Fixation والـ Rotation: id جديد مع كل صلاحية جديدة
- 63الـ Cookie Flags والـ CSRF: المتصفح بيبعت الـ cookie، فلازم تتأكد مين اللي طلب
- 64الـ XSS والـ Content Security Policy: ما تخليش النص يتحوّل لـ code
- 65الـ OAuth و OpenID Connect و PKCE: login بـ Google من غير ما تشوف الـ password
- 66التأكد من الـ JWT صح: التوقيع والـ claims والـ scopes
- 67الـ BOLA و BFLA: الـ token السليم مش معناه إن الطلب مسموح
- 68الـ RBAC و ABAC والملكية: policy واحدة بدل ifs متفرقة
- 69الـ MFA والـ recovery: التاني factor اللي بجد
- 70الـ Passkeys و WebAuthn: login من غير password وضد الـ phishing
- 71الـ Threat Modeling بـ STRIDE: فكّر زي المهاجم قبل ما تكتب code
- 72الـ SQL Injection والـ Parameterization: الـ data ما تبقاش code
- 73الـ SSRF والـ Egress: ما تخليش الـ server بتاعك يزور الشبكة الداخلية
- 74الـ Security Headers والـ TLS: كل response يقول للـ browser يحمي المستخدم إزاي
- 75توقيع الـ Webhooks والـ Replay: الـ webhook ده جاي فعلًا من Stripe؟
- 76تغيير الأسرار والـ HMAC: إزاي تغيّر مفتاح من غير ما كل حاجة تقع
- 77سلسلة التوريد والـ SBOM: إنت واثق في ألف package ما تعرفهمش؟
- 78الـ Audit والـ Privacy Logs: سجّل مين عمل إيه، من غير ما تسجّل الأسرارانت هنا
- 79اختبار الأمان و OWASP ASVS: الأمن جُوّه الـ CI، مش audit آخر السنة
- 80الـ Prototype Pollution والـ Resource DoS: request واحد يخلّي الكل admin أو يوقّع الـ server
- 81الـ SLI والـ SLO والـ Error Budget: إمتى تصحّي الـ on-call وإمتى تسيبه نايم
- 82الـ Event Loop Delay والـ ELU: لما Node نفسه يتخنق
- 83الـ Worker Threads والـ CPU Profiling: الشغل التقيل بره الـ event loop، والوقت راح فين
- 84الـ Memory والـ GC والـ Leaks: الـ process اللي بيكبر لحد ما يقع
- 85الـ N+1 Queries والـ DataLoader: صفحة واحدة بمِيّتين query
- 86الـ HTTP Caching والـ Compression: أسرع request هو اللي ما بيوصلش
- 87الـ Load Testing والـ Soak Testing: الـ server بيستحمل قد إيه بجد
- 88الـ Concurrency Limits والـ Bulkheads: dependency بطيئة ما توقعش الـ app كله
- 89الـ Timeouts والـ Retries والـ Circuit Breakers: إزاي تتعامل مع dependency بطيئة أو واقعة
- 90OpenTelemetry والـ Distributed Tracing: الـ request راح فين وضاع وقته فين
- 91Docker Layers والـ Build Context: ليه الـ build بياخد دقيقة وفيه الـ .env بتاعك
- 92Multi-stage Builds و Non-root: image صغيرة ومن غير root
- 93Docker Compose والـ Networks: الـ services بتلاقي بعض إزاي
- 94Docker Volumes: الـ data بتتحفَظ فين
- 95Healthcheck و Restart و Resource Limits: running مش معناها شغّال
- 96BuildKit والـ Build Secrets: الـ token ما يدخلش الـ image
- 97Reverse Proxy و TLS: اللي واقف قدام الـ app
- 98Multi-arch Images والـ Native Modules: اشتغلت عندي
- 99CI/CD و Rollback و Canary: الـ deploy يبقى ممل
- 100Kubernetes من الأول: Pods و Deployments و Services و Probes
- 101Modular Monolith و DDD: حدود واضحة من غير network
- 102Transactional Outbox و Inbox: الـ event ما يضيعش وما يتنفذش مرتين
- 103Sagas: عملية واحدة على تلات services من غير transaction واحدة
- 104CQRS و Event Sourcing: الـ events هي الحقيقة
- 105الـ Queues والـ Brokers: BullMQ و RabbitMQ و Kafka و SQS
- 106Realtime على أكتر من instance: Redis pub/sub و presence و resume
- 107الـ Object Storage والـ Media: presigned URLs و uploads مباشرة
- 108التكامل مع الـ Email والـ Search: retries و webhooks و indexes
- 109GraphQL و gRPC في الإنتاج: contracts و DataLoader و limits و deadlines
- 110Kafka على أكتر من zone و region: الـ replication والـ ISR والـ acks والـ MirrorMaker والـ failover
- 111TypeScript و runtime boundaries: الـ types بتختفي، والـ schemas لأ
- 112ORM ولا SQL: query builders و repositories و migrations و transactions
- 113الـ Serverless من جُوّه: cold starts و freeze و timeouts و connections
- 114الـ Testing Pyramid: unit و integration و e2e على Postgres حقيقية
- 115Contract Testing و Property-Based Testing بـ fast-check
- 116الـ Payments: idempotency و webhooks و refunds و reconciliation
- 117الـ Timezones والـ Internationalization: UTC و DST والـ locales والـ plurals والفلوس
- 118الـ Privacy والـ Data Retention: consent و export و erasure و crypto shredding
- 119الـ ADRs والـ Feature Flags: القرارات المكتوبة والـ rollout من غير deploy
- 120Multi-region active-active: حل الـ conflicts بـ HLC و CRDTs
- 121Readiness و Liveness و Startup Probes: الـ pod جاهز ولا عايش؟
- 122Incident Runbooks: من الـ alert للـ postmortem