Guia de Segurança
Melhores práticas para proteger sua integração com o PayerScan Payment Gateway.
Segurança da API Key
Nunca exponha sua API Key
Sua API Key autentica as requisições enviadas à API do PayerScan. Ela nunca deve ser visível para os usuários finais.
// ❌ ERRADO - Chamando API do frontend (API Key exposta para todos)
fetch('https://api.payerscan.com/payment/crypto', {
headers: { 'x-api-key': 'EQnhBYpknGAP...' } // API Key exposta!
})
// ✅ CORRETO - Chamando API do servidor backend
// Frontend chama sua API interna
fetch('/api/create-payment', { body: { amount: 100 } })
// Seu backend chama o PayerScan (API Key segura no servidor)
app.post('/api/create-payment', async (req, res) => {
const result = await fetch('https://api.payerscan.com/payment/crypto', {
headers: { 'x-api-key': process.env.PAYERSCAN_API_KEY }
})
res.json(result)
})
Armazene a API Key com segurança
# ✅ Use variáveis de ambiente
PAYERSCAN_API_KEY=EQnhBYpknGAP...
# ❌ Não codifique diretamente no código
const API_KEY = 'EQnhBYpknGAP...' # NÃO FAÇA ISSO
Nota: Nunca faça commit de API Keys no controle de versão (Git). Adicione
.envao seu arquivo.gitignore.
Rotacione a API Key periodicamente
- Troque a API Key se suspeitar que foi comprometida
- Vá para o gerenciamento da Loja → Gerar nova API Key
- Atualize a nova API Key no seu servidor imediatamente
- A API Key antiga será revogada imediatamente após gerar uma nova
Segurança do Webhook
Use HTTPS
Sempre use HTTPS para seu callback_url para criptografar dados em trânsito e prevenir ataques man-in-the-middle.
// ✅ CORRETO - Usar HTTPS
callback_url: 'https://your-server.com/webhook/payment'
// ❌ ERRADO - Usar HTTP (dados não criptografados, vulnerável à interceptação)
callback_url: 'http://your-server.com/webhook/payment'
Verifique as requisições do Webhook
Sempre verifique se as requisições webhook realmente vêm do PayerScan:
app.post('/webhook/payment', express.json(), async (req, res) => {
try {
const { merchant_id, api_key, trans_id, request_id, status, amount, transaction_hash } = req.body
// 1. Verificar merchant_id (completed e expired)
if (merchant_id !== process.env.PAYERSCAN_MERCHANT_ID) {
return res.status(401).json({ error: 'Invalid merchant' })
}
// 2. Verificar api_key (apenas completed — expired não inclui api_key)
if (status === 'completed' && api_key !== process.env.PAYERSCAN_API_KEY) {
return res.status(401).json({ error: 'Invalid API Key' })
}
// 3. Encontrar pedido por request_id (se fornecido) ou trans_id
let order = null
if (request_id) {
order = await db.orders.findOne({ request_id })
}
if (!order) {
order = await db.orders.findOne({ trans_id })
}
if (!order) {
return res.status(404).json({ error: 'Order not found' })
}
// 4. Processar apenas pedidos em estados atualizáveis (idempotente)
const processableStatuses = ['waiting', 'pending', 'processing']
if (!processableStatuses.includes(order.status)) {
return res.status(200).json({ message: 'Already processed' })
}
// 5. Verificar se o valor corresponde (apenas completed — prevenir adulteração)
if (status === 'completed') {
if (parseFloat(amount) !== parseFloat(order.amount)) {
return res.status(400).json({ error: 'Amount mismatch' })
}
}
// 6. Verificar se transaction_hash já foi usado (prevenir replay)
if (status === 'completed') {
const existingTx = await db.orders.findOne({ transaction_hash })
if (existingTx) {
return res.status(409).json({ error: 'Transaction hash already used' })
}
}
// 7. Atualização atômica — inclui filtro de status para prevenir condição de corrida
if (status === 'completed') {
const result = await db.orders.update(
{ trans_id, status: { $in: processableStatuses } },
{ status: 'completed', transaction_hash }
)
if (result.modifiedCount === 0) {
return res.status(200).json({ message: 'Already processed' })
}
} else if (status === 'expired') {
const result = await db.orders.update(
{ trans_id, status: { $in: processableStatuses } },
{ status: 'expired' }
)
if (result.modifiedCount === 0) {
return res.status(200).json({ message: 'Already processed' })
}
}
res.status(200).json({ success: true })
} catch (error) {
console.error('Webhook processing error:', error)
res.status(500).json({ error: 'Internal server error' })
}
})
Processamento idempotente
Webhooks podem ser reenviados até 5 vezes. Garanta que o processamento múltiplo seja seguro:
// ✅ CORRETO - Atualizar apenas pedidos em estados processáveis
const processableStatuses = ['waiting', 'pending', 'processing']
if (!processableStatuses.includes(order.status)) {
return res.status(200).json({ message: 'Already processed' })
}
// ❌ ERRADO - Sem verificação, poderia creditar o saldo várias vezes
await addBalance(user, amount) // Se webhook enviado 2 vezes → creditado 2 vezes!
Segurança dos Dados
Não registre dados sensíveis em log
// ❌ ERRADO - Registrando API Key em log
console.log('Request with API Key:', req.headers['x-api-key'])
// ✅ CORRETO - Registre apenas o necessário
console.log('Payment created:', { trans_id, amount, status })
Valide a entrada
O PayerScan valida a entrada no lado do servidor, mas você também deve validar do seu lado:
// Validar valor (deve ser positivo, máximo 1.000.000 USD)
const amount = parseFloat(req.body.amount)
if (isNaN(amount) || amount <= 0 || amount > 1000000) {
return res.status(400).json({ error: 'Invalid amount' })
}
// Validar formato do callback_url
if (req.body.callback_url) {
try {
const url = new URL(req.body.callback_url)
if (url.protocol !== 'https:') {
console.warn('callback_url deve usar HTTPS para segurança')
}
} catch {
return res.status(400).json({ error: 'Invalid callback_url' })
}
}
Proteções do lado do servidor PayerScan
O PayerScan implementa múltiplas camadas de segurança no lado do servidor:
- Proteção SSRF: O sistema valida todos os valores de
callback_urlantes de enviar webhooks. IPs internos/privados e URLs suspeitas são bloqueados automaticamente. - Limitação de taxa: Os endpoints da API são protegidos com limites de taxa burst e sustentados para prevenir abuso. Veja Limites de Taxa para detalhes.
- Validação de entrada: Todos os parâmetros de requisição são validados usando schemas rigorosos (faixa de valor, formato de URL, limites de comprimento de string).
- Timeout do Webhook: Callbacks de webhook têm um timeout de 10 segundos. Se seu servidor não responder em 10 segundos, a tentativa é marcada como falha e será retentada.
Lista de verificação de segurança
Antes de ir ao ar
- API Key armazenada em variáveis de ambiente (não codificada diretamente)
- API Key não exposta no código frontend/client-side
- Arquivo
.envadicionado ao.gitignore - Endpoint do webhook usa HTTPS
- Webhook verifica
merchant_idpara completed e expired - Webhook verifica
api_keypara webhooks completed - Webhook encontra pedido por
request_idoutrans_id - Processamento de webhooks é idempotente (sem processamento duplicado)
- Webhook verifica se
amountcorresponde ao valor do pedido - Webhook verifica se
transaction_hashnão foi usado (prevenir replay) - Webhook usa atualização atômica com filtro de status (prevenir condição de corrida)
- Nenhum dado sensível registrado em log (API Key, chaves privadas)
- Validação de entrada para valores, URLs
Contínuo
- Revisar regularmente os logs de acesso do endpoint do webhook
- Monitorar requisições de webhook não autorizadas ou suspeitas
- Rotacionar API Key periodicamente ou se comprometida
- Atualizar dependências com patches de segurança
- Testar que o endpoint do webhook responde em 10 segundos
Resposta a incidentes de segurança
Se a API Key for comprometida
- Imediatamente vá ao gerenciamento da Loja → Gerar nova API Key
- Atualize a nova API Key em todos os servidores
- Revise os logs recentes da API para requisições não autorizadas
- Contate o suporte se transações suspeitas forem encontradas
Se webhooks fraudulentos forem detectados
- Verifique se seu handler de webhook verifica
merchant_ideapi_key - Verifique os logs para incompatibilidades de
amountou tentativas detransaction_hashduplicado - Bloqueie o IP de origem (se identificável)
- Adicione lista de permissão de IP se possível
- Contate o suporte para relatar o incidente
Contato com o suporte
Para problemas urgentes de segurança, contate-nos imediatamente:
- Email: payerscan@gmail.com