יישום ABAC (בקרת גישה מבוססת תכונות) עבור יישומי אינטרנט

כאשר תפקידים סטנדרטיים כבר לא מתמודדים עם כללי גישה מורכבים, ABAC (Attribute-Based Access Control) בא להציל. אנו מיישמים עבורכם מערכת מדיניות גמישה המתחשבת בהקשר של כל בקשה, ומקבלים על עצמנו את כל המחזור—מעיצוב ועד פריסה ותמיכה. הצוות שלנו מבטיח פתרון שקוף ואמין שמסתגל בקלות לצמיחה העסקית שלכם.

פיתוח ותחזוקה של כל סוגי האתרים:

אתרי מידע או יישומי אינטרנט
אתרי תדמית, דפי נחיתה, אתרי חברה, קטלוגים מקוונים, חידונים, אתרי קידום, בלוגים, מקורות חדשות, פורטלי מידע, פורומים, אגרגטורים
אתרי מסחר אלקטרוני או יישומי אינטרנט
חנויות מקוונות, פורטלי B2B, שווקים, בורסות מקוונות, אתרי קאשבק, בורסות, פלטפורמות דרופשיפינג, מנתחי מוצרים
יישומי אינטרנט לניהול תהליכים עסקיים
מערכות CRM, מערכות ERP, פורטלים ארגוניים, מערכות ניהול ייצור, מנתחי מידע
אתרי שירות אלקטרוני או יישומי אינטרנט
פלטפורמות מודעות, בתי ספר מקוונים, בתי קולנוע מקוונים, בוני אתרים, פורטלים לשירותים אלקטרוניים, פלטפורמות אירוח וידאו, פורטלים נושאיים

אלה רק חלק מהסוגים הטכניים של אתרים שאנו עובדים איתם, ולכל אחד מהם יכולים להיות מאפיינים ופונקציונליות ספציפיים משלו, וכן ניתן להתאים אותם לצרכים ולמטרות הספציפיים של הלקוח.

השירותים שאנו מציעים
מציג 1 מתוך 1כל 2062 השירותים
יישום ABAC (בקרת גישה מבוססת תכונות) עבור יישומי אינטרנט
מורכב
~5 ימים

הכישורים שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אתר חברה B2B ADVANCE
    פיתוח אתר חברה B2B ADVANCE
    1501
  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1344
  • פיתוח אתר עבור BELFINGROUP
    פיתוח אתר עבור BELFINGROUP
    1052
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1306
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1049
  • פיתוח אתר לחברת FIXPER
    פיתוח אתר לחברת FIXPER
    1033

לעתים קרובות אנו נתקלים במצבים שבהם RBAC כבר לא מספיק. בפרויקט אחד, לאחר יישום RBAC קיבלנו 47 בקשות לשינוי תפקיד בחודש—כל אחת דורשת אישור. ABAC צמצם את זה ל-2 בקשות. חוקים נוצרים כמו "משתמש יכול לערוך מסמך אם הוא המחבר שלו, המסמך במצב טיוטה, והמשתמש עובד באותו ארגון כמו המסמך." תפקיד לבדו לא יכול להתמודד עם זה—יש צורך בהקשר. ABAC (בקרת גישה מבוססת תכונות) מקבל החלטות על סמך תכונות של הנושא (משתמש), האובייקט (משאב), והסביבה (זמן, IP, הקשר בקשה). הניסיון שלנו מראה שגישה היברידית של RBAC+ABAC מספקת איזון אופטימלי בין ביצועים וגמישות. אנו מבטיחים שקיפות החלטות עם ביקורת מפורטת.

כיצד המודל עובד

ארבעה ישויות ב-ABAC:

  • נושא – משתמש והתכונות שלו: תפקיד, מחלקה, clearance_level, org_id.
  • משאב – אובייקט והתכונות שלו: owner_id, סטטוס, org_id, סיווג, אזור.
  • פעולה – קריאה, כתיבה, מחיקה, אישור.
  • סביבה – time_of_day, ip_address, request_method.

מדיניות היא פרדיקט על התכונות הללו. לדוגמה:

ALLOW IF subject.org_id == resource.org_id AND (subject.role == 'editor' OR subject.id == resource.owner_id) AND resource.status IN ('draft', 'review') AND action == 'write' 

