-
Notifications
You must be signed in to change notification settings - Fork 371
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Sistema de Eventos + Firewall #444
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
Era alguma instabilidade no ci, agora foi |
Estou mesclando nesse PR a issue #338 e propondo a implementação de um novo model chamado Bom, o objetivo do Primeira regraA primeira regra está relacionada a um IP spammear a criação de contas. Mas o importante é notar que uma regra é disparada por um sinal e se isso acontecer, os efeitos colaterais são rodados:
Esses valores vão precisar de lapidação, mas por enquanto se um IP tentar criar mais de 5 contas dentro da mesma hora, a request é bloqueada e todos os usuários criados dentro das últimas 6 horas por aquele ip são bloqueados. Isso vai ser bastante útil quando alguém tentar fazer um ataque contra os conteúdos (seja de sacanagem, seja para gerar tabcoins) e ter como efeito colateral todos esses conteúdos removidos (ou colocados como ProblemaO sistema parece estar funcionando, tanto que os testes automatizados não passam mais na parte de criar usuários. O Alguém tem alguma sugestão? |
models/firewall.js
Outdated
throw new TooManyRequestsError({ | ||
message: 'Você está tentando criar muitos usuários.', | ||
action: | ||
'Todos os usuários criados recentemente foram bloqueados. Contate o suporte caso acredite que isso é um erro.', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eu não daria tanta informação sobre a regra infringida, principalmente por esses motivos:
- Caso seja alguém tentando burlar o sistema, ele receberá muitas dicas de como obter sucesso.
- Caso seja um grupo de pessoas com o mesmo IP público que, por qualquer motivo, tenham se cadastrado ao mesmo tempo, por exemplo ao assistirem a live de algum famoso por aí, pode ser considerado uma quebra de privacidade se alguém desse grupo de pessoas receber essa mensagem.
|
Perfeito! 😍 Vou juntar essa sugestão com aquela feita no código e tentar esconder ao máximo esses valores e regras.
De fato todo mundo seria bloqueado de forma errada. Mas fiquei curioso: como que isso é considerada uma quebra de privacidade? |
Imagina uma empresa pequena com um chefe e 5 funcionários. 🤔 O chefe trancado na sua sala nem imagina que os funcionários na sala ao lado também estão matando serviço para assistir o novo vídeo em que Filipe Deschamps fala do TabNews. 🤯 Ele resolve se cadastrar e recebe como retorno a informação de que está tentando criar muitos usuários. 🤨 Automaticamente descobre que não é o único fã do Filipe matando serviço naquele momento 😡 |
ahahah sensacional! De fato, mas isso se aplica a qualquer rate limiting de ip, por exemplo no escritório do Pagar.me um dia do nada minhas buscas no Google foram bloqueadas. O Google retornava uma mensagem de erro por abuso... na verdade a empresa inteira ficou travada de usar o Google. O que tinha acontecido é que um dos desenvolvedores tinha feito um script que marretou o buscador usando a interface dele pra tentar burlar o rate limiting da API 😂 Por isso que precisaremos ir calibrando os valores, principalmente quando tivermos rate limiting na camada da rede. De qualquer forma @aprendendofelipe refiz toda a implementação do
O que acha? |
Deixando uma nota rápida O IP é considerando um dado privado ao abrigo da LGPD. Guardar ele no banco não é aconselhado. ver K-anonymity |
@tcarreira que informação valiosíssima! Principalmente porque queremos que a lista de eventos seja pública para as pessoas conseguirem analisar os dados (no caso do fluxo das tabcoins, tentar identificar algum abuso) 🤝 |
@filipedeschamps, acho incrível que você consegue sempre ir muito além do que lhe é proposto. Com stored procedure ficou perfeito! 😍
É isso! Assim a pessoa pode saber que caiu na regra, mas não vai ter como saber exatamente qual é a regra. Obs. Acho que a função
@tcarreira boa!!! |
Pensando em LGPD, vai ser preciso mascarar o id dos usuários na lista de eventos, pois, da maneira como está, mesmo que o IP fique mascarado, vai ser possível criar um vínculo entre usuários que acessam do mesmo IP. Ou seja, vai se tornar pública a informação de que Fulano e Beltrano utilizam o mesmo IP público, mesmo sem divulgar qual é esse IP. Mascarando o id, então só vai ser possível saber que existem N diferentes usuários no mesmo IP, mas sem identificar quais são os usuários. |
@aprendendofelipe muito bem observado! Era da estratégia anterior, vou remover 🤝
Ahhhh vocês são demaaaaais 😍 a gente pode fazer o id ser filtrado na saída, mas o IP seria legal gravar no banco já mascarado. Alguém conhece algum módulo que implemente o K-anonymity? Não to encontrando nada :( ou qualquer outra alternativa segura. |
Precisamos tratar algumas coisas diferentes: como salvar os eventos no banco de maneira que sejam úteis (o requisito para o firewall, para gerar a página de eventos e para fornecimento de informações para autoridades podem ser diferentes) e como divulgar os dados de maneira anonimizada na página de eventos. FirewallPara o firewall, não é muito interessante usar a estratégia de juntar vários endereços em um único grupo, que é o que o Google Analytics faz. Pois isso obrigaria a adotar limites menos restritos para eventos repetidos com o mesmo grupo de IPs. E como vimos que não adianta muito usar um hash, talvez seja o caso de salvar o endereço explicitamente mesmo e excluí-lo após o período em que ele não é mais necessário para o firewall. Informações para AutoridadesPara fornecer infos para as autoridades, vale quase o mesmo que para o firewall, só que com um prazo bem maior de período de armazenagem dos endereços. Página pública com os eventosSó pode conter dados anonimizados. Para montar uma página com informações anonimizadas de início pode ser utilizada a estratégia de K-anonymity manipulando os dados no momento da geração da página estática (ou na API) enquanto não se tornar um caso para Big Data em que os dados devem ser armazenados já tratados. Só que aqui a preocupação não deve ser só com o IP, mas sim em como apresentar os dados respeitando as leis de proteção de dados. No caso do IP, aí sim entraria a estratégia de unificar grupos de endereços, mas precisamos pensar mais sobre como anonimizar os outros dados que serão disponibilizados nessa página. ResumindoNão vejo problema em armazenar os dados da maneira que foi implementada. Existindo justificativa para isso (e existem), deixando transparente e pedindo autorização dos usuários, acho que estará tudo certo com a LGPD. Futuramente pode-se pensar em eliminar os dados antigos que não serão mais necessários. Agora sobre a divulgação dos dados, acho que é preciso pensar muito mais como vai ser... [Edit] Quando falei sobre não ver problema sobre a maneira que foi implementado, ainda estava sendo armazenado o endereço explicitamente. E reforço que não vejo problema, pois é justificável. O que não pode é divulgar assim. |
Sensacional sua resposta @aprendendofelipe ! Super completa 🤝 Do meu lado, após ler os últimos links e vários outros que não mandei aqui, fazer o Em paralelo, eu fiz o push com um commit que zera o último bloco do ip, o snippet é esse: const ipParts = ip.split('.');
ipParts[3] = '0';
const anonymizedIp = ipParts.join('.');
return anonymizedIp; Fico me perguntando se teremos problemas reais (ou recorrentes) ao agrupar os ips e ajustarmos as regras do firewall, e se algum dia tivermos um falso positivo, não seria interessante implementar um comando de desfazer o que o firewall fez? |
Poderíamos implementar que apenas usuários com X feature poderiam ver os dados exatos, como a hora. O resto dos usuários poderiam ver a hora, mas em um range de horário. Ex.: um usuário publicou/editou um post/comentário entre 15:00 e 16:00 Até poderiam ter diferentes opções de privacidade, como se o usuário quer mostrar seu nome para todos ou não, e só moderadores ou pessoas com a feature X poderiam ver quem realmente fez aquilo e "bypassar" as opções de privacidade do usuário. |
Então, eu não sei de nenhum módulo que faça isso. Mas eu faria desta forma (pseudo código)
(onde A mim, parece-me uma solução bastante segura e irreversível. Pontos de segurança com este algoritmo:
Fraquezas:
Acho que as fraquezas não são preocupantes. Qualquer admin de sistema pode eventualmente ter acesso à RAM e encontrar qualquer informação privada :) |
O único porém é se tiver que fornecer o IP de algum evento para alguma autoridade. Deixaria em uma lista de tarefas a consulta com algum especialista sobre quando o TabNews se enquadraria nisso. Sei que tem questões bem recentes, que envolvem inclusive o período eleitoral que está chegando, mas não estou por dentro.
Com o monitoramento, o tempo dirá! 🤓
Com certeza! Isso precisa ser implementado antes do lançamento do TabNews. E isso levanta uma questão. Está sendo gerado um evento que registre o bloqueio pelo firewall? Me parece que não, pois não vai chegar no É preciso registrar de maneira que fique fácil a reversão. E alertas devem chegar bem rápido para quem tiver esse poder de desfazer. Está usando o Logflare, né? |
@tcarreira show!! Confesso que não entendi muito bem a implementação, mas de tudo que li sobre hash (dado que o range de IP válidos é pequeno), todos são reversíveis. A única forma de deixar anônimo pelo que entendi é o salt variar a cada evento, mas isso invalida o uso dele para o firewall. Outra forma seria o bcrypt, daí você usa um tamanho de salt que inviabiliza a operação pelo poder de computação que vai tomar, mas que também vai penalizar o registro do evento.
@aprendendofelipe justo 🤝
Não está sendo gerado, vou ver uma forma de retornar da função os usuários penalizados pelo efeito colateral e daí colocar todos eles num único payload de evento do firewall.
Hoje estou usando apenas o Axiom: https://www.tabnews.com.br/filipedeschamps/axiom-melhor-servico-de-logs-que-encontrei-ate-agora-para-vercel E vou cadastrar para ele me alertar de qualquer
Ideia interessante @joaogelado 🤝 poderíamos talvez ter pessoas de BI com uma feature em que consigam ver os dados de forma mais detalhada 👍 Sugiro então darmos sequência da seguinte forma:
E turma, que conversa de altíssimo nível!!! Vocês são sen-sa-ci-o-nais!!!!! |
Não sou especialista legal, mas não acho que seja obrigatório guardar o IP do que quer que seja (até porque isso é um dado privado). Não estaremos confundindo o cenário em que vc tem que fornecer esses dados porque vc os tem guardados? eg: "a autoridade obriga vc a devolver todas as armas que vc tem". Vc não entrega nada porque não tem. 🤷 estaremos complicando demasiado este assunto? |
Comentei um pouco o código no meu comentário para se entender melhor, mas a parte complicada do meio serve para dar um salt diferente a cada IP. Mas acho que vale as perguntas:
|
Com uma rápida pesquisada na LGPD, acredito que temos uma alternativa bem válida para criar um firewall dentro das normas. DADOS ANONIMIZADOSSe a lista de IPs não tiver nenhuma relação com os usuários, podemos manter isso em banco de dados trabalhar esses dados de forma anonimizadas por exemplo: Resumindo uma forma de trabalhar o firewall dentro das normas da LGPD. Fonte: https://www.serpro.gov.br/lgpd/menu/protecao-de-dados/dados-anonimizados-lgpd Edit: O @aprendendofelipe já tinha comentando sobre isso, não existe problema em ter essa lista de IPs se não temos vinculo direto ao usuário. |
O TabNews seria 1/10 do que é sem a participação de vocês!!! Olha quanta informação de valor concreto estamos colocando nesse PR!!! Muito muito bom e isso está lapidando a feature de uma forma que eu não imaginava 😍😍😍
@tcarreira ótimas perguntas!!! Começando pela última pergunta e vou dar primeiro minha resposta de médio prazo, depois de curto prazo: hoje o TabNews já foi atacado 3 vezes (sendo que a última foi por falha numa integração que alguém estava fazendo), mas nenhum desses ataques foi de conteúdo, por enquanto. Reforço o por enquanto, pois hoje não existe incentivo que existirá com as TabCoins e TabCash. Fazer o spam de conteúdo vai ser literalmente minerar valor (espaço nos anúncios). Então minha sugestão é colocarmos em prática todo tipo de abordagem e ir desenvolvendo uma maestria nelas, nem que essa maestria seja jogar a abordagem fora. Essa foi a visão de médio prazo, mas a de curto prazo é essa: hoje, ao criar uma conta nós enviamos um email, e ao responder um comentário, também enviamos um email. Então por exemplo se alguém atacar a criação de contas, nós enviaremos um mar de emails e nosso domínio poderá ser barrado pelos provedores de email (ainda pior se alguém usar emails que não existem). Da mesma forma, se alguém criar um monte de respostas, iremos enviar um mar de emails similares. Então esse é um tipo de situação que acho válido especular, pois é um tipo de problema que nós não gostaríamos de ter que resolver. Ter o domínio marcado como spam será desastroso para o projeto, mesmo que isso seja consertado, pois durante o tempo que estivermos marcados, ninguém vai conseguir ativar a conta. Isso é tão sensível que isso já aconteceu, mas não por nossa culpa, foi na época que usamos o Sendgrid e eles estavam com um IP barrado pela Microsoft. IP muda, domínio não. Então novamente, na minha visão vale a pena especular, nem que seja um pouco. Sobre CAPTCHA, eu gosto bastante, mas levanto para discussão dois pontos:
Mas mesmo assim continuo achando válido, pois vira uma briga de saldo, onde se todas as dificuldades técnicas (mesmo sendo burláveis), causam um saldo negativo (você gasta mais do que ganha), não há incentivo para o ataque. Então acho que vai se tornar uma situação da briga eterna entre gato e rato, mas defendo que já é bom entrarmos nesse jogo agora.
Show @rodrigoKulb nosso problema é que temos 100% de vínculo com o usuário, inclusive "os usuários" por conta do efeito colateral de deletar todas as contas criadas por aquele IP. Ou todos os conteúdos de todas as contas que foram marcadas como abuso. Mas com a idéia de não anotar o IP exato (que é mascarando o último valor como o Google Analytics faz), não estamos anotando a informação do usuário individual. E novamente, olha o nível de responsabilidade que estamos tendo com o TabNews!!! Por favor, nunca podemos deixar de ter esse carinho com o projeto 🤝 |
Agora pelo commit 8d091b2 o {
type: 'firewall:blocked_users',
originatorUserId: undefined,
originatorIp: '127.0.0.0',
metadata: {
users: [
'b809e72f-e6b5-4724-817c-2e0802750002',
'0d999f2e-9406-45df-b26a-d0536ba03d97'
]
}
} Então mais para frente poderemos fazer aquele comando de desfazer o efeito colateral. Isso está coberto com testes, inclusive verificando se criou o evento adicional do [edit] To pensando aqui numa segunda versão do evento de bloqueio: {
type: 'firewall:users_blocked',
originatorUserId: context.user.id,
originatorIp: context.clientIp,
metadata: {
from_rule: 'create:user',
users: usersAffected,
},
} |
…ent:text_child` rules
O commit b135bf0 implementa as regras contra abuso em Achei mais responsável deixar como E o fluxo para tudo isso até certo ponto está simples:
E no futuro não somente o |
…e row in the database
Turma, vou começar o deploy em homologação (o app já está deployado pela Vercel, falta rodar as migrations e criar as stored procedures) 👍 |
Pessoal, fiz os testes das 3 regras em ambiente de homologação (spam de Vou passar para produção 👍 |
Turma, vocês foram citados no post comemorativo: https://www.tabnews.com.br/filipedeschamps/novas-melhorias-husky-sistema-de-eventos-firewall-e-melhorias-no-seo 🎉 |
Dando os primeiros passos na issue #351, este PR implementa um novo model
event
que registra eventos de negócio, junto com o ip originador e alguns metadados.Por hora há dois tipos de eventos:
create:user
ecreate:content
.A interface para criar um evento é a seguinte:
Resulta em:
Todos os campos são validados usando o
validator
e a estrutura a ser validada dometadata
dependerá dotype
fornecido. Por hora, para ambos eu coloquei oid
do objeto gerado. Quando existir outros eventos como os de transferência detabcoins
, ometadata
poderá conter coisas comoamount
,from
,to
e coisas assim. E agora revisando, talvez o campooriginator_id
fique melhor comooriginator_user_id
.De qualquer forma, com esses dados (principalmente o
ip
), conseguimos dar início a issue #338 sobre comportamentos abusivos (mesmo ip criando várias contas, ou várias publicações), e logo depois também a issue #352 sobre as tabcoins.Em paralelo, refatorei o
controller.js
e os controllers para ter um método de nome mais genérico e que sirva para injetar na request outras coisas além dorequestId
. Então agora é injetado norequest.context
oclientIp
.