bitrix-security
CSRF, XSS, SQLi, SSRF, JWT/JWK, access rights, encryption. Use when handling input or auditing security.
Install
npx skills add https://github.com/bxmaximum/bitrix-framework-skills/tree/main/skills/bitrix-security
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install bxmaximum-bitrix-framework-skills@llmmart
git clone https://github.com/bxmaximum/bitrix-framework-skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole bxmaximum/bitrix-framework-skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Security in Bitrix
Baseline: main 23.0+. Features newer than baseline are marked Since.
Progressive disclosure: open only the rule files that match the task. Do not read every rules/*.md.
How to use
- Identify the layer the task touches.
- Open the matching
rules/*.mdbelow. - Prefer framework-native Bitrix patterns over custom abstractions.
Choose a rule file
When to read rules/csrf-xss.md
Read rules/csrf-xss.md (CSRF and XSS) when the task involves:
- CSRF
- XSS and HTML Sanitization
- CSRF Details
When to read rules/sql-ssrf.md
Read rules/sql-ssrf.md (SQL injection and SSRF) when the task involves:
- SSRF
- SQL Injections
When to read rules/jwt-crypto-access.md
Read rules/jwt-crypto-access.md (JWT, crypto, access, cookies) when the task involves:
- JWT / JWK
- Access Rights
#[ActionAccess]/AccessCheckControllerInterface- Secure Cookies
- Value Encryption
- Miscellaneous
- Checklist
Checklist
- Opened only the rule file(s) needed for this task.
- Followed DI /
/local// security canons fromAGENTS.md.
Files (bitrix-framework-skills)
-
rules
-
csrf-xss.md 1.8 KB
# CSRF and XSS ## CSRF ### Form/AJAX Protection - `Bitrix\Main\Engine\ActionFilter\Csrf` is in the default prefilters for controllers, but `listAllowedScopes()` limits it to **`Controller::SCOPE_AJAX` only**. It does **not** run for REST/`SCOPE_REST` (or other scopes) unless you add an equivalent check yourself. - In HTML forms: ```php <?= bitrix_sessid_post() ?> <!-- <input type="hidden" name="sessid" value="..."> --> ``` - In `fetch` / AJAX (`runAction`) requests: `X-Bitrix-Csrf-Token: <bitrix_sessid()>` header (or `sessid` in the body). - Manual check (if writing a handler directly): `if (!check_bitrix_sessid()) { die('Invalid sessid'); }`. ### When Sessions are Read-only If `CloseSession` is enabled (via filter), the CSRF token behaves as usual — the kernel reads it from the request rather than the session. ### Antipatterns - A `GET` endpoint that changes state without a CSRF token and checks. - Custom `sessid` field in a form without `bitrix_sessid_post()`. ## XSS and HTML Sanitization - Output everything via `htmlspecialcharsbx($value)`. - In templates — `<?= htmlspecialcharsbx($item['TITLE']) ?>`. - For HTML content from users, use `\Bitrix\Main\Text\HtmlFilter` or `CBXSanitizer`: ```php $sanitizer = new \CBXSanitizer(); $sanitizer->SetLevel(\CBXSanitizer::SECURE_LEVEL_HIGH); // or MEDIUM, LOW $safeHtml = $sanitizer->SanitizeHtml($userHtml); ``` - Pass JS data via `\Bitrix\Main\Web\Json::encode($data)` instead of direct concatenation. - `arResult` in a component template is not escaped by default — escape it yourself. ## CSRF Details - `bitrix_sessid_get()` / `bitrix_sessid()` — get token for JS/AJAX headers. - ActionFilter `Csrf` → only `SCOPE_AJAX`; REST and custom scopes need their own CSRF/auth strategy. - Cookie `SameSite` settings affect CSRF protection — configure in `crypto` / cookie settings. -
jwt-crypto-access.md 5.5 KB
# JWT, crypto, access, cookies ## JWT / JWK Prefer framework-native `Bitrix\Main\Web\JWT` and `Bitrix\Main\Web\JWK` over hand-rolled `header.payload.signature` or local `base64UrlEncode` helpers. Rules: - Issue with `JWT::encode()`; verify with `JWT::decode($token, $key, $allowedAlgs)` — **always** pass an algorithm allowlist; never trust `alg` from the token header alone. - Always set `exp` and `iat` (and other claims your contract needs). Payload must be JSON-safe scalars/arrays — not complex objects. - Secrets / private keys: `.settings_extra.php` or env — not git-tracked `.settings.php`. - JOSE unpadded Base64 URL-safe: `JWT::urlsafeB64Encode()` / `urlsafeB64Decode()` — not generic `base64_*` and not for arbitrary MIME blobs. - RSA public keys from JWKS: `JWK::parseKeySet()` / `JWK::parseKey()`, then `JWT::decode()`. `JWK` is a public-key helper, not a full key-management API (no private-key constructor for every `kty`). - When verifying with a key set that uses `kid`, pass the keyed set from `parseKeySet` into `decode` — do not reimplement key selection. ```php use Bitrix\Main\Web\JWT; use Bitrix\Main\Web\JWK; $token = JWT::encode([ 'sub' => $userId, 'iat' => time(), 'exp' => time() + 3600, ], $secret, 'HS256'); $decoded = JWT::decode($token, $secret, ['HS256']); // OpenID / JWKS: $keys = JWK::parseKeySet($jwks); $decoded = JWT::decode($jwt, $keys, ['RS256']); ``` ## Access Rights ### Basic Checks ```php global $USER; if (!$USER->IsAuthorized()) { return; } if (!$USER->IsAdmin()) { /* ... */ } if (!$USER->CanDoOperation('edit_own_profile')) { /* ... */ } ``` ### Module Permissions ```php $module = 'vendor.blog'; $rights = \CMain::GetUserRight($module, $USER->GetUserGroupArray()); if ($rights < 'W') { /* ... */ } ``` ### Controller Checks Prefer kernel filters over globals: - `ActionFilter\Authentication` for “must be logged in”. - `#[ActionAccess]` + `AccessCheckControllerInterface` when the module has an `access` controller (`AccessibleController` / `BaseAccessController`). Details: skill `bitrix-controllers` → `rules/filters.md`. - Otherwise a small `ActionFilter\Base` — do **not** copy `$USER` checks into every action. ```php use Bitrix\Main\Engine\ActionFilter\Attribute\Access\ActionAccess; use Bitrix\Main\Engine\Contract\AccessCheckControllerInterface; #[ActionAccess(action: 'post_edit', strategyArgs: ['itemIdRequestKey' => 'id'])] public function updateAction(int $id): array { /* ... */ } ``` Custom filter example (only when there is no access controller): ```php final class RequireRole extends \Bitrix\Main\Engine\ActionFilter\Base { public function __construct(private readonly string $role) { parent::__construct(); } public function onBeforeAction(\Bitrix\Main\Event $event) { $user = \Bitrix\Main\Engine\CurrentUser::get(); if (!$user->getId() || !in_array($this->role, $user->getUserGroups(), true)) { $this->errorCollection->add([new \Bitrix\Main\Error('Forbidden', 'ACCESS_DENIED')]); return new \Bitrix\Main\EventResult(\Bitrix\Main\EventResult::ERROR, null, null, $this); } return null; } } ``` ### `access` Module For complex ACL — use `access` module, roles, and permission providers (`Access\Role`, `Access\AccessibleItem`). ## Secure Cookies ```php $response = \Bitrix\Main\Context::getCurrent()->getResponse(); $cookie = new \Bitrix\Main\Web\Cookie('VENDOR_TOKEN', $token, time() + 86400); $cookie->setHttpOnly(true); $cookie->setSecure(true); $cookie->setSpread(\Bitrix\Main\Web\Cookie::SPREAD_DOMAIN); // if needed for all subdomains $response->addCookie($cookie); ``` Use `HttpOnly` + `Secure` + `SameSite=Lax/Strict`. Do not put access tokens in `localStorage`. ## Value Encryption - `CryptoField('SECRET')` — tablet field, encrypted transparently. - `SecretField('TOKEN')` — not returned on `select = '*'`. - Custom encryption: `Bitrix\Main\Security\Cipher`. ## Miscellaneous - **Proactive protection** (`proactive` firewall) — scans suspicious request parameters; do not disable without reason. - **Two-factor authentication** — enabled for admins by default; keep it. - **Captcha** — `\Bitrix\Main\Captcha` / `CCaptcha` for public forms. - **Frame protection** — `X-Frame-Options` / CSP headers via kernel settings. - **Access control module** (`access`) — roles, `Access\Role`, `Access\AccessibleItem` for complex ACL. - **`crypto` section** in `.settings.php` — encryption keys for cookies and `CryptoField`. - Store secrets in `.settings_extra.php` and environment variables, **not** in `.settings.php` under git. ## Checklist - [ ] AJAX controller actions rely on `Csrf` (`SCOPE_AJAX`); REST/other scopes have an explicit CSRF/auth check. - [ ] External URLs from user input use `HttpClient` with timeouts and `privateIp => false` (plus host whitelist where possible). - [ ] In ORM queries, field names and operators are taken from a whitelist, not from the request. - [ ] There is no concatenation with user input in `SqlExpression`/`ExpressionField`/`runtime`. - [ ] In templates, everything coming from the user is via `htmlspecialcharsbx`. - [ ] Administrative actions check `$USER->IsAdmin()` or specific `CanDoOperation`; controller ACL prefers `#[ActionAccess]` when the module has an access controller. - [ ] Cookies with tokens are `HttpOnly`, `Secure`, `SameSite`. - [ ] JWT uses `JWT::encode`/`decode` with an explicit algorithm allowlist; JWKS via `JWK::parseKeySet`. - [ ] Secrets are not committed; access to `.settings_extra.php` is restricted. -
sql-ssrf.md 2.4 KB
# SQL injection and SSRF ## SSRF - Do not access URLs from user input directly: `file_get_contents($url)`, `curl` with user hosts. - Use `Bitrix\Main\Web\HttpClient` with timeouts and **`privateIp => false`** for user-controlled URLs: ```php $client = new \Bitrix\Main\Web\HttpClient([ 'socketTimeout' => 5, 'streamTimeout' => 10, 'redirect' => false, 'disableSslVerification' => false, // Default privateIp is TRUE (private IPs allowed). For SSRF protection: 'privateIp' => false, ]); ``` - `privateIp` default **`true`** = private/link-local IPs **allowed**. Set `false` to block `127.0.0.1`, `169.254.*`, `10.*`, `192.168.*`, etc. - Also whitelist schemes/hosts where possible; for user-provided webhooks — validate host/scheme/port, sign requests with a secret. ## SQL Injections ### Raw SQL (Old Kernel) ```php $conn = \Bitrix\Main\Application::getConnection(); $helper = $conn->getSqlHelper(); $id = (int)$userInput; // for integers — forced casting $login = $helper->forSql($userLogin); // string escaping $conn->queryExecute("UPDATE b_user SET LOGIN = '{$login}' WHERE ID = {$id}"); ``` For bulk inserts/updates: ```php [$insertFields, $insertValues] = $helper->prepareInsert('b_user', $fields); $conn->queryExecute("INSERT INTO b_user ({$insertFields}) VALUES ({$insertValues})"); $update = $helper->prepareUpdate('b_user', $fields); $conn->queryExecute("UPDATE b_user SET {$update[0]} WHERE ID = {$id}", $update[1]); ``` ### ORM Queries — Can Also Be Vulnerable Dangerous spots in `getList`/`query()`: - `select` and `order` — field names **are not escaped**. Never put a "field name from request" there without a whitelist: ```php $allowedOrder = ['ID', 'CREATED_AT', 'TITLE']; $order = in_array(strtoupper($userOrder), $allowedOrder, true) ? strtoupper($userOrder) : 'ID'; PostTable::getList(['order' => [$order => 'DESC']]); ``` - `filter` — values are parameterized, but **keys** (field names with `=`, `>`, etc. prefixes) — are not. Also whitelist. - `SqlExpression` and `ExpressionField` — the second argument is substituted as is. Never build it from user input: ```php // DANGEROUS: new \Bitrix\Main\DB\SqlExpression("IF({$userField} = 1, 'a', 'b')"); // SAFE: new \Bitrix\Main\DB\SqlExpression('IF(?# = 1, "a", "b")', $userField); ``` - `runtime` fields — same rules.
-
-
SKILL.md 1.2 KB
--- name: bitrix-security description: CSRF, XSS, SQLi, SSRF, JWT/JWK, access rights, encryption. Use when handling input or auditing security. --- # Security in Bitrix Baseline: **main 23.0+**. Features newer than baseline are marked **Since**. Progressive disclosure: open **only** the rule files that match the task. Do not read every `rules/*.md`. ## How to use 1. Identify the layer the task touches. 2. Open the matching `rules/*.md` below. 3. Prefer framework-native Bitrix patterns over custom abstractions. ## Choose a rule file ### When to read `rules/csrf-xss.md` Read `rules/csrf-xss.md` (`CSRF and XSS`) when the task involves: - CSRF - XSS and HTML Sanitization - CSRF Details ### When to read `rules/sql-ssrf.md` Read `rules/sql-ssrf.md` (`SQL injection and SSRF`) when the task involves: - SSRF - SQL Injections ### When to read `rules/jwt-crypto-access.md` Read `rules/jwt-crypto-access.md` (`JWT, crypto, access, cookies`) when the task involves: - JWT / JWK - Access Rights - `#[ActionAccess]` / `AccessCheckControllerInterface` - Secure Cookies - Value Encryption - Miscellaneous - Checklist ## Checklist - [ ] Opened only the rule file(s) needed for this task. - [ ] Followed DI / `/local/` / security canons from `AGENTS.md`.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.