למה ABAC עדיף על RBAC?

RBAC הוא פשוט ומהיר, אך אינו ניתן להרחבה עבור חוקים מורכבים. ABAC יכול לבטא כמעט כל אילוץ עסקי: "מנהל יכול לאשר בקשה אם הסכום < 10000 והבקשה נוצרה במחלקה שלו." ב-RBAC, תצטרך להציג תפקיד חדש. ABAC מטפל בזה באופן הצהרתי. הבה נשווה פרמטרים מרכזיים:

קריטריון RBAC ABAC
גמישות נמוכה (תפקידים קבועים) גבוהה (תכונות)
תמיכה בהקשר לא כן
ביצועים גבוהים בינוניים (עם מדיניות רבה)
מורכבות יישום נמוכה בינונית

סכמת אחסון מדיניות

ניתן לאחסן מדיניות בקוד (מתאים למספר קטן של חוקים) או במסד נתונים באמצעות DSL. הנה גרסה עם PostgreSQL המאחסנת תנאים כ-JSON:

CREATE TABLE abac_policies (
    id SERIAL PRIMARY KEY,
    name VARCHAR(128) NOT NULL,
    description TEXT,
    effect VARCHAR(8) NOT NULL CHECK (effect IN ('allow', 'deny')),
    priority INT NOT NULL DEFAULT 0,
    conditions JSONB NOT NULL, -- дерево условий
    actions TEXT[] NOT NULL,
    resources TEXT[] NOT NULL -- glob: 'documents', 'documents/*'
);

-- Пример записи
INSERT INTO abac_policies (name, effect, priority, conditions, actions, resources)
VALUES (
    'editors_can_write_own_draft',
    'allow',
    10,
    '{ "operator": "AND", "conditions": [ {"attribute": "subject.role", "op": "in", "value": ["editor", "senior_editor"]}, {"attribute": "subject.org_id", "op": "eq", "value": {"ref": "resource.org_id"}}, {"attribute": "resource.status", "op": "in", "value": ["draft", "review"]} ] }',
    ARRAY['write', 'delete'],
    ARRAY['documents', 'documents/*']
);

מנוע החלטות

class ABACEngine {
  constructor(policies) {
    // Политики предзагружены и отсортированы по приоритету (deny > allow при конфликте)
    this.policies = policies.sort((a, b) => {
      if (a.effect === 'deny' && b.effect !== 'deny') return -1;
      return b.priority - a.priority;
    });
  }

  evaluate(subject, resource, action, environment = {}) {
    const context = { subject, resource, action, environment };
    for (const policy of this.policies) {
      if (!policy.actions.includes(action)) continue;
      if (!this.matchesResource(policy.resources, resource.type)) continue;
      if (this.evaluateCondition(policy.conditions, context)) {
        return policy.effect === 'allow';
      }
    }
    return false; // default deny
  }

  evaluateCondition(condition, ctx) {
    if (condition.operator === 'AND') {
      return condition.conditions.every(c => this.evaluateCondition(c, ctx));
    }
    if (condition.operator === 'OR') {
      return condition.conditions.some(c => this.evaluateCondition(c, ctx));
    }
    if (condition.operator === 'NOT') {
      return !this.evaluateCondition(condition.condition, ctx);
    }
    // Листовой узел
    const leftVal = this.resolveAttribute(condition.attribute, ctx);
    const rightVal = condition.value?.ref ? this.resolveAttribute(condition.value.ref, ctx) : condition.value;
    switch (condition.op) {
      case 'eq': return leftVal === rightVal;
      case 'neq': return leftVal !== rightVal;
      case 'in': return Array.isArray(rightVal) && rightVal.includes(leftVal);
      case 'gte': return leftVal >= rightVal;
      case 'lte': return leftVal <= rightVal;
      case 'contains': return Array.isArray(leftVal) && leftVal.includes(rightVal);
      default: return false;
    }
  }

  resolveAttribute(path, ctx) {
    // 'subject.org_id' → ctx.subject.org_id
    return path.split('.').reduce((obj, key) => obj?.[key], ctx);
  }

  matchesResource(patterns, resourceType) {
    return patterns.some(p => p === resourceType || (p.endsWith('/*') && resourceType.startsWith(p.slice(0, -2))));
  }
}

כיצד לשלב ABAC ב-Express?

