Atualmente, os serviços da Web são constantemente expostos a uma variedade de ataques. Portanto, a segurança é algo a ser lembrado em todas as etapas do ciclo de vida do projeto. Os autores do material, cuja tradução publicamos hoje, mantêm um
repositório no GitHub contendo cerca de 80 recomendações para proteger aplicativos em execução na plataforma Node.js. Este material, com base em muitas publicações de segurança, possui mais de duas dúzias de recomendações sobre o Node.js e algumas dicas gerais. Além disso, este material cobre as 10 principais vulnerabilidades da lista do projeto OWASP.

1. Use as regras para o linter, destinadas a verificar a segurança do código
Recomendações
Durante o desenvolvimento, use um plug-in orientado à segurança para o linter, como
eslint-plugin-security . Isso permite que você identifique vulnerabilidades e problemas de segurança muito cedo - na hora de escrever o código apropriado. Essa abordagem ajuda a encontrar pontos fracos na segurança do programa. Entre eles estão o uso do comando
eval
, a invocação de processos filhos, a importação de módulos com a transferência para o comando correspondente de algo diferente de uma string literal (digamos, uma certa string formada com base nos dados transmitidos ao servidor pelo usuário).
→
Aqui estão alguns materiais úteis sobre regras de linter
Adam Baldwin diz o seguinte sobre o linting: “O Linter não deve ser apenas uma ferramenta que segue meticulosamente as regras relativas ao número de espaços usados, ponto e vírgula e o uso do comando eval. O ESLint fornece ao desenvolvedor uma plataforma poderosa que pode detectar e eliminar uma ampla variedade de padrões potencialmente perigosos no código. Estamos falando, por exemplo, sobre expressões regulares, sobre como verificar a entrada do usuário e assim por diante. Acredito que o linter oferece aos desenvolvedores preocupados com questões de segurança uma nova e poderosa ferramenta que vale a pena prestar atenção. ”
Possíveis problemas
O que parece uma falha de segurança menor durante o desenvolvimento está se tornando uma séria vulnerabilidade na produção. Além disso, se todos os desenvolvedores do projeto não seguirem regras uniformes de segurança ao trabalhar com código, isso poderá levar a vulnerabilidades ou, por exemplo, à penetração de dados confidenciais em repositórios públicos.
2. Limite o número de solicitações simultâneas do servidor
Recomendações
Os ataques de DoS são muito populares entre os cibercriminosos e são relativamente fáceis de realizar. Você pode implementar um sistema para limitar o número de solicitações a um aplicativo usando um serviço externo, como um balanceador de carga na nuvem, um firewall na nuvem, um servidor nginx ou, para aplicativos pequenos que não são críticos, usando o middleware para limitar o número de solicitações, como
taxa expressa -limite .
→
Aqui está o material sobre a implementação do sistema para limitar a frequência de solicitações ao servidor
Possíveis problemas
Um aplicativo que não fornece um sistema para limitar o número de solicitações simultâneas pode ser atacado, o que levará à falha. Isso é expresso no fato de que os usuários de um aplicativo têm dificuldade em trabalhar com ele ou não conseguem interagir com ele.
3. Remova as informações confidenciais dos arquivos de configuração ou criptografe-os
Recomendações
Nunca armazene dados confidenciais em texto sem formatação nos arquivos de configuração ou no código. Em vez disso, use sistemas de gerenciamento de dados confidenciais, como produtos Vault ou sistemas Kubernetes / Docker Secrets, ou use variáveis de ambiente para armazenar esses dados. Os dados confidenciais armazenados no sistema de controle de versão devem ser criptografados, medidas devem ser tomadas para armazenamento e uso seguros. Entre essas medidas estão o uso de chaves dinâmicas, o uso de datas de expiração de senha, auditorias de segurança e assim por diante. Use sistemas para verificar o código antes de confirmar ou antes de enviá-lo ao repositório para impedir o envio acidental de dados confidenciais ao repositório público.
→
Aqui está o material sobre o gerenciamento de dados confidenciais
Possíveis problemas
Mesmo se o código for armazenado em um repositório fechado, um dia, por engano, ele poderá se tornar disponível ao público. Neste ponto, todos os dados confidenciais armazenados nele se tornarão de domínio público. Como resultado, o acesso de terceiros ao repositório com o código inadvertidamente fará com que eles obtenham acesso aos sistemas associados a ele (bancos de dados, APIs, serviços e assim por diante).
4. Evite vulnerabilidades de injeção de código
Recomendações
Para evitar injeções de SQL / NoSQL e outros ataques similares, sempre use as bibliotecas ORM / ODM ou mecanismos DBMS para limpeza de dados ou suporte a consultas parametrizadas nomeadas ou indexadas e verifique o que está vindo do usuário. Nunca use, para incorporar certos valores nos textos de consulta, apenas sequências JavaScript de modelo ou concatenação de sequências, pois essa abordagem abre seu aplicativo para uma ampla variedade de vulnerabilidades. Todas as bibliotecas respeitáveis do Node.js usadas para trabalhar com dados (por exemplo,
Sequelize ,
Knex ,
mangusto ) contêm proteção
interna contra ataques
injetando código.
→
Aqui está o material sobre prevenção de injeção usando bibliotecas ORM / ODM
Possíveis problemas
O uso de dados não verificados e não limpos, recebidos do usuário em consultas, pode levar a um ataque ao introduzir um operador ao trabalhar com um banco de dados NoSQL, como o MongoDB. Se você não usar um sistema de limpeza de dados ou uma biblioteca ORM ao trabalhar com um banco de dados SQL, isso levará à possibilidade de um ataque por injeção SQL, o que cria uma enorme falha de segurança no aplicativo.
5. Evite ataques DoS definindo explicitamente as condições para o término anormal do processo
Recomendações
O processo do nó falha quando ocorre um erro não tratado. Porém, em muitas recomendações que refletem as práticas recomendadas para o Nó, é recomendável que os processos sejam finalizados mesmo quando um erro foi interceptado e processado. Express, por exemplo, falhará quando ocorrer algum erro assíncrono - a menos que as rotas sejam agrupadas em expressões de
catch
. Esse fato oferece aos atacantes uma oportunidade muito atraente. Eles, tendo descoberto que quando uma certa solicitação chega, o processo falha, começam a enviar exatamente essas solicitações para ele. Não há recomendação que resolva esse problema de uma só vez; no entanto, alguns truques podem atenuá-lo. Portanto, no final do processo devido a um erro não tratado, você precisa notificar o administrador, dando a essa notificação a maior prioridade de importância. É necessário verificar o que ocorre com o processo nas solicitações e evitar situações de encerramento anormal do processo devido a solicitações que, acidental ou intencionalmente, são formadas incorretamente. Todas as rotas devem ser agrupadas em expressões de
catch
e o sistema deve ser configurado para que, se a causa do erro for uma solicitação, o processo não travar (ao contrário do que acontece no nível do aplicativo global).
Possíveis problemas
Vamos analisar a seguinte situação. Existem muitos aplicativos Node.js. O que acontece se começarmos a enviar solicitações POST com JSON vazio como o corpo da solicitação? Isso fará com que muitos desses aplicativos falhem.
Agora, se desempenharmos o papel de cibercriminosos, para impedir que os aplicativos falhem, seria suficiente continuar enviando solicitações semelhantes.
6. Configure os cabeçalhos de resposta HTTP para aumentar a segurança do projeto
Recomendações
Um aplicativo deve usar cabeçalhos HTTP orientados à segurança para impedir que os invasores recorram a técnicas comuns de ataque como XSS (cross-site scripting), clickjacking e outros. É fácil personalizar os cabeçalhos usando módulos especiais, como
capacete .
→
Aqui está o material sobre o uso de cabeçalhos seguros
Possíveis problemas
Se não forem usados cabeçalhos HTTP seguros, os invasores poderão realizar ataques aos usuários de seus aplicativos, o que gera enormes vulnerabilidades.
7. Verifique contínua e automaticamente seus projetos quanto ao uso de dependências vulneráveis.
Recomendações
No ecossistema NPM, projetos com muitas dependências são muito comuns. As dependências devem sempre ser controladas, dada a descoberta de novas vulnerabilidades. Use ferramentas como
auditoria npm ,
nsp ou
snyk para detectar, monitorar e corrigir dependências vulneráveis. Incorpore essas ferramentas ao seu sistema de integração contínua. Isso permitirá que você detecte dependências vulneráveis antes que elas entrem em produção.
→
Aqui está o material sobre segurança de dependência do projeto
Possíveis problemas
Um invasor pode determinar a estrutura da web usada no projeto e executar ataques a todas as vulnerabilidades conhecidas.
8. Tente não usar o módulo criptográfico padrão Node.js. para processamento de senha, use Bcrypt
Recomendações
As senhas ou outros dados confidenciais (chaves de API, por exemplo) devem ser armazenados processando-os com funções criptográficas usando "salt", como Bcrypt. Vale a pena usar exatamente algo semelhante, e não o módulo
crypto
padrão do Node.js. por razões de segurança e desempenho.
→
Aqui está o material sobre o Bcrypt
Possíveis problemas
As senhas ou alguns dados confidenciais armazenados sem a aplicação de medidas apropriadas para protegê-los são vulneráveis a ataques de força bruta e ataques de dicionário, que, como resultado, levam à divulgação desses dados.
9. Use sistemas de escape de caracteres em dados HTML, JS e CSS enviados ao usuário
Recomendações
Se alguns dados são enviados para o navegador do usuário a partir de uma fonte não confiável, mesmo que devam ser exibidos simplesmente, esses dados podem ser um código que pode ser executado. Isso geralmente é chamado de script entre sites (XSS). Você pode reduzir o risco de tais ataques serem possíveis usando bibliotecas especiais que processam dados para que não possam ser executados. Isso é chamado de codificação ou proteção de dados.
→
Aqui está o material sobre a proteção da saída
Possíveis problemas
Se você não se importa com a proteção de dados, um invasor pode, por exemplo, salvar código JavaScript malicioso no banco de dados, que pode ser transmitido aos clientes inalterados e iniciados.
10. Verifique os dados JSON que chegam ao servidor
Recomendações
Controle o conteúdo dos corpos das solicitações recebidas, verificando se elas correspondem ao que você espera ver em tais solicitações. Se a solicitação não parecer como o esperado, pare rapidamente de processá-la. Para evitar a operação demorada do código de verificação de solicitação de gravação para cada rota, você pode usar ferramentas JSON leves para validação de dados, como
jsonschema ou
joi .
→
Aqui está o material sobre a verificação de dados JSON recebidos
Possíveis problemas
Se o servidor aceitar solicitações cordialmente sem examiná-las completamente, isso aumentará bastante a superfície de ataque do aplicativo e inspirará os invasores a tentar encontrar muitos deles que causam uma "falha" do sistema.
11. Manter tokens JWT na lista negra
Recomendações
Ao usar tokens JWT (por exemplo, se você trabalha com
Passport.js ), por padrão, não há mecanismo padrão para revogar privilégios de acesso ao sistema para tokens já emitidos. Mesmo se você achar que um determinado usuário está fazendo algo obviamente anormal, não há como, através do mecanismo do token, bloquear seu acesso ao sistema, desde que ele tenha um token válido. Esse problema pode ser atenuado com a implementação de uma lista negra de tokens não confiáveis, cuja validação é realizada em cada solicitação.
→
Aqui está o material sobre os tokens JWT na lista negra
Possíveis problemas
Tokens que caem nas mãos erradas podem ser usados por um atacante. Ele poderá acessar o aplicativo e se passar por um usuário comum - o proprietário do token.
12. Limite o número de tentativas de login
Recomendações
Em aplicativos baseados em express, para proteger contra ataques de força bruta e ataques de dicionário, vale a pena usar o middleware apropriado, como
express-brute . Da mesma forma, você precisa proteger rotas críticas como
/admin
ou
/login
. A proteção deve se basear na análise das propriedades da consulta, como o nome de usuário usado na consulta ou outros identificadores, como parâmetros do corpo da consulta.
→
Aqui está o material para limitar o número de tentativas de login
Possíveis problemas
Se o aplicativo não limitar o número de tentativas de login, o invasor poderá enviar automaticamente um número ilimitado de solicitações de login para o seu sistema, por exemplo, tentando obter acesso a uma conta privilegiada.
13. Execute o Node.js como um usuário não raiz
Recomendações
Um cenário extremamente comum é quando o Node.js é executado como um usuário root com privilégios ilimitados. Por exemplo, é assim que tudo é configurado por padrão nos contêineres do Docker. É recomendável criar um usuário que não tenha privilégios de root e incorporá-lo à imagem do Docker ou iniciar o processo em nome desse usuário chamando o contêiner com o sinalizador
-u username
.
→
Aqui está o material sobre o lançamento do Node.js como um usuário não raiz
Possíveis problemas
Se o Node.js for executado na conta de usuário raiz, um invasor que foi capaz de executar um script no servidor terá possibilidades ilimitadas na máquina local. Digamos que ele possa alterar
iptable
configurações do
iptable
e redirecionar o tráfego para seu próprio computador.
14. Limite a quantidade de dados transmitidos em solicitações usando um servidor proxy reverso ou middleware
Recomendações
Quanto maior a quantidade de dados no corpo da solicitação, mais difícil é para um servidor de thread único processar tal solicitação. O uso de solicitações grandes oferece ao invasor a oportunidade de inundar o servidor com trabalho desnecessário sem enviar a ele um grande número de solicitações (ou seja, sem executar um ataque DoS / DDoS). Você pode reduzir o risco de tais ataques limitando o tamanho dos corpos das solicitações recebidas em um determinado sistema de borda (em um firewall ou em um balanceador de carga) ou configurando o
body-parser express para receber apenas pacotes contendo uma pequena quantidade de dados.
→
Aqui está o material sobre como limitar a quantidade de dados transmitidos nas solicitações
Possíveis problemas
Se você não limitar a quantidade de dados transmitidos nas solicitações, um invasor poderá carregar o aplicativo processando solicitações grandes. No momento, ele não poderá resolver as tarefas para as quais foi projetado. Isso leva a um desempenho ruim e torna o aplicativo vulnerável a ataques de DoS.
15. Evite usar a função eval em JavaScript
Recomendações
A função
eval
é inválida porque permite executar código JS arbitrário passado a ele durante a execução do programa. Além disso, está longe de ser apenas que esse código possa retardar o aplicativo. Essa função representa um sério risco à segurança, pois o código JS mal-intencionado enviado ao servidor por um invasor pode entrar nele.
Além disso, você deve evitar o
new Function
construtor
new Function
. As funções
setTimeout
e
setInterval
nunca precisam passar o código JS gerado dinamicamente.
→
Aqui estão as coisas sobre eval
Possíveis problemas
Se alguém encontrar uma maneira de transferir código JS malicioso, na forma de texto, uma função de avaliação ou algum outro mecanismo JS semelhante, ele terá acesso total à página, a tudo o que pode ser feito usando JavaScript. Essa vulnerabilidade é frequentemente associada a ataques XSS.
16. Não sobrecarregue aplicativos Node.js. de thread único com expressões regulares maliciosas
Recomendações
As expressões regulares, embora convenientes, representam uma ameaça para aplicativos JavaScript em geral, e em particular para a plataforma Node.js. Processar com expressão regular o que veio do usuário pode criar uma enorme carga no processador. Por exemplo, o processamento de expressões regulares pode ser tão ineficiente que a verificação de dez palavras pode bloquear o ciclo de eventos por vários segundos e sobrecarregar o processador. Portanto, é melhor usar pacotes de terceiros para verificar os dados da string, como
validator.js , em vez de escrever suas próprias expressões regulares. Você pode usar o pacote
safe-regex para detectar padrões de
regex vulneráveis.
→
Aqui está o material regex anti-malware
Possíveis problemas
Expressões regulares mal escritas podem estar sujeitas a um tipo especial de ataques DoS, durante os quais o loop de eventos é completamente bloqueado. Por exemplo, em novembro de 2017, foi descoberto que o pacote de
moment
popular estava vulnerável a esses ataques.
17. Evite carregar módulos usando variáveis
Recomendações
Evite importar arquivos cujo caminho seja especificado como parâmetro, com base em considerações segundo as quais esse parâmetro pode ser definido com base nos dados do usuário. Essa regra pode ser expandida para incluir aqui e, em geral, acesso a arquivos (usando
fs.readFile()
) e acesso a quaisquer outros recursos importantes usando parâmetros recebidos do usuário. O uso de
eslint-plugin-security torna possível detectar esses padrões inseguros muito cedo.
→
Aqui está o material sobre o carregamento seguro do módulo
Possíveis problemas
Os dados enviados ao servidor por um invasor podem estar nas configurações responsáveis pela importação de certos arquivos, entre os quais um arquivo malicioso que foi carregado anteriormente no servidor. Esses dados também podem ser usados para acessar arquivos do sistema que já estão no computador.
18.
, (, ), «», . , (
cluster.fork()
), npm-, .
→
, , . — , , , .
19.
, , . , , , .
child_process.execFile
, , , , , .
→
,
, , , , .
20.
express, , . , , ,
Error
( ). , , , - , .
→
, , , , , , .
21. npm Yarn
, -, (MFA, multi-factor authentication). npm Yarn , . , , , . , . , , npm, .
, ?
eslint, .
22. ,
- . , — , - . , ,
X-Powered-By
, , . , ( , , Node.js express).
→
-
- . , , -, — . .
23.
, . — , Node.js.
,
OWASP .
- root- .
- ( SSH-).
- , , , . OWASP, .
- , . , .
- OAuth, OpenID, . Basic Authentication.
- . , ( — ), X , Y .
- — , — . , .
- , , . ( — GitHub, AWS, Jenkins, ).
Sumário
. , Node.js-.
Caros leitores! -, ?
