Documentação técnica detalhada da arquitetura criptográfica do PDF Pro
Transferência de ficheiros encriptada de ponta a ponta
PDF Pro Whitepaper WP-001 — Arquitetura e segurança
Este whitepaper descreve a arquitetura do sistema Transferência Segura do PDF Pro, um mecanismo de transferência de ficheiros encriptado de ponta a ponta no qual os ficheiros são encriptados do lado do cliente com AES-256-GCM antes do envio. O servidor armazena apenas texto cifrado opaco e não tem capacidade para desencriptar, inspecionar ou ler o conteúdo dos ficheiros em qualquer momento. O sistema suporta dois modos de chave: uma chave aleatória gerada automaticamente (transportada no fragmento do URL, que nunca é enviado ao servidor) ou uma chave derivada de uma frase-passe usando PBKDF2. Em ambos os modos, a chave de encriptação existe apenas no navegador do remetente e do destinatário. Este documento detalha as primitivas criptográficas, o fluxo de dados, o modelo de ameaças e as limitações honestas do sistema. Nota sobre a terminologia: este sistema não utiliza provas de conhecimento zero (ZKPs). Quando dizemos que o servidor tem "conhecimento zero" dos seus ficheiros, queremos dizer que — como consequência da encriptação do lado do cliente — o servidor apenas detém texto cifrado que não consegue desencriptar.
O sistema Transferência Segura segue uma separação rigorosa entre cliente e servidor, na qual todas as operações criptográficas ocorrem exclusivamente no navegador:
O servidor é intencionalmente concebido como um "tubo opaco" para dados encriptados. Não tem conhecimento da chave de encriptação, da frase-passe ou do conteúdo dos ficheiros. Isto é imposto arquitetonicamente, não meramente por política.
Princípio de design: O servidor deve poder ser comprometido sem comprometer os dados dos utilizadores. Mesmo com acesso total à base de dados e execução de código do lado do servidor, um atacante não consegue desencriptar os ficheiros transferidos.
Toda a encriptação de ficheiros utiliza o algoritmo de encriptação autenticada AES-256-GCM, acedido através da Web Crypto API nativa do navegador. Isto fornece tanto confidencialidade (os dados não podem ser lidos) como integridade (os dados não podem ser modificados sem deteção).
| Parâmetro | Valor | Justificação |
|---|---|---|
| Algoritmo | AES-256-GCM | Aprovado pelo NIST, encriptação autenticada com dados associados (AEAD) |
| Tamanho da chave | 256 bits | Comprimento máximo de chave AES; fornece segurança de 128 bits contra força bruta |
| Tamanho do IV | 96 bits (12 bytes) | Comprimento de IV recomendado pelo NIST para o modo GCM |
| Tamanho do tag | 128 bits (16 bytes) | Tag de autenticação de comprimento total para máxima proteção da integridade |
| Geração do IV | crypto.getRandomValues() | Gerador de números aleatórios criptograficamente seguro |
// Fluxo de encriptação simplificado (Web Crypto API) const iv = crypto.getRandomValues(new Uint8Array(12)); const salt = crypto.getRandomValues(new Uint8Array(16)); // Derivar chave a partir da frase-passe (ver Secção 1.4) const key = await deriveKey(passphrase, salt); // Encriptar o ficheiro const ciphertext = await crypto.subtle.encrypt( { name: "AES-GCM", iv: iv }, key, fileArrayBuffer ); // Pacote: [salt (16B)] + [iv (12B)] + [ciphertext + tag] const blob = concatenate(salt, iv, ciphertext);
O blob encriptado final é uma concatenação de três componentes: o salt de 16 bytes (utilizado para derivação de chave), o IV de 12 bytes (utilizado para AES-GCM) e o texto cifrado com o tag de autenticação GCM de 16 bytes anexado. Este blob é o que o servidor recebe e armazena.
A Transferência Segura suporta dois modos de chave mutuamente exclusivos. O modo é selecionado pelo remetente no momento da criação da transferência.
No modo predefinido, não é envolvida qualquer frase-passe. O navegador gera diretamente uma chave AES de 256 bits criptograficamente aleatória:
crypto.getRandomValues() e crypto.subtle.generateKey().#).Quando o remetente opta por definir uma frase-passe, a chave é derivada dessa frase-passe utilizando PBKDF2:
| Parâmetro | Valor | Justificação |
|---|---|---|
| Algoritmo | PBKDF2 | Recomendado pelo NIST SP 800-132; amplamente auditado |
| Função de hash | SHA-256 | Hash criptográfico padrão; saída de 256 bits |
| Iterações | 600 000 | Cumpre a recomendação OWASP 2023 para PBKDF2-SHA256 |
| Tamanho do salt | 128 bits (16 bytes) | Único por transferência; previne ataques por tabelas arco-íris |
| Comprimento da chave de saída | 256 bits | Corresponde ao requisito de chave AES-256 |
async function deriveKey(passphrase, salt) { // Importar frase-passe como material de chave em bruto const keyMaterial = await crypto.subtle.importKey( "raw", new TextEncoder().encode(passphrase), { name: "PBKDF2" }, false, ["deriveKey"] ); // Derivar chave AES-256-GCM return crypto.subtle.deriveKey( { name: "PBKDF2", salt: salt, iterations: 600000, hash: "SHA-256" }, keyMaterial, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"] ); }
Nota de segurança: A segurança depende da entropia da frase-passe no Modo B. Recomendamos frases-passe com 12 ou mais caracteres misturando maiúsculas, minúsculas, dígitos e símbolos.
O ciclo de vida completo de uma transferência segura segue este percurso:
crypto.getRandomValues().#).crypto.getRandomValues().| Elemento de Dados | Servidor Tem Acesso? | Detalhes |
|---|---|---|
| Blob encriptado (salt + IV + ciphertext + tag) | Sim | Dados binários opacos; o servidor não consegue interpretar o conteúdo |
| ID da transferência | Sim | Os identificadores de transferência são valores UUID v4 gerados pela função gen_random_uuid() do PostgreSQL, fornecendo 122 bits de aleatoriedade criptográfica do CSPRNG do servidor |
| Nome de ficheiro original | Sim | Armazenado em metadados para apresentação ao destinatário |
| Tamanho de ficheiro original | Sim | Armazenado em metadados para fins de apresentação |
| Carimbo temporal de expiração | Sim | Utilizado para aplicação de eliminação automática |
| Contagem / limite de transferências | Sim | Utilizado para aplicação de "queimar após leitura" e do limite de transferências |
| ID do utilizador remetente (se autenticado) | Sim | Liga a transferência à conta para gestão |
| Frase-passe | Não — nunca | Nunca enviada ao servidor; nunca sai do navegador |
| Chave de encriptação derivada | Não — nunca | Existe apenas na memória do navegador durante a encriptação/desencriptação |
| Conteúdo do ficheiro em texto simples | Não — nunca | Apenas o texto cifrado encriptado chega ao servidor |
| Número de iterações PBKDF2 | Não | Codificado no cliente; não transmitido ao servidor |
Todas as transferências seguras são efémeras por design. Não existe opção de armazenamento permanente.
| Opção | Comportamento | Aplicação |
|---|---|---|
| Queimar após leitura | O blob encriptado é eliminado imediatamente após a primeira transferência bem-sucedida | Do lado do servidor: blob eliminado do armazenamento após o stream de transferência terminar |
| 1 hora | Eliminado automaticamente após 1 hora, independentemente do estado de transferência | Do lado do servidor: tarefa de limpeza agendada + verificação de expiração no acesso |
| 24 horas | Eliminado automaticamente após 24 horas | Igual ao anterior |
| 7 dias | Retenção máxima; eliminado automaticamente após 7 dias | Igual ao anterior |
Quando uma transferência expira ou é queimada após leitura, o blob encriptado é eliminado permanentemente do Supabase Storage. O registo de metadados é mantido durante 30 dias num estado de eliminação suave (para investigação de abuso) antes de ser purgado permanentemente. O registo de metadados não contém a chave de encriptação, a frase-passe ou qualquer informação que possa ser utilizada para reconstruir o ficheiro.
| Ameaça | Vetor de Ataque | Mitigação |
|---|---|---|
| Comprometimento do servidor | Atacante obtém acesso total à base de dados e ao armazenamento | Todos os dados armazenados são texto cifrado AES-256-GCM. O atacante obtém apenas blobs opacos. Sem a frase-passe, atacar AES de 256 bits por força bruta é computacionalmente inviável. |
| Interceção de rede (MITM) | Atacante interceta dados em trânsito | Todo o tráfego utiliza TLS 1.3. Mesmo que o TLS seja quebrado, o atacante obtém apenas blobs encriptados (igual ao comprometimento do servidor). |
| Frase-passe fraca | Atacante força por força bruta uma frase-passe curta ou comum | O PBKDF2 com 600 mil iterações torna cada tentativa computacionalmente dispendiosa. Uma frase-passe de 4 caracteres ainda exigiria poder de computação significativo. A interface aplica um comprimento mínimo da frase-passe e fornece feedback de robustez. |
| Interceção da frase-passe | Atacante interceta a frase-passe partilhada entre remetente e destinatário | A frase-passe é partilhada fora da banda (não através do nosso sistema). Recomendamos a partilha através de um canal diferente do URL de transferência. Esta é uma responsabilidade do utilizador. |
| Adulteração do código do lado do cliente | Atacante modifica o JavaScript servido ao utilizador | Todos os recursos são servidos por HTTPS através do CDN da Vercel. Hashes de Subresource Integrity (SRI) protegem contra adulteração ao nível do CDN. Os utilizadores podem verificar o código-fonte nas ferramentas de programador do navegador. |
| Extração de memória | Atacante extrai a chave de encriptação da memória do navegador | As chaves da Web Crypto API são marcadas como não extraíveis sempre que possível. As chaves derivadas existem em memória apenas durante a operação de encriptação/desencriptação. O isolamento de memória do navegador fornece proteção ao nível do sistema operativo. |
| Ataque de repetição | Atacante repete um blob encriptado capturado | Cada transferência tem um ID único e é protegida por limites de transferência e expiração. As transferências com queima após leitura são eliminadas após o primeiro acesso. |
Limitações honestas: Nenhum sistema de segurança é perfeito. Acreditamos na divulgação transparente das limitações conhecidas.
Assinatura criptográfica de documentos com privacidade em primeiro lugar
PDF Pro Whitepaper WP-002 — Arquitetura e segurança
Este whitepaper descreve a arquitetura do sistema Assinatura Privada do PDF Pro, um mecanismo criptográfico de assinatura de documentos no qual o documento PDF nunca sai do navegador do signatário. O sistema utiliza ECDSA com a curva P-256 e hash SHA-256 para produzir assinaturas digitais separadas. Apenas o hash do documento, a assinatura criptográfica e a chave pública são transmitidos ao servidor. As chaves privadas são geradas, encriptadas e armazenadas exclusivamente no navegador do utilizador através de IndexedDB, protegidas por derivação de chave PBKDF2 (600 000 iterações) e encriptação AES-256-GCM. Este documento detalha a arquitetura completa de assinatura e verificação, o modelo de gestão de chaves, o esquema do payload assinado, o design do registo de auditoria, o modelo de ameaças e as limitações honestas.
O sistema Assinatura Privada foi concebido em torno de uma restrição fundamental: o documento PDF nunca pode ser transmitido ao servidor. Isto é imposto arquitetonicamente através de um modelo de assinatura separada.
Garantia central: O servidor nunca vê, recebe ou processa o documento PDF. Os únicos dados relacionados com o documento que o servidor recebe são um hash SHA-256 — um valor de tamanho fixo de 256 bits a partir do qual o documento original não pode ser reconstruído.
| Parâmetro | Valor | Justificação |
|---|---|---|
| Algoritmo de assinatura | ECDSA (Algoritmo de Assinatura Digital de Curva Elíptica) | NIST FIPS 186-4; assinaturas compactas; segurança forte por bit de chave |
| Curva | P-256 (secp256r1 / prime256v1) | Aprovada pelo NIST; nível de segurança de 128 bits; amplo suporte na Web Crypto API |
| Função de hash | SHA-256 | NIST FIPS 180-4; resumo de 256 bits; resistente a colisões |
| Tamanho da chave | Chave privada de 256 bits, chave pública de 512 bits (não comprimida) | Padrão para P-256; equivalente a RSA de ~3072 bits |
| Tamanho da assinatura | 64 bytes (r: 32 bytes, s: 32 bytes) | Compacta; adequada para armazenamento e transmissão |
| Formato da assinatura | IEEE P1363 (r || s em bruto) | Saída nativa da Web Crypto API; codificada em base64url para armazenamento |
Codificação da assinatura: O ECDSA com P-256 da Web Crypto API produz uma assinatura em bruto de 64 bytes composta por dois inteiros de 32 bytes (r || s) em formato big-endian de largura fixa. Esta saída em bruto é codificada em base64url para armazenamento. Este NÃO é um formato DER — é o formato IEEE P1363 que a Web Crypto API produz nativamente.
// 1. Calcular hash do documento PDF (do lado do cliente) const fileBuffer = await file.arrayBuffer(); const hashBuffer = await crypto.subtle.digest("SHA-256", fileBuffer); const hashHex = Array.from(new Uint8Array(hashBuffer)) .map(b => b.toString(16).padStart(2, '0')).join(''); // 2. Assinar o hash com a chave privada (do lado do cliente) const signature = await crypto.subtle.sign( { name: "ECDSA", hash: "SHA-256" }, privateKey, // CryptoKey de IndexedDB (desencriptada) hashBuffer ); // 3. Enviar ao servidor: hash + assinatura + chave pública (NÃO o PDF) await submitSignature({ documentHash: hashHex, signature: base64Encode(signature), publicKey: exportedPublicKeyJWK });
| Tipo de Chave | Contexto | Ciclo de Vida | Armazenamento |
|---|---|---|---|
| Efémera | Utilizadores convidados (sem sessão iniciada) | Gerada por sessão; destruída quando o separador é fechado | Apenas em memória (objeto CryptoKey); nunca persistida |
| Persistente | Utilizadores autenticados (com sessão iniciada) | Gerada uma vez; persistida entre sessões; revogável | IndexedDB (encriptada com PBKDF2 + AES-256-GCM) |
// Gerar par de chaves ECDSA P-256 (Web Crypto API) const keyPair = await crypto.subtle.generateKey( { name: "ECDSA", namedCurve: "P-256" }, true, // extraível (necessário para encriptação + armazenamento) ["sign", "verify"] ); // Exportar chave pública como JWK para registo no servidor const publicKeyJWK = await crypto.subtle.exportKey("jwk", keyPair.publicKey); // Exportar chave privada como JWK para armazenamento encriptado const privateKeyJWK = await crypto.subtle.exportKey("jwk", keyPair.privateKey);
Formato da chave pública: As chaves públicas são exportadas e armazenadas no formato JWK (JSON Web Key). A impressão digital da chave é calculada como SHA-256 do JWK canónico contendo apenas os campos públicos {crv, kty, x, y} com as chaves ordenadas alfabeticamente.
As chaves privadas persistentes nunca são armazenadas em texto simples. Antes de serem escritas em IndexedDB, a chave privada (exportada como JWK JSON) é encriptada utilizando o mesmo padrão da Transferência Segura:
| Parâmetro | Valor |
|---|---|
| Derivação de chave | PBKDF2-SHA256, 600 000 iterações |
| Salt | 16 bytes aleatórios (por chave) |
| Encriptação | AES-256-GCM |
| IV | 12 bytes aleatórios (por encriptação) |
| Entrada | JWK da chave privada (string JSON, codificada em UTF-8) |
| Saída armazenada em IndexedDB | { salt, iv, ciphertext, publicKeyJWK, keyId, createdAt } |
// Estrutura do registo IndexedDB para uma chave de assinatura encriptada { "keyId": "uuid-v4-unique-identifier", "publicKey": { /* formato JWK, não encriptado */ }, "encryptedPrivateKey": { "salt": "base64-encoded-16-bytes", "iv": "base64-encoded-12-bytes", "ciphertext": "base64-encoded-aes-gcm-ciphertext" }, "algorithm": "ECDSA", "curve": "P-256", "createdAt": "2026-04-16T00:00:00.000Z", "userId": "supabase-auth-user-id" }
Recuperação de chave: Se o utilizador esquecer a sua frase-passe de assinatura, a chave privada não pode ser recuperada. Não temos a frase-passe, a chave derivada ou qualquer mecanismo para contornar a proteção PBKDF2 + AES-GCM. Os utilizadores devem exportar cópias de segurança das chaves.
O PDF Pro utiliza um modelo de assinatura separada, o que significa que a assinatura é armazenada separadamente do documento. Este é o mecanismo crítico de privacidade: o documento nunca sai do dispositivo do signatário.
Garantia criptográfica: O SHA-256 é uma função de hash unidirecional. Dado apenas o hash e3b0c44298fc1c14..., fornece uma forte garantia criptográfica, sob os pressupostos de segurança do ECDSA e do SHA-256, de que o documento original não pode ser reconstruído. O hash não revela nada sobre o conteúdo, comprimento ou estrutura do documento, para além de confirmar a identidade quando recalculado.
O esquema JSON seguinte define o registo de assinatura completo armazenado no servidor:
{
"schemaVersion": "1.0",
"signatureId": "uuid-v4",
"documentHash": "sha256-hex-64-chars",
"hashAlgorithm": "SHA-256",
"signature": "base64-encoded-ecdsa-signature",
"signatureAlgorithm": "ECDSA",
"curve": "P-256",
"publicKey": {
"kty": "EC",
"crv": "P-256",
"x": "base64url-encoded-x-coordinate",
"y": "base64url-encoded-y-coordinate"
},
"signer": {
"identityLevel": "authenticated | self-asserted",
"displayName": "string or null",
"email": "string or null",
"userId": "supabase-uid or null"
},
"timestamp": "ISO-8601-UTC",
"metadata": {
"fileName": "original-file-name.pdf",
"fileSize": 123456,
"pageCount": 12,
"clientVersion": "2.0.0",
"userAgent": "browser-user-agent-string"
},
"auditChain": {
"previousEventHash": "sha256-of-previous-audit-event or null",
"eventHash": "sha256-of-this-record"
}
}A verificação de assinaturas é um processo em duas fases: verificação criptográfica do lado do cliente seguida de verificação cruzada do lado do servidor.
const isValid = await crypto.subtle.verify( { name: "ECDSA", hash: "SHA-256" }, importedPublicKey, signatureBuffer, hashBuffer );
isValid === true, a assinatura é criptograficamente válida: o documento não foi modificado desde a assinatura e a assinatura foi produzida pelo detentor da chave privada correspondente.| Resultado | Significado |
|---|---|
| Válida (Autenticada) | A assinatura é criptograficamente válida E a chave pública pertence a um utilizador PDF Pro registado e autenticado. |
| Válida (Auto-Declarada) | A assinatura é criptograficamente válida, mas a identidade do signatário é auto-declarada (utilizador convidado ou nome não verificado). |
| Inválida | A verificação criptográfica falhou. O documento foi modificado desde a assinatura ou a assinatura está corrompida. |
| Revogada | A assinatura era válida, mas foi explicitamente revogada pelo signatário. |
| Nenhuma assinatura encontrada | Não existe registo de assinatura para este hash de documento. |
Cada evento de assinatura e verificação é registado num registo de auditoria à prova de adulteração. Os eventos são encadeados por hash: cada evento inclui o hash SHA-256 do evento anterior, formando uma cadeia apenas de adição semelhante a uma blockchain.
| Tipo de Evento | Acionador | Dados Registados |
|---|---|---|
KEY_REGISTERED | Utilizador regista uma nova chave pública | JWK da chave pública, ID do utilizador, carimbo temporal |
DOCUMENT_SIGNED | Utilizador assina um documento | Hash do documento, assinatura, chave pública, identidade do signatário, carimbo temporal |
SIGNATURE_VERIFIED | Qualquer utilizador verifica uma assinatura | Hash do documento, resultado da verificação, informação do verificador (se autenticado), carimbo temporal |
SIGNATURE_REVOKED | Signatário revoga uma assinatura | ID da assinatura, motivo da revogação, carimbo temporal |
KEY_REVOKED | Utilizador revoga uma chave pública | ID da chave pública, motivo da revogação, carimbo temporal |
// Cada evento de auditoria inclui: { "eventId": "uuid-v4", "eventType": "DOCUMENT_SIGNED", "timestamp": "ISO-8601-UTC", "data": { /* payload específico do evento */ }, "previousEventHash": "sha256-of-previous-event-json", "eventHash": "sha256-of-this-event-json-without-eventHash" } // Deteção de adulteração: para verificar a cadeia, calcular: // SHA-256(JSON.stringify(evento sem o campo eventHash)) // e confirmar que corresponde ao eventHash. // Depois confirmar que previousEventHash corresponde ao eventHash do evento anterior.
Se algum evento na cadeia for modificado, todas as ligações de hash subsequentes serão quebradas, tornando a adulteração imediatamente detetável. Isto fornece uma forte garantia da integridade do registo de auditoria.
Limitação importante: A cadeia de hashes torna a adulteração detetável dentro da sequência de eventos registados. No entanto, um administrador da base de dados com acesso direto poderia teoricamente eliminar e reconstruir a cadeia. Garantias mais fortes exigiriam carimbo temporal externo ou atestação por terceiros, o que não está implementado nesta versão.
| Nível | Requisitos | Propriedades de Confiança | Caso de Uso |
|---|---|---|---|
| Autenticada | Utilizador PDF Pro com sessão iniciada e e-mail verificado; par de chaves persistente registado na conta | E-mail verificado pelo Supabase Auth; chave pública vinculada a uma conta autenticada; registo de auditoria ligado ao ID do utilizador | Documentos empresariais, contratos, acordos formais |
| Auto-Declarada | Utilizador convidado ou utilizador autenticado com nome introduzido por si próprio; par de chaves efémero ou persistente | Integridade criptográfica garantida; a identidade do signatário é auto-declarada e não é independentemente verificada | Assinatura rápida, documentos pessoais, acordos informais |
Nota: Na interface do produto, "self_asserted" pode ser apresentado como "Identidade Auto-Declarada" ou "Assinatura de Convidado". "authenticated" pode ser apresentado como "Conta Autenticada". Estas são etiquetas de apresentação para os mesmos níveis de identidade subjacentes.
Vinculação de identidade: Uma assinatura "autenticada" significa que a chave pública está registada numa conta PDF Pro com um e-mail verificado. NÃO significa que a identidade real do signatário foi verificada por documento de identificação governamental, biometria ou verificação presencial. Não realizamos verificações Know Your Customer (KYC).
| Ameaça | Vetor de Ataque | Mitigação |
|---|---|---|
| Ataque de repetição | Atacante copia uma assinatura válida e aplica-a a um documento diferente | A assinatura está vinculada ao hash SHA-256 do documento específico. Um documento diferente terá um hash diferente e a verificação ECDSA falhará. |
| Falsificação | Atacante cria uma assinatura válida sem a chave privada | A segurança do ECDSA P-256 baseia-se no Problema do Logaritmo Discreto em Curvas Elípticas (ECDLP). Falsificar uma assinatura sem a chave privada é computacionalmente inviável (nível de segurança de 128 bits). |
| Substituição de chave | Atacante regista a sua própria chave pública e alega que uma assinatura foi feita por outra pessoa | As assinaturas autenticadas vinculam a chave pública a um e-mail verificado. O registo de auditoria regista qual a chave que assinou qual documento. Os eventos de registo de chave são encadeados por hash. |
| Substituição de documento | Atacante modifica um PDF assinado e alega que a assinatura ainda é válida | Qualquer modificação ao PDF altera o seu hash SHA-256. A assinatura existente falhará a verificação contra o novo hash. Encontrar uma colisão (documento diferente com o mesmo hash) requer ~2^128 operações. |
| Roubo da chave privada | Atacante extrai a chave privada encriptada de IndexedDB | A chave privada é encriptada com AES-256-GCM, com chave derivada por PBKDF2 (600 mil iterações). Sem a frase-passe, desencriptar a chave é computacionalmente inviável. |
| Comprometimento do servidor | Atacante obtém acesso total ao servidor | O servidor tem apenas chaves públicas e registos de assinaturas. As chaves privadas nunca chegam ao servidor. Um atacante não consegue falsificar novas assinaturas. Pode eliminar ou modificar registos existentes, mas as quebras na cadeia de hashes seriam detetáveis. |
| Adulteração do registo de auditoria | Atacante modifica eventos do registo de auditoria no servidor | Eventos encadeados por hash: modificar qualquer evento quebra a cadeia a partir desse ponto. Ferramentas de verificação independentes podem detetar quebras na cadeia. |
O que as assinaturas do PDF Pro NÃO são:
O nosso compromisso: Construímos segurança através da arquitetura, não do marketing. Estes whitepapers descrevem exatamente como os nossos sistemas funcionam, incluindo as suas limitações. Acreditamos que os utilizadores conscientes da segurança merecem total transparência técnica. Se tiver questões sobre qualquer aspeto da nossa arquitetura, contacte-nos em info@webdesign9.com.