Segurança
A segurança é fundamental quando trabalhamos com pagamentos. Este guia apresenta as melhores práticas para proteger sua integração.
Proteção da API Key
A API Key é sua credencial de autenticação. Compromissos podem levar a cobranças não autorizadas.
Armazene em Variáveis de Ambiente
Use Cofres de Segredos em Produção
AWS Secrets Manager
aws secretsmanager create-secret \
--name toktus-api/api-key \
--secret-string "tk_a1b2c3d4e5f6789abcdef..."
```
```javascript
const AWS = require('aws-sdk');
const client = new AWS.SecretsManager();
const secret = await client.getSecretValue({
SecretId: 'toktus-api/api-key'
}).promise();
const apiKey = JSON.parse(secret.SecretString);
```
## Azure Key Vault
```bash
az keyvault secret set \
--vault-name meu-vault \
--name toktus-api-api-key \
--value "tk_a1b2c3d4e5f6789abcdef..."
```
```javascript
const { SecretClient } = require('@azure/keyvault-secrets');
const { DefaultAzureCredential } = require('@azure/identity');
const client = new SecretClient(
'https://meu-vault.vault.azure.net',
new DefaultAzureCredential()
);
const secret = await client.getSecret('toktus-api-api-key');
const apiKey = secret.value;
```
## HashiCorp Vault
```bash
# Armazenar
vault kv put secret/toktus-api api-key="tk_a1b2c3d4e5f6789abcdef..."
# Recuperar
vault kv get -field=api-key secret/toktus-api
```
### O que NÃO Fazer
> [!WARNING]
> **Nunca faça nenhuma das seguintes práticas:**
>
> - Commitar API Keys no Git ou repositórios públicos
> - Hardcodear no código-fonte
> - Expor em requisições client-side (JavaScript no navegador)
> - Compartilhar via e-mail, chat ou canais não criptografados
> - Registrar em logs em texto claro
> - Incluir em URLs ou query parameters
```javascript
// Avoid — hardcoded credentials in source code
const API_KEY = 'tk_a1b2c3d4e5f6789abcdef...';
// Avoid — logging sensitive values in plain text
console.log('API Key:', process.env.TOKTUS_API_API_KEY);
// Correct — redact sensitive values in all log output
console.log('API Key:', '***REDACTED***');Tokenização de Cartões
NUNCA trafegue dados de cartão através de seu backend sem certificação PCI DSS.
Tokenize no Frontend
Use as bibliotecas JavaScript dos gateways para tokenizar cartões direto no navegador:
Stripe.js
<script src="https://js.stripe.com/v3/"></script>
<script>
const stripe = Stripe('pk_test_sua_chave_publica');
const elements = stripe.elements();
const cardElement = elements.create('card');
cardElement.mount('#card-element');
// Tokeniza no frontend (nunca envia dados raw ao backend)
const {token, error} = await stripe.createToken(cardElement);
if (error) {
console.error(error.message);
} else {
// Envia APENAS o token ao backend
await fetch('/api/processar-pagamento', {
method: 'POST',
body: JSON.stringify({
cardToken: token.id, // tok_visa
amount: 10000
})
});
}
</script>
```
## MercadoPago.js
```html
<script src="https://sdk.mercadopago.com/js/v2"></script>
<script>
const mp = new MercadoPago('APP_USR-sua-public-key', {
locale: 'pt-BR'
});
const cardForm = mp.cardForm({
amount: '100.00',
iframe: true,
form: { id: 'form-checkout' },
callbacks: {
onSubmit: event => {
event.preventDefault();
const {token} = cardForm.getCardFormData();
fetch('/api/processar-pagamento', {
method: 'POST',
body: JSON.stringify({token})
});
}
}
});
</script>
```
> [!WARNING]
> Nunca envie dados raw de cartão ao backend. Isso viola normas PCI DSS e expõe dados sensíveis.
>
> ```javascript
> // Avoid — sending raw card data to the backend violates PCI DSS
> fetch('/api/processar-pagamento', {
> body: JSON.stringify({
> cardNumber: '4242424242424242',
> cvv: '123'
> })
> });
> ```
## SSL/TLS Obrigatório
### Sempre Use HTTPS em Produção
```javascript
// Express - force HTTPS
app.use((req, res, next) => {
if (req.header('x-forwarded-proto') !== 'https') {
res.redirect(`https://${req.header('host')}${req.url}`);
} else {
next();
}
});NGINX com Let's Encrypt
server {
listen 443 ssl http2;
server_name api.seudominio.com;
ssl_certificate /etc/letsencrypt/live/api.seudominio.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.seudominio.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
location / {
proxy_pass http://localhost:3001;
}
}Validação de Webhooks
Sempre valide que webhooks vieram do gateway legítimo:
Rate Limiting
Implemente rate limiting para proteger contra ataques:
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutos
max: 100,
message: {
success: false,
error: {
code: 'RATE_LIMIT_EXCEEDED',
message: 'Muitas requisições. Tente novamente em 15 minutos.'
}
}
});
app.use('/api/', limiter);Logs e Monitoramento
Registre
- Tentativas de autenticação (sucesso e falha)
- Operações de cobrança e estorno
- Erros de gateway
- Webhooks recebidos
- Mudanças de configuração
Nunca Registre
- Números de cartão completos
- CVV
- API Keys em texto claro
- Tokens não expirados
- Senhas
- Dados pessoais sensíveis (CPF completo, endereço)
// Correct — log only non-sensitive identifiers
logger.info('Cobrança criada', {
chargeId: 'ch_abc123',
amount: 10000,
gateway: 'stripe',
cardLast4: '4242' // Last 4 digits only
});
// Avoid — never log raw card data or credentials
logger.info('Cobrança criada', {
cardNumber: '4242424242424242',
apiKey: process.env.API_KEY
});Criptografia de Dados Sensíveis
Toktus API já criptografa credenciais com AES-256. Se você armazenar dados adicionais, faça o mesmo:
const crypto = require('crypto');
const ENCRYPTION_KEY = process.env.ENCRYPTION_KEY; // 32 bytes
const IV_LENGTH = 16;
function encrypt(text) {
const iv = crypto.randomBytes(IV_LENGTH);
const cipher = crypto.createCipheriv(
'aes-256-cbc', Buffer.from(ENCRYPTION_KEY, 'hex'), iv
);
let encrypted = cipher.update(text);
encrypted = Buffer.concat([encrypted, cipher.final()]);
return iv.toString('hex') + ':' + encrypted.toString('hex');
}
function decrypt(text) {
const parts = text.split(':');
const iv = Buffer.from(parts.shift(), 'hex');
const encryptedText = Buffer.from(parts.join(':'), 'hex');
const decipher = crypto.createDecipheriv(
'aes-256-cbc', Buffer.from(ENCRYPTION_KEY, 'hex'), iv
);
let decrypted = decipher.update(encryptedText);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted.toString();
}Ambiente de Teste
Use ambientes de teste/sandbox antes de produção:
| Gateway | Como Ativar |
|---|---|
| Stripe | Use chaves sk_test_... |
| Pagar.me | Use chaves sk_test_... |
| Asaas | Adicione "sandbox": "true" nas credenciais |
| Mercado Pago | Use credenciais de teste do painel |
| PagSeguro | Adicione "sandbox": "true" nas credenciais |
Checklist de Segurança
Antes de ir para produção, verifique:
Recursos Externos
Updated about 2 hours ago