Segurança em PDV & Varejo
Segurança em PDV: vulnerabilidades, ataques e testes práticos
Análise técnica de sistemas PDV, TEF e Pix: integração com pinpads como o Gertec PPC930, APIs, SQL injection, DLLs e conciliação, com comandos e demonstrações em Python.
Um sistema PDV concentra dinheiro, identidade de operadores, estoque, documentos fiscais e integrações de pagamento em uma máquina que precisa funcionar durante todo o expediente. Quando o software do caixa confia demais no Windows, na rede local ou em uma resposta recebida do navegador, o impacto pode aparecer como venda adulterada, acesso a outra filial, indisponibilidade ou conciliação financeira incorreta.
No varejo brasileiro, existe uma oferta ampla de sistemas de frente de caixa gratuitos ou com planos gratuitos, disponíveis para instalação rápida. O cenário que merece atenção é a empresa baixar o programa, instalar drivers, conectar um pinpad como o Gertec PPC930 e considerar a integração segura porque uma venda de teste foi aprovada. A aprovação demonstra funcionamento daquele fluxo; não avalia autenticação, autorização, integridade do instalador ou resistência a adulteração.
Este guia examina a arquitetura de PDV, TEF e Pix, apresenta nove classes de ataque e inclui três demonstrações locais completas. Os exemplos usam dados fictícios e não dependem de adquirente, cartão ou pinpad físico.
PDV gratuito é vulnerável? O problema está na cadeia de confiança
Gratuito, comercial e open source são modelos de distribuição distintos, não resultados de auditoria. Um projeto aberto e mantido pode oferecer controles melhores que um produto pago abandonado. O risco surge quando não há procedência verificável, atualização confiável, separação de privilégios ou responsável por corrigir falhas.
Há fornecedores brasileiros que anunciam versões gratuitas de PDV, como o Consumer. Essa referência comprova a existência da modalidade; não indica vulnerabilidade nesse fornecedor, compatibilidade com determinado pinpad nem prevalência de instalações inseguras. A análise abaixo trata de padrões de arquitetura que devem ser verificados em cada implantação.
Antes de discutir exploração, identifique quem fornece o executável, quem atualiza o middleware, onde ficam as credenciais do integrador e quem possui acesso remoto ao caixa. Um instalador autêntico pode entregar uma configuração fraca; um software bem desenvolvido pode ser instalado com permissões excessivas. São problemas diferentes e pedem evidências diferentes.
- Origem do instalador e canal oficial de atualização identificados.
- Versão do PDV, middleware e driver registrada por estação.
- Conta de operador separada da administração do Windows.
- Diretórios de programa protegidos contra gravação pelo operador.
- Serviços locais com identidade, porta e finalidade conhecidas.
- Credenciais de produção separadas das credenciais de teste.
- Confirmação de pagamento feita pelo backend com dados do provedor.
Como PDV, TEF, Pix e pinpad se conectam
PDV é a aplicação que conduz a venda. TEF é a integração que coordena operações de transferência eletrônica de fundos. O pinpad é o periférico de interação com o cartão e o portador. Um POS autônomo pode reunir várias funções no mesmo dispositivo; um pinpad ligado por USB normalmente participa de uma arquitetura com um computador hospedeiro.
A documentação do PPC930 informa interfaces USB e serial e recursos para cartões e criptografia. Esses recursos não tornam automaticamente confiável o software instalado no computador. Uma exposição no serviço que conversa com o periférico é uma descoberta sobre esse serviço e sua configuração; não basta para afirmar quebra da proteção criptográfica do pinpad.
Operador
-> PDV: carrinho, descontos, fechamento e identidade da loja
-> Backend: pedidos, permissoes e conciliacao
-> Integrador TEF / middleware
-> Driver / USB / serial -> pinpad
-> Provedor de pagamento / adquirente
Pix integrado
-> Backend cria cobranca no PSP
-> PDV exibe QR Code retornado pelo fluxo
-> Backend confirma recebimento e concilia o pedidoO ponto decisivo é localizar as fronteiras de confiança: interface para backend, processo para serviço local, loja para outra loja, pedido para recebimento. Pergunte qual componente pode alterar cada dado e qual componente toma a decisão final. O preço enviado pela interface, por exemplo, não deve substituir o cálculo autorizado do servidor.
Nove tipos de ataque contra sistemas PDV
| Superfície | Pré-condição relevante | Possível impacto | Evidência a buscar |
|---|---|---|---|
| Instalador e atualizador | Origem ou integridade não verificadas | Execução de código no caixa | Assinatura, hash confiável e mecanismo de atualização |
| DLLs e serviços | Caminho gravável e carga de código pelo processo | Execução com os privilégios do serviço | ACL efetiva e módulo realmente carregado |
| API local | Operação sensível sem autenticação adequada | Controle indevido da integração | Requisição reproduzível e mudança de estado correlacionada |
| API entre lojas | Falta de autorização por objeto | Leitura ou alteração de pedidos de outra filial | Comparação com identidades e objetos conhecidos |
| Entrada SQL | Concatenação de dados em consultas | Consulta adulterada e acesso indevido | Consulta reproduzida com base fictícia |
| Pix e conciliação | Confiança no cliente ou evento sem verificação | Baixa indevida, divergência ou duplicação | Recebimento autenticado versus pedido e estado |
| Suporte remoto | Conta compartilhada ou sessão excessivamente privilegiada | Acesso inicial e movimento lateral | Identidade, origem, duração e ações da sessão |
| Periféricos USB | Dispositivo com classe inesperada aceito | Entrada de teclado ou interface de rede indevida | Inventário PnP e eventos de conexão |
| Malware e disponibilidade | Execução prévia ou fluxo sem recuperação | Adulteração, parada de caixa e perda de operação | Processos, módulos, conexões e histórico transacional |
Uma porta aberta não demonstra fraude. Uma ACL permissiva não prova que uma DLL foi carregada. Um evento duplicado não prova pagamento duplicado. O relatório técnico deve ligar pré-condição, comportamento observado e impacto, sem pular essas etapas.
1. Inventário do caixa: processos, portas, serviços e pinpad
Comece pelo Windows do PDV. Os comandos desta seção são para PowerShell; os caminhos são exemplos que devem corresponder à instalação examinada. Eles coletam estado, sem reiniciar serviços ou enviar comandos ao dispositivo de pagamento.
Get-CimInstance Win32_SerialPort |
Select-Object DeviceID, Name, PNPDeviceID
Get-PnpDevice -PresentOnly |
Where-Object { $_.FriendlyName -match 'Gertec|PPC930|Pin.?Pad' } |
Select-Object Status, Class, FriendlyName, InstanceId
Get-CimInstance Win32_Service |
Where-Object { $_.Name -match 'PDV|TEF|Gertec' -or $_.DisplayName -match 'PDV|TEF|Gertec' } |
Select-Object Name, State, StartName, PathName
Get-NetTCPConnection -State Listen |
Sort-Object LocalPort |
Select-Object LocalAddress, LocalPort, OwningProcessOs filtros por nome são triagem: serviços com outro nome podem ficar de fora, e nem todo pinpad será exposto como porta serial. Cruze o PID da porta com o executável e com a conta do serviço. Uma escuta em 0.0.0.0 ou :: indica associação a todas as interfaces daquela família, mas a acessibilidade remota ainda depende de firewall e roteamento. Uma escuta em loopback reduz exposição de rede e continua acessível a outros processos locais.
Para uma estação de teste conhecida, um inventário TCP direcionado ajuda a comparar o que está escutando com o que outra máquina alcança. O endereço abaixo representa um único host da rede de laboratório; não há varredura de uma faixa inteira.
nmap -sT -sV --version-light -T2 -p 135,139,445,3389,8080,8443 192.168.56.20Uma porta 3389 acessível aponta para uma superfície de administração remota, não para credencial fraca comprovada. Uma porta 8080 não identifica, por si, o middleware do fabricante. Registre serviço, versão observada, origem do teste e regra de acesso esperada.
2. Instaladores, DLL hijacking e permissões excessivas
Um caminho de comprometimento pode começar antes da primeira venda: instalador obtido de um espelho desconhecido, atualização sem verificação ou componente colocado em um diretório gravável pelo operador. Se um processo privilegiado carrega uma biblioteca controlável a partir desse diretório, a gravação deixa de ser apenas um problema de organização de arquivos.
O MITRE ATT&CK documenta abuso de DLLs, incluindo substituição e manipulação da ordem de busca. Para confirmar um caso no PDV, é necessário demonstrar a resolução e a carga do módulo, além da permissão de gravação. Não basta localizar um arquivo com extensão DLL na pasta do programa.
$instalador = 'C:\Auditoria\instalador-pdv.exe'
Get-FileHash -LiteralPath $instalador -Algorithm SHA256
Get-AuthenticodeSignature -LiteralPath $instalador |
Select-Object Status, StatusMessage, SignerCertificate
Get-ChildItem -LiteralPath 'C:\PDV' -Filter *.dll -File |
ForEach-Object {
$assinatura = Get-AuthenticodeSignature -LiteralPath $_.FullName
[pscustomobject]@{
Arquivo = $_.FullName
Estado = $assinatura.Status
}
}icacls "C:\PDV"
icacls "C:\PDV\bin"
whoami /groupsCompare o SHA-256 com um valor obtido por um canal confiável; calcular um hash sozinho não autentica a origem. Uma assinatura válida identifica um signatário e ajuda a verificar integridade, mas não prova ausência de vulnerabilidades. Já NotSigned não é sinônimo de malware. O Get-AuthenticodeSignature fornece dados para essa análise, não um veredito completo.
Em ACLs, avalie entradas de modificação ou controle total concedidas a grupos amplos, herança e acesso efetivo do usuário. Separe binários de dados mutáveis: o operador pode precisar gravar um arquivo de operação, mas não substituir o executável do serviço. A correção deve preservar as permissões necessárias ao integrador e ser validada com o fluxo de venda.
3. API local: localhost não substitui autenticação
Alguns desenhos de integração expõem uma API HTTP local para intermediar periféricos. Outros usam DLLs, sockets ou troca de arquivos. A superfície depende da implementação instalada; não há neste artigo a afirmação de que uma porta ou endpoint específico pertence ao PPC930.
Em uma API local, examine quem pode chamar a operação, como a sessão é vinculada ao caixa e se operações de estado aceitam chamadas repetidas. Um serviço que aceita comandos de qualquer processo do usuário precisa de um modelo explícito de confiança. Se a API também é acessível pelo navegador, analise origem, formatos aceitos e proteção contra requisições de páginas não confiáveis.
O controle de acesso também precisa ser granular. Consultar o estado de uma sessão, abrir uma transação e encerrar uma operação não têm necessariamente a mesma autorização. Uma resposta HTTP 200 apenas informa que a camada HTTP respondeu; a conclusão exige observar o estado funcional e os identificadores da transação.
4. Demonstração de BOLA: pedido de outra loja
Em um backend com múltiplas filiais, autenticar o operador não significa autorizar todos os pedidos. A falha BOLA ocorre quando a API recebe um identificador válido e entrega o objeto sem verificar seu vínculo com a identidade solicitante. A OWASP descreve essa classe de falha; trocar números sequenciais por UUIDs não substitui a autorização.
Salve o código abaixo como api_pdv_lab.py. Ele usa apenas a biblioteca padrão do Python 3.10 ou superior, escuta em 127.0.0.1:8766 e contém dois pedidos fictícios. Os tokens demo-loja-a e demo-loja-b são identificadores fixos de demonstração, não um mecanismo de autenticação para produção.
import json
from http.server import BaseHTTPRequestHandler, HTTPServer
PEDIDOS = {
'100': {'loja': 'A', 'total_centavos': 12990},
'200': {'loja': 'B', 'total_centavos': 4500},
}
TOKENS_DEMO = {'demo-loja-a': 'A', 'demo-loja-b': 'B'}
class API(BaseHTTPRequestHandler):
def responder(self, status, corpo):
dados = json.dumps(corpo).encode()
self.send_response(status)
self.send_header('Content-Type', 'application/json')
self.send_header('Content-Length', str(len(dados)))
self.end_headers()
self.wfile.write(dados)
def do_GET(self):
token = self.headers.get('Authorization', '').removeprefix('Bearer ')
loja = TOKENS_DEMO.get(token)
if loja is None:
return self.responder(401, {'erro': 'autenticacao'})
partes = self.path.strip('/').split('/')
if len(partes) != 3 or partes[1] != 'pedidos':
return self.responder(404, {'erro': 'rota'})
modo, _, pedido_id = partes
if modo not in ('vulneravel', 'corrigido'):
return self.responder(404, {'erro': 'rota'})
pedido = PEDIDOS.get(pedido_id)
if pedido is None:
return self.responder(404, {'erro': 'pedido'})
if modo == 'corrigido' and pedido['loja'] != loja:
return self.responder(403, {'erro': 'loja_nao_autorizada'})
self.responder(200, pedido)
if __name__ == '__main__':
print('API ficticia em http://127.0.0.1:8766', flush=True)
HTTPServer(('127.0.0.1', 8766), API).serve_forever()python api_pdv_lab.pyEm outro terminal, compare os dois caminhos com a mesma identidade da loja A e o pedido 200, que pertence à loja B:
curl -i -H "Authorization: Bearer demo-loja-a" http://127.0.0.1:8766/vulneravel/pedidos/200
curl -i -H "Authorization: Bearer demo-loja-a" http://127.0.0.1:8766/corrigido/pedidos/200
curl -i -H "Authorization: Bearer demo-loja-a" http://127.0.0.1:8766/corrigido/pedidos/100No Windows, use curl.exe para evitar o alias de versões antigas do PowerShell. A primeira chamada retorna HTTP 200 com o pedido de outra loja; a segunda retorna HTTP 403; a terceira retorna HTTP 200 porque o objeto pertence à identidade autenticada. Esses resultados foram verificados no exemplo local.
Em produção, a loja deve vir da sessão validada no servidor. Aceitar loja_id do corpo da requisição e usá-lo como prova de autorização apenas muda o lugar do problema. A validação também deve considerar função: visualizar um pedido não implica poder cancelar, estornar ou conceder desconto.
5. Demonstração de SQL injection no cadastro de produtos
Um leitor de código de barras entrega entrada para a aplicação; isso não transforma o conteúdo lido em dado confiável. Campos de SKU, busca e importação podem alcançar consultas SQL. Se o código concatena a entrada à consulta, caracteres destinados a representar um produto podem ser interpretados como instrução SQL.
Este exemplo cria uma base SQLite apenas em memória. Salve como sqli_pdv.py e execute com Python. A consulta vulnerável e a parametrizada recebem exatamente a mesma entrada.
import sqlite3
db = sqlite3.connect(':memory:')
db.execute('CREATE TABLE produtos (sku TEXT, nome TEXT, preco_centavos INTEGER)')
db.executemany('INSERT INTO produtos VALUES (?, ?, ?)', [
('1001', 'Cafe', 1590),
('1002', 'Arroz', 2490),
])
def vulneravel(sku):
sql = "SELECT sku, nome FROM produtos WHERE sku = '" + sku + "'"
return db.execute(sql).fetchall()
def parametrizada(sku):
return db.execute('SELECT sku, nome FROM produtos WHERE sku = ?', (sku,)).fetchall()
entrada = "1001' OR 1=1 -- "
print('Busca normal:', vulneravel('1001'))
print('Concatenacao:', vulneravel(entrada))
print('Parametros:', parametrizada(entrada))
assert len(vulneravel(entrada)) == 2
assert parametrizada(entrada) == []python sqli_pdv.pyBusca normal: [('1001', 'Cafe')]
Concatenacao: [('1001', 'Cafe'), ('1002', 'Arroz')]
Parametros: []A entrada modifica a condição da primeira consulta e amplia o conjunto retornado. Na segunda, permanece um valor de busca e não encontra produto correspondente. Esse resultado demonstra adulteração de uma consulta no programa de exemplo; não demonstra extração de dados de um PDV comercial.
A parametrização de consultas deve ser aplicada na camada que acessa o banco. Validação de formato continua útil para regras de negócio, mas uma expressão regular no frontend não substitui esse controle. Nomes dinâmicos de coluna e ordenação exigem listas explícitas de opções permitidas, pois não são tratados como valores por todos os mecanismos de parâmetros.
6. Pix: QR Code exibido não significa recebimento liquidado
Em um fluxo mal implementado, o PDV recebe um QR Code, abre uma tela de espera e confia em uma resposta local como pago=true. Um atacante que controla a interface ou uma integração intermediária pode tentar adulterar essa indicação. O backend deve decidir a baixa a partir de informação autenticada do provedor e da correspondência com o pedido.
A especificação oficial da API Pix define recursos funcionais, e o próprio repositório separa esse escopo dos requisitos dos manuais de segurança. O formato de autenticação e de notificações deve seguir a integração do PSP contratado. Não existe um cabeçalho HMAC universal que possa ser inventado pelo PDV e tratado como padrão do Pix.
Há dois problemas distintos: adulterar o destinatário apresentado ao pagador e enganar a conciliação do comerciante. O primeiro exige proteger a origem e a integridade do conteúdo exibido; o segundo exige conferir o recebimento no backend. Verificar apenas um texto na tela, um comprovante ou o CRC do payload do QR Code não autentica uma liquidação.
| Campo ou relação | Verificação no backend |
|---|---|
| Pedido | Existe e pertence à loja autenticada |
| Valor | Corresponde ao valor esperado na política de pagamento |
| Recebedor | Corresponde à conta ou ao estabelecimento esperado |
| Identificador de cobrança | Está vinculado à tentativa de pagamento correta |
| Identificador de recebimento | Ainda não foi apropriado por outro pedido |
| Estado | Permite a transição solicitada |
| Origem da informação | Foi autenticada segundo o contrato do provedor |
Use valores monetários inteiros em centavos ou um tipo decimal apropriado. O exemplo seguinte adota pagamento integral único; parcelamento, pagamento parcial, devolução e múltiplas tentativas exigem um modelo mais rico.
7. Demonstração de conciliação e proteção contra replay
Salvar um identificador depois de marcar a venda como paga deixa uma janela de inconsistência. Duas entregas de um mesmo evento podem disputar o processamento. A unicidade e a mudança de estado precisam ser garantidas no armazenamento transacional, e não apenas em uma variável de memória do servidor.
Salve como conciliacao_pdv.py. O objeto recibo representa o resultado já autenticado de uma consulta ao PSP. O código não implementa transporte, autenticação do provedor nem um endpoint de webhook; concentra o teste nas regras de conciliação. A base é fictícia e fica em memória.
import sqlite3
db = sqlite3.connect(':memory:', isolation_level=None)
db.executescript('''
CREATE TABLE pedidos (
id TEXT PRIMARY KEY, txid TEXT UNIQUE, valor_centavos INTEGER,
recebedor TEXT, estado TEXT
);
CREATE TABLE recebimentos (
provedor TEXT, id TEXT, pedido_id TEXT UNIQUE,
PRIMARY KEY (provedor, id)
);
INSERT INTO pedidos VALUES ('P100', 'TX-DEMO-100', 12990, 'LOJA-A', 'PENDENTE');
''')
def conciliar(pedido_id, recibo):
# recibo representa uma consulta autenticada ao PSP, nao o body do cliente.
db.execute('BEGIN IMMEDIATE')
try:
pedido = db.execute('SELECT * FROM pedidos WHERE id = ?', (pedido_id,)).fetchone()
if pedido is None:
raise ValueError('pedido inexistente')
_, txid, valor, recebedor, estado = pedido
if (recibo['txid'], recibo['valor_centavos'], recibo['recebedor']) != (txid, valor, recebedor):
raise ValueError('divergencia na conciliacao')
if recibo['estado'] != 'LIQUIDADO':
raise ValueError('recebimento ainda nao liquidado')
anterior = db.execute(
'SELECT pedido_id FROM recebimentos WHERE provedor = ? AND id = ?',
(recibo['provedor'], recibo['id']),
).fetchone()
if anterior:
if anterior[0] != pedido_id:
raise ValueError('recebimento pertence a outro pedido')
db.execute('COMMIT')
return 'REPETICAO_IGNORADA'
if estado != 'PENDENTE':
raise ValueError('transicao de estado invalida')
db.execute('INSERT INTO recebimentos VALUES (?, ?, ?)',
(recibo['provedor'], recibo['id'], pedido_id))
db.execute("UPDATE pedidos SET estado = 'PAGO' WHERE id = ?", (pedido_id,))
db.execute('COMMIT')
return 'PAGO'
except Exception:
db.execute('ROLLBACK')
raise
recibo = dict(provedor='PSP-DEMO', id='E2E-DEMO-100', txid='TX-DEMO-100',
valor_centavos=12990, recebedor='LOJA-A', estado='LIQUIDADO')
for campo, valor in [('valor_centavos', 1), ('recebedor', 'LOJA-B'), ('estado', 'PENDENTE')]:
try:
conciliar('P100', {**recibo, campo: valor})
raise AssertionError('entrada invalida foi aceita')
except ValueError as erro:
print(campo, '-> REJEITADO:', erro)
print(conciliar('P100', recibo))
print(conciliar('P100', recibo))
assert db.execute('SELECT count(*) FROM recebimentos').fetchone()[0] == 1python conciliacao_pdv.pyvalor_centavos -> REJEITADO: divergencia na conciliacao
recebedor -> REJEITADO: divergencia na conciliacao
estado -> REJEITADO: recebimento ainda nao liquidado
PAGO
REPETICAO_IGNORADAO teste verifica divergência de valor, recebedor incorreto, estado pendente e repetição. A chave composta identifica um recebimento no provedor; a restrição por pedido representa a política de pagamento único. BEGIN IMMEDIATE e o commit agrupam registro e mudança de estado no SQLite. A versão de produção deve usar uma base persistente, política de retry, tratamento de conflitos e observabilidade.
Mesmo um evento autêntico pode estar atrasado. Depois de timeout, não crie outra cobrança cegamente: consulte a tentativa anterior e reconcilie o estado. A autorização transacional precisa estar ligada aos dados e ao estado da operação, não apenas ao fato de o usuário ter feito login.
8. Suporte remoto e segmentação da rede de caixas
O acesso remoto do fornecedor pode ser um caminho administrativo legítimo e, ao mesmo tempo, uma superfície crítica. Contas compartilhadas, sessões permanentes e permissões de administrador transformam o comprometimento de uma credencial em acesso a várias estações. A pergunta técnica é quais recursos essa identidade consegue alcançar e como suas ações são atribuídas.
Uma VLAN de PDVs deve ter regras de fluxo, não apenas um nome diferente. Caixas não precisam, por padrão, conversar livremente com todo o escritório, a rede de convidados e interfaces de administração. A política deve ser construída a partir dos destinos necessários ao PDV, ao integrador, à resolução de nomes, à atualização e ao suporte controlado.
Get-NetFirewallProfile |
Select-Object Name, Enabled, DefaultInboundAction, DefaultOutboundAction
Get-SmbShare |
Select-Object Name, Path, Description
Get-CimInstance Win32_Service |
Where-Object { $_.StartName -eq 'LocalSystem' } |
Select-Object Name, State, PathNameEsses comandos são um ponto de partida. As políticas efetivas também podem vir de domínio, MDM e regras no equipamento de rede. Uma política local com firewall ativo não prova isolamento entre filiais. Valide a comunicação permitida a partir das origens relevantes e compare com a matriz de acesso documentada.
9. USB, malware de PDV e disponibilidade operacional
Um dispositivo USB pode se apresentar como teclado, armazenamento, porta serial ou placa de rede. O formato físico do conector não informa a classe do dispositivo. Em uma estação desbloqueada, a aceitação indiscriminada de periféricos pode abrir caminhos de entrada que a equipe não associou à operação do caixa.
Controle físico, inventário de dispositivos e regras por classe e identidade ajudam a reduzir essa superfície. O teste deve considerar os equipamentos realmente usados: pinpad, scanner, impressora e assistência técnica. Uma política que bloqueia todos os USB indiscriminadamente pode impedir a própria operação que deveria proteger.
Malware voltado a pagamentos também é uma realidade documentada. Em 2023, a Kaspersky descreveu variantes do Prilex que bloqueavam transações por aproximação em sistemas infectados para induzir o uso do cartão físico. É uma referência histórica de pesquisa; não prova infecção atual, vulnerabilidade do PPC930 ou quebra geral de pagamentos contactless.
Da mesma forma, RAM scraping depende de dados sensíveis estarem acessíveis no processo comprometido. Não se deve assumir que o computador recebe PAN completo ou PIN em claro em toda arquitetura. A avaliação precisa mapear o fluxo real de dados e a solução de proteção implantada. Um ataque pode comprometer lógica de venda ou disponibilidade sem extrair informações criptográficas do dispositivo.
Falhas de estado merecem a mesma atenção que injeções: cabo desconectado durante a operação, timeout, callback atrasado e reinício do processo podem deixar pedidos pendentes. Reiniciar um serviço e observar a tela voltar não comprova reconciliação. O sistema precisa reconhecer a tentativa anterior, preservar o identificador e resolver o resultado antes de aceitar uma nova cobrança.
| Evento | Comportamento a verificar |
|---|---|
| Duplo clique em pagar | Uma intenção lógica e controle de concorrência |
| Timeout do integrador | Consulta de estado antes de repetir a operação |
| Queda do PDV | Recuperação de tentativas pendentes ao iniciar |
| Evento duplicado | Processamento idempotente |
| Cancelamento local | Estado confirmado no fluxo correspondente |
| Resposta tardia | Associação à tentativa correta, sem baixar outra venda |
| Perda de rede | Estado explícito de incerteza e reconciliação posterior |
Telemetria: como investigar o que aconteceu no caixa
Procure relações entre processo, arquivo, rede e operação comercial. Uma conexão desconhecida fica mais útil quando associada ao executável que a iniciou, ao horário de atualização e à sessão do operador. Um estorno sem trilha de autorização pode ser mais relevante que uma lista extensa de portas.
Com o Sysmon instalado e configurado, eventos de criação de processo, conexão de rede, carga de imagem e criação de arquivo ajudam nessa correlação. A disponibilidade depende da configuração: carga de imagem e conexões não devem ser presumidas habilitadas. A consulta abaixo lê eventos já existentes.
$inicio = (Get-Date).AddHours(-4)
Get-WinEvent -FilterHashtable @{
LogName = 'Microsoft-Windows-Sysmon/Operational'
StartTime = $inicio
Id = 1, 3, 7, 11
} -ErrorAction Stop |
Select-Object TimeCreated, Id, MessageAusência de evento pode significar ausência de coleta, retenção insuficiente ou filtro de configuração. Não é um atestado de ausência de ataque. Para o fluxo financeiro, registre identificador do pedido, tentativa, loja, estação, operação, decisão e código de resultado. Credenciais, PIN, CVV e trilhas de cartão não pertencem ao log de diagnóstico.
Nos requisitos de pagamento, diferencie a avaliação do dispositivo, do software e do ambiente. O PCI DSS trata da proteção de dados de conta; ter um periférico com certificações não substitui a análise de escopo da implantação. A configuração exata da solução e as responsabilidades dos participantes precisam ser consideradas.
Como transformar a análise em um relatório técnico útil
Descreva cada achado com o mínimo necessário para outra pessoa reproduzir e corrigir: versão, componente, identidade utilizada, entrada, resposta, estado antes e depois e condição de sucesso. Evite agrupar “PDV vulnerável” como se fosse uma descoberta única. O proprietário da correção pode ser o desenvolvedor do caixa, o integrador, a infraestrutura ou mais de uma equipe.
- Executável e versão do componente afetado identificados.
- Pré-condição demonstrada, sem transformar hipótese em fato.
- Requisição, comando ou código do teste preservado.
- Resposta e efeito no estado registrados com identificadores fictícios ou saneados.
- Impacto separado de comportamentos apenas operacionais.
- Correção proposta na fronteira de confiança responsável.
- Reteste com resultado esperado, incluindo falha e repetição.
- Fluxos de venda, cancelamento e recuperação verificados após a mudança.
Os testes locais deste artigo demonstram três problemas específicos: consulta SQL alterada por concatenação, leitura de pedido de outra loja e validação de conciliação com idempotência. Eles não são uma auditoria de hardware nem uma comprovação de falha em um produto comercial. A força de uma análise de Red Team está em transformar essas hipóteses em evidências dentro da arquitetura examinada.
Perguntas frequentes sobre segurança em PDV
Conectar um Gertec PPC930 protege o software do caixa?
O pinpad participa do processamento de pagamento, mas não valida automaticamente o cadastro de produtos, as permissões do operador ou a autorização da API do PDV. Avalie cada componente e o fluxo entre eles.
Um sistema PDV gratuito é menos seguro?
O preço não determina segurança. Procedência, manutenção, controles de acesso, integração de pagamentos e configuração da instalação são critérios verificáveis. Não há neste artigo um levantamento estatístico comparando produtos gratuitos e pagos.
Qual é o primeiro teste em um PDV Windows?
Inventariar software, serviços, contas, diretórios e interfaces. Esse mapa permite escolher testes específicos e reconhecer quando um resultado pertence ao PDV, ao integrador ou ao sistema operacional.
Um webhook basta para marcar uma venda como paga?
Somente quando sua origem, dados e semântica forem validados segundo o provedor e a política de conciliação. O processamento deve tolerar repetição, atraso e concorrência, além de conferir o vínculo com o pedido.
Referências técnicas
As referências estão vinculadas às seções correspondentes: Gertec para características do PPC930; OWASP para autorização e SQL injection; Banco Central para API Pix; Microsoft para inspeção e telemetria; MITRE para abuso de DLLs; Kaspersky para o caso histórico Prilex; PCI SSC para segurança de dados de pagamento. Os programas demonstrativos foram escritos para este artigo e usam somente dados fictícios.