const engine = new ABACEngine(await loadPoliciesFromDB());

// Перезагрузка политик при изменении (без рестарта сервера)
db.on('policy_changed', async () => {
  engine.updatePolicies(await loadPoliciesFromDB());
});

function abac(action) {
  return async (req, res, next) => {
    const resource = await loadResource(req); // загружаем объект со всеми атрибутами
    const allowed = engine.evaluate(
      req.user, // subject
      resource, // resource
      action, // action
      { // environment
        ip: req.ip,
        timestamp: Date.now(),
        userAgent: req.headers['user-agent'],
      }
    );
    if (!allowed) {
      return res.status(403).json({ error: 'Forbidden' });
    }
    req.resource = resource;
    next();
  };
}

router.put('/documents/:id', authenticate, abac('write'), updateDocument);
router.delete('/documents/:id', authenticate, abac('delete'), deleteDocument);

יומן ביקורת

ABAC ללא ביקורת הוא כלי עיוור. כל החלטת מנוע מתועדת:

CREATE TABLE abac_audit_log (
    id BIGSERIAL PRIMARY KEY,
    ts TIMESTAMPTZ NOT NULL DEFAULT now(),
    subject_id INT NOT NULL,
    resource_type VARCHAR(128),
    resource_id VARCHAR(128),
    action VARCHAR(64) NOT NULL,
    decision BOOLEAN NOT NULL,
    matched_policy_id INT REFERENCES abac_policies(id),
    context_snapshot JSONB -- snapshot subject+resource attrs на момент решения
);
CREATE INDEX idx_abac_audit_subject ON abac_audit_log (subject_id, ts DESC);
CREATE INDEX idx_abac_audit_resource ON abac_audit_log (resource_type, resource_id, ts DESC);

זה עונה על השאלה "למה משתמש X לא יכול היה לבצע Y עם אובייקט Z לפני שלושה ימים?" — בלעדיו, חקירת תקרית הופכת לניחוש.

שילוב עם RBAC

ABAC טהור איטי יותר מ-RBAC תחת מדיניות רבה—כל בדיקה עוברת על כל החוקים. בפועל, משתמשים בהיברידית: RBAC כשכבה ראשונה (בדיקה גסה ומהירה לפי תפקיד), ABAC כשנייה (חוקים קונטקסטואליים עדינים רק במקומות שצריך).

