130 lines
6.4 KiB
Markdown
130 lines
6.4 KiB
Markdown
# Compatibilidade de Navegadores e Acesso de Rede Privada (CCSP/1)
|
|
|
|
Este documento detalha o funcionamento, as garantias de segurança e os requisitos de compatibilidade entre aplicações web (servidas sob **HTTPS**) e o agente desktop **CyberCore Signer** em loopback local (`http://127.0.0.1:21325`).
|
|
|
|
---
|
|
|
|
## 1. Contexto Arquitetural: HTTPS para Loopback HTTP
|
|
|
|
Tradicionalmente, navegadores modernos impedem o carregamento de recursos inseguros (`http://`) a partir de contextos seguros (`https://`), mecanismo conhecido como **Mixed Content**.
|
|
|
|
No entanto, para agentes de assinatura digital locais e periféricos de hardware, o consórcio **W3C (Secure Contexts Specification)** e os motores de renderização modernos tratam o loopback IPv4 (`127.0.0.1`) e `localhost` como **Origens Potencialmente Confiáveis (*Potentially Trustworthy Origins*)**.
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
autonumber
|
|
participant Web as Aplicação Web (HTTPS)
|
|
participant Browser as Navegador (Chrome/Firefox/Safari)
|
|
participant Agent as CyberCore Signer (127.0.0.1:21325)
|
|
|
|
Note over Web,Agent: 1. Preflight CORS + Private Network Access (PNA)
|
|
Web->>Browser: fetch("http://127.0.0.1:21325/ccsp/v1/sign", { method: "POST" })
|
|
Browser->>Agent: OPTIONS /ccsp/v1/sign<br/>Origin: https://meusistema.com.br<br/>Access-Control-Request-Private-Network: true
|
|
Agent-->>Browser: HTTP 204 No Content<br/>Access-Control-Allow-Origin: *<br/>Access-Control-Allow-Private-Network: true<br/>Access-Control-Allow-Methods: GET, POST, OPTIONS
|
|
Note over Browser,Agent: 2. Requisição Real CCSP/1
|
|
Browser->>Agent: POST /ccsp/v1/sign (JSON Digest)
|
|
Agent-->>Browser: HTTP 200 OK (Assinatura Base64)
|
|
Browser-->>Web: Retorno Promise Resolvida
|
|
```
|
|
|
|
---
|
|
|
|
## 2. Private Network Access (PNA / W3C)
|
|
|
|
O **Private Network Access (PNA)** é uma especificação de segurança do W3C (adotada inicialmente pelo motor Chromium a partir do Chrome 98+) com o objetivo de proteger a rede local contra ataques de Cross-Site Request Forgery (CSRF).
|
|
|
|
### Como a especificação classifica as redes:
|
|
1. **Pública (*public*):** A internet pública (ex: `https://meusistema.com.br`).
|
|
2. **Privada (*private*):** Redes locais RFC 1918 (ex: `192.168.x.x`, `10.x.x.x`).
|
|
3. **Local (*local*):** A máquina do próprio usuário (`127.0.0.1`, `localhost`).
|
|
|
|
Quando uma página em um espaço de IP mais público solicita um recurso em um espaço mais restrito (como `public` $\rightarrow$ `local`), o navegador dispara uma requisição preliminar **Preflight PNA**.
|
|
|
|
### Headers Enviados pelo Navegador:
|
|
```http
|
|
OPTIONS /ccsp/v1/sign HTTP/1.1
|
|
Host: 127.0.0.1:21325
|
|
Origin: https://meusistema.com.br
|
|
Access-Control-Request-Method: POST
|
|
Access-Control-Request-Headers: Content-Type, X-CyberCore-AppId
|
|
Access-Control-Request-Private-Network: true
|
|
```
|
|
|
|
### Resposta Padrão do CyberCore Signer (`CcspServer`):
|
|
O servidor do agente desktop intercepta requisições `OPTIONS` e responde imediatamente com:
|
|
```http
|
|
HTTP/1.1 204 No Content
|
|
Access-Control-Allow-Origin: *
|
|
Access-Control-Allow-Methods: GET, POST, OPTIONS
|
|
Access-Control-Allow-Headers: Content-Type, Authorization, X-CyberCore-AppId, Origin, Accept
|
|
Access-Control-Allow-Private-Network: true
|
|
Access-Control-Max-Age: 86400
|
|
Connection: close
|
|
```
|
|
|
|
> [!NOTE]
|
|
> O cabeçalho `Access-Control-Allow-Private-Network: true` é fundamental para autorizar o navegador a enviar requisições privadas originadas de sites HTTPS públicos.
|
|
|
|
---
|
|
|
|
## 3. Matriz de Compatibilidade de Navegadores
|
|
|
|
| Navegador | Versão Mínima | Suporte HTTPS $\rightarrow$ 127.0.0.1 | Comportamento PNA | Requer Ação do Usuário? |
|
|
| :--- | :---: | :---: | :---: | :---: |
|
|
| **Google Chrome** | 88+ | ✅ Suportado | PNA ativo com preflight | Não (automático) |
|
|
| **Microsoft Edge** | 88+ | ✅ Suportado | PNA ativo com preflight | Não (automático) |
|
|
| **Mozilla Firefox** | 84+ | ✅ Suportado | Trata 127.0.0.1 como Secure Context | Não (automático) |
|
|
| **Opera / Brave** | Recentes | ✅ Suportado | Idêntico ao Chromium (ver nota Brave) | Pode exigir ajuste no Shields |
|
|
| **Apple Safari** | 15.4+ (macOS) | ✅ Suportado | Trata loopback como seguro | Não |
|
|
|
|
---
|
|
|
|
## 4. Casos de Borda e Soluções (Troubleshooting)
|
|
|
|
### 4.1. Navegador Brave (Brave Shields)
|
|
O Brave possui um mecanismo agressivo de proteção que pode bloquear preflights para `127.0.0.1`.
|
|
- **Sintoma:** O SDK lança `AgentNotRunningError`, mesmo com o agente em execução.
|
|
- **Resolução:** O usuário deve clicar no ícone do escudo (Shields) na barra de endereços da aplicação e desativar temporariamente o bloqueio para a origem ou permitir conexões locais nas configurações (`brave://settings/shields`).
|
|
|
|
### 4.2. Extensões de Privacidade e AdBlockers
|
|
Extensões como *uBlock Origin*, *Privacy Badger* ou *NoScript* podem conter regras genéricas de bloqueio para portas locais.
|
|
- **Resolução:** Adicionar a URL da sua aplicação web à lista de permissões (*allowlist*) da extensão.
|
|
|
|
### 4.3. Softwares de Antivírus e Endpoint Protection
|
|
Alguns antivírus com módulo de "Proteção Web" ou "Inspeção HTTPS" tentam atuar como proxy transparente no loopback local:
|
|
- **Resolução:** Configurar o antivírus para excluir a porta `21325` da inspeção de tráfego local.
|
|
|
|
### 4.4. Políticas Corporativas de Grupo (GPO / Chromium Enterprise)
|
|
Em ambientes corporativos restritos, administradores de rede podem bloquear chamadas a redes privadas via política:
|
|
- Política Chromium: `InsecurePrivateNetworkRequestsAllowed` ou `InsecurePrivateNetworkRequestsAllowedForUrls`.
|
|
- **Resolução:** Adicionar a URL do portal web corporativo na política `InsecurePrivateNetworkRequestsAllowedForUrls`.
|
|
|
|
---
|
|
|
|
## 5. Boas Práticas para Desenvolvedores Web
|
|
|
|
1. **Use sempre o SDK `@cybercore/signer-sdk`:** Ele gerencia timeouts, fallbacks de preflight e detecção de conectividade.
|
|
2. **Utilize `isInstalled()` antes de iniciar fluxos de assinatura:**
|
|
```javascript
|
|
import { CyberCoreSigner } from '@cybercore/signer-sdk';
|
|
|
|
const signer = new CyberCoreSigner();
|
|
|
|
if (!(await signer.isInstalled())) {
|
|
mostrarModalInstalacaoAgente();
|
|
}
|
|
```
|
|
3. **Capture `AgentNotRunningError` e exiba o guia de ajuda:**
|
|
```javascript
|
|
import { AgentNotRunningError } from '@cybercore/signer-sdk';
|
|
|
|
try {
|
|
await signer.connect();
|
|
} catch (err) {
|
|
if (err instanceof AgentNotRunningError) {
|
|
console.info(err.actionableGuidance);
|
|
exibirAjudaAoUsuario(err.actionableGuidance);
|
|
}
|
|
}
|
|
```
|