diff --git a/index.json b/index.json index 4f04544..1e11ef4 100755 --- a/index.json +++ b/index.json @@ -892,6 +892,25 @@ "severity": "critical", "path": "records/plugin-dev/KB-PLUGIN-044-glpi11-native-visibility-in-plugin-boards.md", "summary": "id: KB-PLUGIN-044" + }, + { + "id": "KB-PLUGIN-045", + "title": "Padrao de campo seguro para formulario anonimo GLPI 11 (QuestionType + Applicator)", + "domain": "plugin-dev", + "tags": [ + "glpi", + "glpi11", + "form-builder", + "question-type", + "form-destination", + "anonymous", + "security", + "extform" + ], + "status": "active", + "severity": "high", + "path": "records/plugin-dev/KB-PLUGIN-045-safe-anonymous-field-questiontype-applicator.md", + "summary": "id: KB-PLUGIN-045" } ] } diff --git a/records/infrastructure/KB-INFRA-005-glpi11-subpath-root_doc-symfony-routes-allowlist.md b/records/infrastructure/KB-INFRA-005-glpi11-subpath-root_doc-symfony-routes-allowlist.md index e697ec8..d671128 100644 --- a/records/infrastructure/KB-INFRA-005-glpi11-subpath-root_doc-symfony-routes-allowlist.md +++ b/records/infrastructure/KB-INFRA-005-glpi11-subpath-root_doc-symfony-routes-allowlist.md @@ -64,12 +64,18 @@ Por isso o form builder (controlador Symfony generico) quebrava, enquanto o rest # Correcao aplicada Adicionar as rotas de topo do GLPI 11 ao allowlist nos DOIS lugares. -Enumerar as rotas de topo: +Enumerar as rotas de topo — ATENCAO: muitas `#[Route(...)]` sao MULTI-LINHA (o path +vem na linha seguinte), entao um grep de linha unica PERDE rotas (ex.: `/Altcha/Challenge`). +Usar `-A2`: ```bash -grep -rhoE "#\[Route\(\s*[\"']/[A-Za-z0-9_]+" src/Glpi/Controller/ \ - | sed -E "s/.*['\"]\/([A-Za-z0-9_]+).*/\1/" | sort -u -# -> Central Form GenericAjaxCrud Helpdesk Install Inventory front progress +grep -rhA2 "#\[Route(" src/Glpi/Controller/ \ + | grep -oE '"/[A-Za-z0-9_]+' | sed 's|"/||' | sort -u +# 11.0.8 -> Altcha AuthLDAP Config Form GenericAjaxCrud Helpdesk Install Inventory +# Knowbase MFA Plugin ServiceCatalog Session UI api apirest caldav front progress status ``` +Como `root_doc=""` faz TODAS essas baterem na raiz, adicionar o conjunto todo de uma vez +(exceto `Install`, por hardening) evita ficar caçando rota a rota. O GLPI aplica a propria +auth (Firewall) em cada rota — o allowlist do proxy e so roteamento, nao fronteira de seguranca. 1. `nginx.conf` — regex do `location`: ``` @@ -94,6 +100,15 @@ curl -sk https://host/rota-inexistente | head -c 40 # -> "404 page not found" ``` No browser: recarregar (Ctrl+Shift+R) e salvar um formulario -> deve funcionar. +# Caso 2026-07-15 (2) — captcha ALTCHA em formulario anonimo falhava +Sintoma: "A verificacao falhou. Por favor, tente novamente mais tarde." no widget ALTCHA +("Nao sou um robo") + "Falha ao enviar o formulario" no submit. Causa: o widget busca o +desafio em `GET /Altcha/Challenge` (STRATEGY_NO_CHECK), rota que NAO estava no allowlist +(fora por causa do bug de enumeracao multi-linha acima). Fix: adicionadas ao allowlist as +rotas faltantes: `Altcha AuthLDAP Config Knowbase MFA ServiceCatalog Session UI apirest +caldav status`. Validar: `curl -sk https://host/Altcha/Challenge` deve dar 200 com JSON +`{"algorithm":"SHA-256","challenge":...}`. + # Regra para agentes - 404 com corpo `404 page not found` (plain text) = proxy/Traefik nao roteou; 404 HTML = GLPI roteou mas nao achou a rota. Distinga SEMPRE pelo corpo antes de culpar a app ou um plugin. - GLPI 11 em subcaminho depende de allowlist manual das rotas de topo (Symfony) em Traefik + nginx. A cada upgrade do GLPI, reenumerar as rotas de `src/Glpi/Controller` e ressincronizar as duas allowlists. diff --git a/records/plugin-dev/KB-PLUGIN-045-safe-anonymous-field-questiontype-applicator.md b/records/plugin-dev/KB-PLUGIN-045-safe-anonymous-field-questiontype-applicator.md new file mode 100644 index 0000000..a0a2f29 --- /dev/null +++ b/records/plugin-dev/KB-PLUGIN-045-safe-anonymous-field-questiontype-applicator.md @@ -0,0 +1,100 @@ +--- +id: KB-PLUGIN-045 +title: Padrao de campo seguro para formulario anonimo GLPI 11 (QuestionType + Applicator) +domain: plugin-dev +tags: + - glpi + - glpi11 + - form-builder + - question-type + - form-destination + - anonymous + - security + - extform +status: active +severity: high +created_at: 2026-07-15 +updated_at: 2026-07-15 +applies_to: + - GLPI 11.0.x form builder nativo + - plugin extform (campos externos seguros) + - qualquer campo "bloqueado no anonimo" que precise ser exposto com seguranca +related_records: + - KB-PLUGIN-002 + - KB-PLUGIN-005 + - KB-PLUGIN-007 + - KB-INFRA-005 +--- + +# Contexto +O GLPI 11 esconde de usuarios NAO autenticados toda pergunta cujo tipo retorna +`isAllowedForUnauthenticatedAccess() === false` (Condition\Engine). Bloqueados: atores, +Item/ItemDropdown (inventario), UserDevice. Categoria ITIL e Localizacao entram via +ItemDropdown -> tambem bloqueados. Precisamos expor alguns desses campos em formularios +de acesso externo, de forma SEGURA (sem enumerar entidades internas). + +# Padrao (modelo, validado com QuestionTypeSafeCategory) +Cada campo bloqueado-mas-necessario = TRES pecas. + +## 1. QuestionType de plugin (estende AbstractQuestionType) +- `isAllowedForUnauthenticatedAccess(): bool => true`. +- `getCategory()` retorna a categoria do plugin (KB-PLUGIN-002, senao editor quebra no JS). +- `renderEndUserTemplate()`: monta o `` mostra so o subconjunto seguro; + categoria nao-visivel NAO aparece. +3. Submit valido via AnswersHandler::saveAnswers -> ticket criado com o campo setado. +4. Submit adulterado (id fora do subconjunto) -> `prepareEndUserAnswer` rejeita -> + campo do ticket fica 0. Categoria proibida nunca e injetada. + +# Armadilhas +- Metodos do editor DEVEM passar sem excecao, senao o GLPI aborta o plugin_init e o tipo + "some" (checar `glpi:plugin:list`; reativar). Ver KB-PLUGIN-002. +- `QuestionTypeItemDropdown` e `final` — nao estender (KB-PLUGIN-007). +- Ambiente atras de proxy em subcaminho: o form builder e o captcha so funcionam apos o + allowlist de rotas Symfony (KB-INFRA-005). + +# Regra para agentes +Para expor no anonimo qualquer campo que o core bloqueia, NUNCA "desbloquear" o tipo nativo +(recria a vulnerabilidade de enumeracao). Criar um QuestionType de plugin com render +server-side ESCOPADO + revalidacao no submit, e um Applicator silencioso para mapear a +resposta ao campo do ticket. Filtrar sempre pelo flag de visibilidade do proprio GLPI +(`is_helpdeskvisible`) e/ou escopo de entidade. + +# Classificacao +- Tipo: Padrao arquitetural reutilizavel (modelo para SafeCategory, SafeLocation, etc.). +- Reutilizacao: base de todos os campos seguros do plugin extform.