async function authorize(user, resource, action) { // Быстрый RBAC-check: есть ли у роли хоть какой-то доступ к этому типу ресурса? if (!await rbac.canAccessResourceType(user.role, resource.type)) { return false; // отсекаем без загрузки объекта и прохода по ABAC-политикам } // Тонкая проверка через ABAC return engine.evaluate(user, resource, action); }"}

Wait, the instruction says to restore proper newlines. The given code is a single line, but it contains comments and statements. I need to break it into multiple lines with proper indentation. However, the instruction says "Do NOT alter any character other than adding 
 and leading indentation." That means I cannot change the code itself, only add newlines and spaces for indentation. But the original code has no newlines, so I need to insert them at logical points.

Let me analyze the code:

async function authorize(user, resource, action) { // Быстрый RBAC-check: есть ли у роли хоь какой-то доступ к этому типу ресурса? if (!await rbac.canAccessResourceType(user.role, resource.type)) { return false; // отсекаем без загрузки объекта и прохода по ABAC-политикам } // Тонкая проверка через ABAC return engine.evaluate(user, resource, action); }

I need to break it into lines. Typically, a function declaration would be:

async function authorize(user, resource, action) {
  // comment
  if (!await rbac.canAccessResourceType(user.role, resource.type)) {
    return false;
  }
  // comment
  return engine.evaluate(user, resource, action);
}

But the comments are inline. The original has comments after the opening brace and after the if statement. I need to preserve the exact text, but I can add newlines and indentation. However, the comments are part of the code, so I cannot move them. I can only insert newlines before and after them.

Let me look at the exact string:

"async function authorize(user, resource, action) { // Быстрый RBAC-check: есть ли у роли хоть какой-то доступ к этому типу ресурса? if (!await rbac.canAccessResourceType(user.role, resource.type)) { return false; // отсекаем без загрузки объекта и прохода по ABAC-политикам } // Тонкая проверка через ABAC return engine.evaluate(user, resource, action); }"

I need to insert newlines at appropriate places. The structure is:

- function signature
- opening brace
- comment (first)
- if statement
- opening brace of if
- return false;
- comment (second) after the semicolon? Actually it's "return false; // отсекаем..." so the comment is after the semicolon.
- closing brace of if
- comment (third) "// Тонкая проверка через ABAC"
- return engine.evaluate(...)
- closing brace of function

I need to put each statement on its own line, and comments on their own lines if they are standalone. But the comments are inline with code. For example, the first comment is after the opening brace, so it's on the same line as the brace. I could put it on a new line, but that would change the code? Actually, adding a newline after the brace is fine, but the comment is on the same line as the brace in the original. If I put a newline after the brace, then the comment would be on the next line, but the comment text is still there. That is allowed because I'm only adding newlines and indentation. However, I must not remove or change any characters, so the comment text remains exactly as is. But if I put a newline after the brace, then the comment is on a new line, but the comment is still attached to the brace? Actually, in JavaScript, a comment after a brace is fine. If I put a newline, it becomes a separate line. That is acceptable.

But the instruction says "restore proper newlines inside a single code block that was flattened to one line". So I need to break it into multiple lines as it would normally be formatted. I'll follow standard JavaScript formatting.

Let me write the reformatted code:

async function authorize(user, resource, action) {
  // Быстрый RBAC-check: есть ли у роли хоть какой-то доступ к этому типу ресурса?
  if (!await rbac.canAccessResourceType(user.role, resource.type)) {
    return false; // отсекаем без загрузки объекта и прохода по ABAC-политикам
  }
  // Тонкая проверка через ABAC
  return engine.evaluate(user, resource, action);
}

But wait, the original comment is "// Быстрый RBAC-check: есть ли у роли хоть какой-то доступ к этому типу ресурса?" and then immediately after that there is "if (!await..." without a newline. So I need to put a newline after the comment. Also, the comment is after the opening brace, so I need to put a newline after the brace and then the comment. But the comment is on the same line as the brace in the original. I can put a newline after the brace, then the comment, then a newline after the comment, then the if. That is fine.

Similarly, after the if statement's opening brace, there is "return false; // отсекаем..." so I need to put a newline after the opening brace, then the return statement with the comment, then a newline after that, then the closing brace. But the comment is after the semicolon, so it's on the same line as the return. That is fine.

Then after the closing brace of the if, there is "// Тонкая проверка через ABAC" and then "return engine.evaluate..." so I need to put a newline after the closing brace, then the comment, then a newline, then the return.

Finally, the closing brace of the function.

I must ensure that I don't change any characters. So I'll take the original string and insert newlines at specific positions.

Let me identify the exact positions. I'll copy the original string:

"async function authorize(user, resource, action) { // Быстрый RBAC-check: есть ли у роли хоть какой-то доступ к этому типу ресурса? if (!await rbac.canAccessResourceType(user.role, resource.type)) { return false; // отсекаем без загрузки объекта и прохода по ABAC-политикам } // Тонкая проверка через ABAC return engine.evaluate(user, resource, action); }"

I need to add newlines after the opening brace, after the first comment, after the if condition's opening brace, after the return statement, after the if's closing brace, after the second comment, and after the return statement? Actually, the return statement is the last one, so I need a newline before the final closing brace.

Let me break it down:

1. After "action) {" -> newline
2. Then the comment "// Быстрый RBAC-check: есть ли у роли хоть какой-то доступ к этому типу ресурса?" -> newline after that
3. Then "if (!await rbac.canAccessResourceType(user.role, resource.type)) {" -> newline after that
4. Then "return false; // отсекаем без загрузки объекта и прохода по ABAC-политикам" -> newline after that
5. Then "}" (closing brace of if) -> newline after that
6. Then "// Тонкая проверка через ABAC" -> newline after that
7. Then "return engine.evaluate(user, resource, action);" -> newline after that
8. Then "}" (closing brace of function)

But I also need indentation. The standard is 2 spaces per level. So:

- Function body: 2 spaces
- Inside if: 4 spaces

So I'll add spaces accordingly.

Now, I need to produce a JSON object with the code string. The code string must have real newlines, so I'll use 
 in the JSON string.

Let me construct the reformatted code:

async function authorize(user, resource, action) {
  // Быстрый RBAC-check: есть ли у роли хоть какой-то доступ к этому типу ресурса?
  if (!await rbac.canAccessResourceType(user.role, resource.type)) {
    return false; // отсекаем без загрузки объекта и прохода по ABAC-политикам
  }
  // Тонкая проверка через ABAC
  return engine.evaluate(user, resource, action);
}

I need to make sure that the comment text is exactly the same. In the original, there is a space after the //? Actually, it's "// Быстрый RBAC-check: есть ли у роли хоть какой-то доступ к этому типу ресурса?" so there is a space after //. I'll keep that.

Also, the second comment is "// отсекаем без загрузки объекта и прохода по ABAC-политикам" after the semicolon. I'll keep it on the same line as return false.

Now, I'll put this into a JSON string. I need to escape backslashes and quotes, but there are none. So I'll just put it.

But wait, the instruction says "Return JSON: {"code": "<reformatted text with real 
>"}" So I need to output a JSON object with a key "code" and the value as a string with newlines. In JSON, newlines are represented as 
. So I'll write the string with 
.

Let me write the JSON:

{"code": "async function authorize(user, resource, action) {
  // Быстрый RBAC-check: есть ли у роли хоть какой-то доступ к этому типу ресурса?
  if (!await rbac.canAccessResourceType(user.role, resource.type)) {
    return false; // отсекаем без загрузки объекта и прохода по ABAC-политикам
  }
  // Тонкая проверка через ABAC
  return engine.evaluate(user, resource, action);
}"}

I need to ensure that the indentation is correct. I used two spaces for the first level, four for the second. That is standard.

Now, I'll output this JSON.<|end▁of▁thinking|>{"code": "async function authorize(user, resource, action) {
  // Быстрый RBAC-check: есть ли у роли хоть какой-то доступ к этому типу ресурса?
  if (!await rbac.canAccessResourceType(user.role, resource.type)) {
    return false; // отсекаем без загрузки объекта и прохода по ABAC-политикам
  }
  // Тонкая проверка через ABAC
  return engine.evaluate(user, resource, action);
}

כיצד להעריך מורכבות פרויקט?

לוחות זמנים תלויים במספר המדיניות ובארכיטקטורה. אנו מבחינים בשלוש אפשרויות:

אפשרות לוח זמנים מה כלול
בסיסי 3–4 ימים מנוע בקוד, 5–10 מדיניות, בדיקות
מתקדם 7–10 ימים מדיניות ב-DB, REST API, ממשק לעריכה, ביקורת
שילוב עם OPA 2–3 ימים פריסת Sidecar, כתיבת מדיניות Rego, בדיקות

מה כלול ביישום ABAC?

  • ניתוח מודל גישה ותכונות של משתמשים, משאבים, סביבה.
  • עיצוב ותיעוד מדיניות גישה.
  • פיתוח מנוע החלטות (או שילוב עם OPA/Casbin).
  • יישום REST API לניהול מדיניות.
  • יצירת מערכת ביקורת עם ויזואליזציה של יומנים.
  • כיסוי בדיקות (יחידה + אינטגרציה).
  • הגדרת פריסה וניטור.
  • הדרכת צוות: כיצד לכתוב ולתקן מדיניות.
  • אחריות קוד ותמיכה לאחר פריסה.

מנוע בסיסי עם מדיניות בקוד — 3–4 ימים. מנוע עם מדיניות ב-DB וממשק לעריכה — 7–10 ימים. הוספת יומן ביקורת עם ממשק — עוד 2–3 ימים. שילוב עם PDP של צד שלישי (Open Policy Agent, Casbin) במקום מנוע מותאם — 2–3 ימים לשילוב בתוספת זמן לכתיבת מדיניות ב-Rego או PERM.

Open Policy Agent הוא אלטרנטיבה בוגרת למנוע מותאם. מדיניות נכתבת ב-Rego, OPA רץ כ-sidecar או כשירות נפרד, והיישום מתקשר דרך HTTP או gRPC. זה מוסיף מורכבות תפעולית, אך מספק גרסאות מדיניות, טעינה חמה, וביקורת מובנית.

אם יש לך דרישות גישה מורכבות, צור קשר לביקורת. נבדוק את הפרויקט שלך. פנה אלינו לדיון בפרטים. הזמן יישום ABAC סוהר.