{"id":2336,"date":"2026-08-20T14:24:26","date_gmt":"2026-08-20T17:24:26","guid":{"rendered":"https:\/\/desvendandoocodigo.com.br\/?p=2336"},"modified":"2026-08-20T14:32:21","modified_gmt":"2026-08-20T17:32:21","slug":"seguranca-em-api-rest-com-node-js-e-express-boas-praticas-no-backend","status":"publish","type":"post","link":"https:\/\/desvendandoocodigo.com.br\/?p=2336","title":{"rendered":"Seguran\u00e7a em API REST com Node.js e Express: Boas Pr\u00e1ticas no Backend"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Criar uma <strong>API REST com Node.js e Express<\/strong> que funciona \u00e9 apenas uma parte do desenvolvimento de uma aplica\u00e7\u00e3o.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">O servidor pode iniciar corretamente, as rotas podem responder, o login pode funcionar e os dados podem chegar ao <strong>Backend<\/strong> sem nenhum problema.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Mas isso n\u00e3o significa que sua API esteja segura.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Uma informa\u00e7\u00e3o sens\u00edvel exposta no c\u00f3digo, uma senha armazenada de maneira inadequada, a falta de valida\u00e7\u00e3o ou at\u00e9 uma mensagem de erro detalhada demais podem criar problemas de <strong>seguran\u00e7a<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Foi exatamente esse o ponto de partida desta aula: come\u00e7amos analisando uma <strong>API REST que funciona, mas possui problemas de seguran\u00e7a<\/strong>, e depois fomos corrigindo esses pontos utilizando <strong>Node.js e Express<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Neste artigo, voc\u00ea vai entender algumas boas pr\u00e1ticas importantes de <strong>seguran\u00e7a no Backend<\/strong>, trabalhando conceitos como:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>vari\u00e1veis de ambiente;<\/li>\n\n\n\n<li>prote\u00e7\u00e3o de senhas com bcrypt;<\/li>\n\n\n\n<li>valida\u00e7\u00e3o dos dados;<\/li>\n\n\n\n<li>autentica\u00e7\u00e3o;<\/li>\n\n\n\n<li>Async\/Await;<\/li>\n\n\n\n<li>Try\/Catch;<\/li>\n\n\n\n<li>c\u00f3digos HTTP 400, 401 e 500;<\/li>\n\n\n\n<li>logs;<\/li>\n\n\n\n<li>JWT;<\/li>\n\n\n\n<li>tratamento seguro de erros.<\/li>\n<\/ul>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Importante:<\/strong> seguran\u00e7a de aplica\u00e7\u00f5es \u00e9 um assunto muito maior do que conseguimos abordar em uma \u00fanica aula. O objetivo aqui \u00e9 construir uma base pr\u00e1tica para quem est\u00e1 come\u00e7ando a desenvolver APIs.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Uma API funcionando pode continuar insegura<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Imagine que voc\u00ea criou uma <strong>API REST<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Voc\u00ea inicia o servidor e tudo funciona.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">O login responde.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As informa\u00e7\u00f5es chegam corretamente.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Nenhum erro aparece.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">S\u00f3 que, ao analisar o c\u00f3digo, encontramos situa\u00e7\u00f5es como:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">constSECRET='minha_chave_secreta';constusuario= {    email: 'usuario@email.com',    senha: '123456'};<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Al\u00e9m disso, a aplica\u00e7\u00e3o pode estar respondendo:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Usu\u00e1rio n\u00e3o encontrado<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">ou:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Senha incorreta<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">E, quando acontece algum problema interno:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Erro ao acessar determinado arquivo...<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A aplica\u00e7\u00e3o funciona, mas estamos expondo informa\u00e7\u00f5es desnecess\u00e1rias.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Foi justamente esse cen\u00e1rio que analisamos no in\u00edcio da aula: segredo exposto, senha sem o tratamento adequado, falta de valida\u00e7\u00e3o e mensagens que poderiam fornecer informa\u00e7\u00f5es demais para quem utiliza a API.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Essa \u00e9 uma das primeiras ideias que precisamos entender:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Uma API funcionar n\u00e3o significa que ela esteja segura.<\/strong><\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">1. N\u00e3o deixe informa\u00e7\u00f5es sens\u00edveis no c\u00f3digo<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Uma das primeiras melhorias relacionadas \u00e0 <strong>seguran\u00e7a no Backend<\/strong> \u00e9 separar informa\u00e7\u00f5es sens\u00edveis da l\u00f3gica principal da aplica\u00e7\u00e3o.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Em vez de fazer:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">constJWT_SECRET='minha_chave_secreta';<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">podemos utilizar <strong>vari\u00e1veis de ambiente<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Para isso, podemos ter um arquivo <code>.env<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">PORT=3000JWT_SECRET=minha_chave_secreta<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">E acessar essas informa\u00e7\u00f5es no Node.js:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">require('dotenv').config();constPORT=process.env.PORT ||3000;constJWT_SECRET=process.env.JWT_SECRET;<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Isso tamb\u00e9m ajuda a deixar o c\u00f3digo principal do <strong>Backend<\/strong> mais organizado.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Cuidado com o <code>.env<\/code> no GitHub<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Criar um arquivo <code>.env<\/code> e depois envi\u00e1-lo para um reposit\u00f3rio p\u00fablico elimina boa parte da vantagem dessa separa\u00e7\u00e3o.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Por isso, podemos adicion\u00e1-lo ao <code>.gitignore<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">node_modules\/.env<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Assim, o arquivo n\u00e3o deve ser versionado junto com o restante do projeto.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Em produ\u00e7\u00e3o, essas informa\u00e7\u00f5es normalmente s\u00e3o configuradas no pr\u00f3prio ambiente onde a aplica\u00e7\u00e3o ser\u00e1 executada.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">O fluxo fica mais ou menos assim:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">DESENVOLVIMENTO      \u2193Arquivo .env      \u2193N\u00e3o enviar informa\u00e7\u00f5es sens\u00edveis ao reposit\u00f3rio      \u2193PRODU\u00c7\u00c3O      \u2193Vari\u00e1veis configuradas no ambiente<\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">2. N\u00e3o armazene senhas em texto puro<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Outro ponto importante de <strong>seguran\u00e7a<\/strong> est\u00e1 relacionado \u00e0s senhas.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Evite armazenar algo assim:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">constusuario= {    email: 'usuario@email.com',    senha: '123456'};<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Nesse exemplo, temos a senha exatamente como ela foi informada.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Durante a aula utilizamos o <strong>bcrypt<\/strong> para trabalhar com o hash da senha.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">constbcrypt=require('bcryptjs');constusuario= {    id: 1,    nome: 'Marcos',    email: 'marcos@email.com',    senhaHash: bcrypt.hashSync('123456', 10)};<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">No projeto da aula, utilizamos dados locais apenas para conseguirmos demonstrar o processo de autentica\u00e7\u00e3o sem precisar adicionar um banco de dados naquele momento.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Em um projeto real, naturalmente essa informa\u00e7\u00e3o estaria associada \u00e0 camada de persist\u00eancia da aplica\u00e7\u00e3o.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">O importante aqui \u00e9 compreender o conceito:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Senha informada      \u2193Hash      \u2193Valor armazenado<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Depois, durante o login, n\u00e3o precisamos recuperar a senha original. Fazemos a compara\u00e7\u00e3o utilizando o bcrypt.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">3. Sempre valide os dados recebidos pela API REST<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Uma <strong>API REST<\/strong> recebe informa\u00e7\u00f5es externas.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Por isso, n\u00e3o devemos simplesmente confiar que tudo chegar\u00e1 exatamente como esperamos.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">No nosso login precisamos de duas informa\u00e7\u00f5es:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">emailsenha<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Podemos criar uma fun\u00e7\u00e3o espec\u00edfica para validar esses dados:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">functionvalidarLogin(email, senha) {if (!email||!senha) {return'E-mail e senha s\u00e3o obrigat\u00f3rios';    }if (typeofemail!=='string'||typeofsenha!=='string'    ) {return'E-mail e senha devem ser textos';    }returnnull;}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Essa fun\u00e7\u00e3o possui uma responsabilidade bem definida: <strong>validar os dados do login<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Se existir algum problema, retornamos uma mensagem.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Caso contr\u00e1rio:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">returnnull;<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Na implementa\u00e7\u00e3o da aula, essa valida\u00e7\u00e3o acontece antes de continuarmos com a busca do usu\u00e1rio e a verifica\u00e7\u00e3o das credenciais.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Al\u00e9m da <strong>seguran\u00e7a<\/strong>, separar a valida\u00e7\u00e3o em uma fun\u00e7\u00e3o tamb\u00e9m ajuda na organiza\u00e7\u00e3o e evita duplica\u00e7\u00e3o de c\u00f3digo.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">4. Criando a rota de login no Backend<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Para receber os dados do login, criamos uma rota <code>POST<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">app.post('\/login', async (req, res) =&gt; {});<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">O cliente pode enviar um JSON semelhante a:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">{    \"email\": \"marcos@email.com\",    \"senha\": \"123456\"}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">No <strong>Backend<\/strong>, esses dados chegam pelo corpo da requisi\u00e7\u00e3o.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Podemos acess\u00e1-los utilizando:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">req.body<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">E podemos utilizar a desestrutura\u00e7\u00e3o:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">const { email, senha } =req.body;<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u00c9 como se fiz\u00e9ssemos:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">constemail=req.body.email;constsenha=req.body.senha;<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Durante a aula, utilizamos justamente esse exemplo para mostrar o \u201cdesempacotamento\u201d das informa\u00e7\u00f5es que chegaram no JSON.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">O fluxo \u00e9:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">FRONT-END    \u2193JSON    \u2193REQUISI\u00c7\u00c3O    \u2193API REST    \u2193BACKEND    \u2193req.body<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Entender esse caminho facilita bastante a compreens\u00e3o da integra\u00e7\u00e3o entre Front-end e <strong>Backend<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">5. Validando a requisi\u00e7\u00e3o com o Status HTTP 400<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Agora podemos utilizar a fun\u00e7\u00e3o criada anteriormente:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">consterroValidacao=validarLogin(email, senha);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Se existir algum erro:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">if (erroValidacao) {returnres.status(400).json({        erro: erroValidacao    });}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Nesse caso utilizamos o <strong>Status HTTP 400<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Somente depois que os dados passam por essa primeira valida\u00e7\u00e3o continuamos o processamento do login.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Isso \u00e9 muito melhor do que simplesmente receber qualquer informa\u00e7\u00e3o e come\u00e7ar imediatamente a utiliz\u00e1-la dentro da aplica\u00e7\u00e3o.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">6. Buscando o usu\u00e1rio<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Depois de validar os dados, precisamos descobrir se existe um usu\u00e1rio correspondente.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Como estamos utilizando um vetor para simplificar o exemplo, podemos fazer:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">constusuario=usuarios.find(item =&gt; item.email ===email);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">O <code>find()<\/code> procura o primeiro elemento que atende \u00e0 condi\u00e7\u00e3o.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Na aula, utilizamos exatamente essa l\u00f3gica para comparar o e-mail recebido pelo <strong>Backend<\/strong> com os usu\u00e1rios dispon\u00edveis no nosso exemplo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Se estiv\u00e9ssemos utilizando um banco de dados, essa etapa seria substitu\u00edda pela consulta correspondente.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">O racioc\u00ednio continuaria semelhante:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Recebe o e-mail      \u2193Valida      \u2193Busca o usu\u00e1rio      \u2193Encontrou?      \u2193Continua a autentica\u00e7\u00e3o<\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">7. Por que n\u00e3o retornar \u201cusu\u00e1rio n\u00e3o encontrado\u201d?<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Aqui temos um detalhe pequeno no c\u00f3digo, mas muito interessante quando falamos de <strong>seguran\u00e7a em API REST<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Imagine que algu\u00e9m tenta fazer login e recebe:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Usu\u00e1rio n\u00e3o encontrado<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Agora tenta outro e recebe:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Senha incorreta<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Existe uma diferen\u00e7a importante.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">No segundo caso, a pr\u00f3pria aplica\u00e7\u00e3o acabou de informar que aquele usu\u00e1rio provavelmente existe.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Quem estiver realizando tentativas indevidas j\u00e1 possui parte da informa\u00e7\u00e3o.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Por isso podemos utilizar uma mensagem gen\u00e9rica:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">if (!usuario) {returnres.status(401).json({        erro: 'Usu\u00e1rio ou senha inv\u00e1lidos'    });}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A mesma mensagem pode aparecer quando a senha estiver errada.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Na aula, esse cuidado foi explicado justamente para evitar fornecer \u201c50% da informa\u00e7\u00e3o\u201d para algu\u00e9m que esteja tentando descobrir credenciais v\u00e1lidas.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">8. Erro 401 na autentica\u00e7\u00e3o<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">O <strong>Status HTTP 401<\/strong> est\u00e1 relacionado \u00e0 autentica\u00e7\u00e3o.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">No nosso exemplo:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">returnres.status(401).json({    erro: 'Usu\u00e1rio ou senha inv\u00e1lidos'});<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Perceba que n\u00e3o precisamos informar:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Usu\u00e1rio est\u00e1 correto, mas a senha est\u00e1 errada.<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Nem:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Senha correta, usu\u00e1rio inexistente.<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Simplesmente:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Usu\u00e1rio ou senha inv\u00e1lidos.<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Isso reduz a quantidade de informa\u00e7\u00e3o fornecida por nossa <strong>API REST<\/strong> durante uma tentativa de autentica\u00e7\u00e3o.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">9. Async\/Await no Backend<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Durante a cria\u00e7\u00e3o da rota aparece outra d\u00favida muito comum de quem est\u00e1 come\u00e7ando com Node.js:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">asyncawait<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">O conceito fica mais f\u00e1cil quando pensamos que algumas opera\u00e7\u00f5es precisam aguardar um resultado antes que o algoritmo continue.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Isso acontece bastante quando trabalhamos com:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">API externaBanco de dadosArquivosAutentica\u00e7\u00e3oOutras opera\u00e7\u00f5es ass\u00edncronas<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">No nosso exemplo:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">constsenhaCorreta=awaitbcrypt.compare(senha,usuario.senhaHash);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Precisamos saber o resultado da compara\u00e7\u00e3o antes de decidir se o login pode continuar.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Por isso utilizamos <code>await<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Na aula, esse conceito \u00e9 apresentado justamente dentro do contexto de opera\u00e7\u00f5es que dependem de respostas externas ou ass\u00edncronas no <strong>Backend<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">10. Comparando a senha com bcrypt<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Depois de localizar o usu\u00e1rio, fazemos a compara\u00e7\u00e3o:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">constsenhaCorreta=awaitbcrypt.compare(senha,usuario.senhaHash);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Depois verificamos:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">if (!senhaCorreta) {returnres.status(401).json({        erro: 'Usu\u00e1rio ou senha inv\u00e1lidos'    });}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Observe novamente que utilizamos a mesma resposta.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">N\u00e3o importa se foi o usu\u00e1rio ou a senha que causou a falha na autentica\u00e7\u00e3o.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Para quem est\u00e1 utilizando a API:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Usu\u00e1rio ou senha inv\u00e1lidos<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Na constru\u00e7\u00e3o realizada durante a live, <code>await<\/code>, <code>bcrypt.compare()<\/code> e o <strong>Status 401<\/strong> aparecem justamente nessa etapa.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">11. Entendendo Try\/Catch<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Outra estrutura extremamente importante no desenvolvimento <strong>Backend<\/strong> \u00e9:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">try {} catch (erro) {}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Dentro do <code>try<\/code>, executamos o c\u00f3digo principal.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Se alguma opera\u00e7\u00e3o gerar uma exce\u00e7\u00e3o, podemos capturar o problema no <code>catch<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Exemplo:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">app.post('\/login', async (req, res) =&gt; {try {\/\/ l\u00f3gica do login    } catch (erro) {console.error('Erro interno no login:', erro);returnres.status(500).json({            erro: 'Erro interno do servidor'        });    }});<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Essa estrutura se torna ainda mais importante quando trabalhamos com <strong>APIs, banco de dados e servi\u00e7os externos<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Na aula, o <code>try\/catch<\/code> tamb\u00e9m foi utilizado para mostrar que precisamos conseguir identificar internamente o que aconteceu quando alguma opera\u00e7\u00e3o falha.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">12. O usu\u00e1rio n\u00e3o precisa ver o mesmo erro que o desenvolvedor<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Aqui temos uma distin\u00e7\u00e3o fundamental para a <strong>seguran\u00e7a do Backend<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Quando algo falha, existem pelo menos duas necessidades diferentes.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Desenvolvedor<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Precisa de informa\u00e7\u00f5es suficientes para investigar o problema.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">console.error('Erro interno no login:', erro);<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Usu\u00e1rio<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Precisa saber que alguma coisa deu errado, mas n\u00e3o necessariamente conhecer detalhes internos da aplica\u00e7\u00e3o.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">returnres.status(500).json({    erro: 'Erro interno do servidor'});<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">S\u00e3o p\u00fablicos diferentes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">E, portanto, as informa\u00e7\u00f5es tamb\u00e9m podem ser diferentes.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">13. Erro 500: cuidado com o que sua API revela<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Um dos pontos que mais destacamos na aula foi o <strong>erro 500<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Imagine fazer:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">catch (erro) {returnres.status(500).json({        erro: erro    });}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Dependendo do erro e da estrutura da aplica\u00e7\u00e3o, podemos acabar expondo informa\u00e7\u00f5es internas desnecess\u00e1rias.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Uma abordagem melhor para nosso exemplo \u00e9:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">catch (erro) {console.error('Erro interno no login:', erro);returnres.status(500).json({        erro: 'Erro interno do servidor'    });}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Assim:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">DESENVOLVEDOR      \u2193Informa\u00e7\u00f5es detalhadas no logUSU\u00c1RIO      \u2193Erro interno do servidor<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Durante a live, esse foi apresentado como um dos problemas mais graves da API inicial: retornar detalhes espec\u00edficos de um erro interno diretamente para quem fez a requisi\u00e7\u00e3o.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">E, durante a implementa\u00e7\u00e3o, refor\u00e7amos novamente que o erro detalhado deve ser \u00fatil internamente, enquanto o cliente recebe uma resposta gen\u00e9rica.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">14. Logs ajudam a descobrir problemas no Backend<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Esconder informa\u00e7\u00f5es internas do usu\u00e1rio n\u00e3o significa esconder os erros do desenvolvedor.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Precisamos conseguir descobrir o que est\u00e1 acontecendo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Podemos utilizar:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">console.log('Servidor iniciado');<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Para erros:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">console.error('Erro interno no login:', erro);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">E tamb\u00e9m avisos:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">console.warn('JWT_SECRET n\u00e3o configurado');<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Na aula tamb\u00e9m comentamos a diferen\u00e7a sem\u00e2ntica entre <code>log<\/code>, <code>error<\/code> e <code>warn<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Em aplica\u00e7\u00f5es maiores, naturalmente podemos utilizar ferramentas pr\u00f3prias para logs e monitoramento.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Mas para quem est\u00e1 come\u00e7ando, \u00e9 importante compreender desde cedo a ideia:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>O usu\u00e1rio precisa de uma resposta segura. O desenvolvedor precisa de informa\u00e7\u00f5es para diagnosticar o problema.<\/strong><\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">15. JWT e informa\u00e7\u00f5es secretas<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Durante a aula tamb\u00e9m deixamos preparada a ideia do <code>JWT_SECRET<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">O <strong>JWT<\/strong> pode fazer parte do processo de autentica\u00e7\u00e3o de uma aplica\u00e7\u00e3o, mas nesta aula n\u00e3o implementamos todo o processo de cria\u00e7\u00e3o do token, payload e demais configura\u00e7\u00f5es.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">O objetivo foi mostrar onde esse tipo de informa\u00e7\u00e3o entraria e, principalmente, refor\u00e7ar que uma chave secreta n\u00e3o deveria ficar exposta diretamente no c\u00f3digo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Podemos inclusive verificar sua exist\u00eancia:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">if (!process.env.JWT_SECRET) {console.warn('JWT_SECRET n\u00e3o configurado');}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A implementa\u00e7\u00e3o completa de JWT fica para uma etapa espec\u00edfica, porque envolve outros conceitos que merecem ser estudados com mais calma. Isso tamb\u00e9m foi deixado claro durante a pr\u00f3pria aula.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">16. Front-end e Backend precisam falar a mesma l\u00edngua<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Observe uma resposta da nossa API:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">returnres.status(401).json({    erro: 'Usu\u00e1rio ou senha inv\u00e1lidos'});<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Temos uma propriedade chamada:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">erro<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">O Front-end precisa saber que essa propriedade existe para conseguir apresentar sua mensagem.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A resposta da <strong>API REST<\/strong> ser\u00e1 semelhante a:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">{    \"erro\": \"Usu\u00e1rio ou senha inv\u00e1lidos\"}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Isso mostra como entender <strong>Backend<\/strong> tamb\u00e9m ajuda no desenvolvimento Front-end.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A interface n\u00e3o recebe uma informa\u00e7\u00e3o m\u00e1gica.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Existe uma estrutura definida na API que precisa ser interpretada corretamente.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Esse relacionamento entre a propriedade criada no JSON e aquilo que posteriormente ser\u00e1 utilizado pelo Front-end tamb\u00e9m foi demonstrado durante a aula.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">17. Somente depois das valida\u00e7\u00f5es retornamos sucesso<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Depois de validar os dados, localizar o usu\u00e1rio e comparar a senha, podemos finalmente retornar uma resposta de sucesso:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">returnres.status(200).json({    mensagem: 'Login realizado com sucesso',    usuario: {        id: usuario.id,        nome: usuario.nome,        email: usuario.email    }});<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Observe quantas coisas aconteceram antes:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Receber os dados       \u2193Validar       \u2193Buscar usu\u00e1rio       \u2193Verificar credenciais       \u2193Comparar senha       \u2193Tratar poss\u00edveis erros       \u2193Retornar sucesso<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Na aplica\u00e7\u00e3o constru\u00edda na aula, o <code>200<\/code> s\u00f3 \u00e9 retornado depois que essas verifica\u00e7\u00f5es s\u00e3o realizadas.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Isso demonstra uma ideia importante:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Seguran\u00e7a n\u00e3o \u00e9 uma \u00fanica fun\u00e7\u00e3o adicionada \u00e0 API. S\u00e3o v\u00e1rias decis\u00f5es tomadas durante o desenvolvimento.<\/strong><\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">18. Teste sua API durante o desenvolvimento<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">N\u00e3o espere terminar todo o <strong>Backend<\/strong> para descobrir se ele funciona.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Durante a aula fomos testando as etapas da aplica\u00e7\u00e3o.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Um fluxo simples ajuda bastante:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">IMPLEMENTA    \u2193TESTA    \u2193FUNCIONOU?    \u2193CONTINUA<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Ao testar o login, por exemplo, conseguimos verificar uma tentativa inv\u00e1lida e posteriormente uma autentica\u00e7\u00e3o bem-sucedida. A pr\u00f3pria captura dos erros tamb\u00e9m ajuda o desenvolvedor a localizar rapidamente onde est\u00e1 o problema.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Para quem est\u00e1 come\u00e7ando com <strong>Node.js, Express e API REST<\/strong>, esse h\u00e1bito evita passar muito tempo procurando um erro que foi introduzido v\u00e1rias etapas antes.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Seguran\u00e7a em API REST vai muito al\u00e9m deste projeto<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Tudo que vimos aqui representa apenas uma introdu\u00e7\u00e3o.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Quando come\u00e7amos a desenvolver aplica\u00e7\u00f5es maiores, aparecem outros assuntos importantes de <strong>seguran\u00e7a<\/strong>, como:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>JWT;<\/li>\n\n\n\n<li>sess\u00f5es;<\/li>\n\n\n\n<li>cookies;<\/li>\n\n\n\n<li>middlewares;<\/li>\n\n\n\n<li>autoriza\u00e7\u00e3o;<\/li>\n\n\n\n<li>prote\u00e7\u00e3o de rotas;<\/li>\n\n\n\n<li>limita\u00e7\u00e3o de tentativas de login;<\/li>\n\n\n\n<li>valida\u00e7\u00f5es mais completas;<\/li>\n\n\n\n<li>controle de permiss\u00f5es;<\/li>\n\n\n\n<li>prote\u00e7\u00e3o das informa\u00e7\u00f5es;<\/li>\n\n\n\n<li>monitoramento e logs;<\/li>\n\n\n\n<li>outras formas de ataque e prote\u00e7\u00e3o.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">A pr\u00f3pria live deixa claro desde o come\u00e7o que JWT, sess\u00f5es, cookies, middlewares e outras camadas de <strong>seguran\u00e7a<\/strong> precisam ser estudadas separadamente.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">N\u00e3o tente aprender tudo de uma vez.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Primeiro entenda o fluxo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Depois v\u00e1 adicionando novas camadas de <strong>seguran\u00e7a ao Backend<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">\ud83d\udcfa Assista \u00e0 aula completa<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Este artigo foi desenvolvido a partir da <strong>Live 128 do Desvendando o C\u00f3digo<\/strong>, onde constru\u00edmos e testamos o projeto passo a passo.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Seguran\u00e7a em API REST com Node.js e Express | Boas Pr\u00e1ticas na Pr\u00e1tica<\/h3>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-4-3 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"Seguran\u00e7a em API REST com Node.js e Express | Boas Pr\u00e1ticas na Pr\u00e1tica\" width=\"960\" height=\"720\" src=\"https:\/\/www.youtube.com\/embed\/p0t8LWGXqBU?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">No v\u00eddeo voc\u00ea pode acompanhar todo o desenvolvimento da <strong>API REST<\/strong>, a constru\u00e7\u00e3o da rota de login e os testes realizados no <strong>Backend com Node.js e Express<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h1 class=\"wp-block-heading\">Conclus\u00e3o<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Criar uma <strong>API REST<\/strong> n\u00e3o significa apenas fazer as rotas funcionarem.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Quando trabalhamos com <strong>Backend<\/strong>, tamb\u00e9m precisamos pensar nas informa\u00e7\u00f5es que recebemos, processamos, armazenamos e devolvemos.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ao longo deste projeto vimos cuidados importantes de <strong>seguran\u00e7a<\/strong>, como proteger informa\u00e7\u00f5es sens\u00edveis, n\u00e3o armazenar senhas em texto puro, utilizar bcrypt, validar os dados recebidos, tratar erros com <code>try\/catch<\/code>, utilizar <code>async\/await<\/code>, trabalhar corretamente com os c\u00f3digos HTTP e evitar retornar informa\u00e7\u00f5es internas da aplica\u00e7\u00e3o.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Principalmente:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Uma API funcionando n\u00e3o significa uma API segura.<\/strong><\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">A <strong>seguran\u00e7a no Backend<\/strong> precisa fazer parte das decis\u00f5es tomadas durante o desenvolvimento da aplica\u00e7\u00e3o.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Comece pelos fundamentos apresentados aqui e v\u00e1 evoluindo sua <strong>API REST com Node.js e Express<\/strong> conforme aprender novas t\u00e9cnicas de autentica\u00e7\u00e3o, autoriza\u00e7\u00e3o e prote\u00e7\u00e3o de dados.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"> camadas de <strong>seguran\u00e7a<\/strong> podem ser adicionadas \u00e0 aplica\u00e7\u00e3o.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Criar uma API REST com Node.js e Express que funciona \u00e9 apenas uma parte do desenvolvimento de uma aplica\u00e7\u00e3o. O servidor pode iniciar corretamente, as rotas podem responder, o login pode funcionar e os dados podem chegar ao Backend sem nenhum problema. Mas isso n\u00e3o significa que sua API esteja segura. Uma informa\u00e7\u00e3o sens\u00edvel exposta no c\u00f3digo, uma senha armazenada de maneira inadequada, a falta de valida\u00e7\u00e3o ou at\u00e9 uma mensagem de erro detalhada demais podem criar problemas de seguran\u00e7a. Foi exatamente esse o ponto de partida desta aula: come\u00e7amos analisando uma API REST que funciona, mas possui problemas de seguran\u00e7a, e depois fomos corrigindo esses pontos utilizando Node.js e Express. Neste artigo, voc\u00ea vai entender algumas boas pr\u00e1ticas importantes de seguran\u00e7a no Backend, trabalhando conceitos como: Importante: seguran\u00e7a de aplica\u00e7\u00f5es \u00e9 um assunto muito maior do que conseguimos abordar em uma \u00fanica aula. O objetivo aqui \u00e9 construir uma base pr\u00e1tica para quem est\u00e1 come\u00e7ando a desenvolver APIs. Uma API funcionando pode continuar insegura Imagine que voc\u00ea criou uma API REST. Voc\u00ea inicia o servidor e tudo funciona. O login responde. As informa\u00e7\u00f5es chegam corretamente. Nenhum erro aparece. S\u00f3 que, ao analisar o c\u00f3digo, encontramos situa\u00e7\u00f5es como: constSECRET=&#8217;minha_chave_secreta&#8217;;constusuario= { email: &#8216;usuario@email.com&#8217;, senha: &#8216;123456&#8217;}; Al\u00e9m disso, a aplica\u00e7\u00e3o pode estar respondendo: Usu\u00e1rio n\u00e3o encontrado ou: Senha incorreta E, quando acontece algum problema interno: Erro ao acessar determinado arquivo&#8230; A aplica\u00e7\u00e3o funciona, mas estamos expondo informa\u00e7\u00f5es desnecess\u00e1rias. Foi justamente esse cen\u00e1rio que analisamos no in\u00edcio da aula: segredo exposto, senha sem o tratamento adequado, falta de valida\u00e7\u00e3o e mensagens que poderiam fornecer informa\u00e7\u00f5es demais para quem utiliza a API. Essa \u00e9 uma das primeiras ideias que precisamos entender: Uma API funcionar n\u00e3o significa que ela esteja segura. 1. N\u00e3o deixe informa\u00e7\u00f5es sens\u00edveis no c\u00f3digo Uma das primeiras melhorias relacionadas \u00e0 seguran\u00e7a no Backend \u00e9 separar informa\u00e7\u00f5es sens\u00edveis da l\u00f3gica principal da aplica\u00e7\u00e3o. Em vez de fazer: constJWT_SECRET=&#8217;minha_chave_secreta&#8217;; podemos utilizar vari\u00e1veis de ambiente. Para isso, podemos ter um arquivo .env: PORT=3000JWT_SECRET=minha_chave_secreta E acessar essas informa\u00e7\u00f5es no Node.js: require(&#8216;dotenv&#8217;).config();constPORT=process.env.PORT ||3000;constJWT_SECRET=process.env.JWT_SECRET; Isso tamb\u00e9m ajuda a deixar o c\u00f3digo principal do Backend mais organizado. Cuidado com o .env no GitHub Criar um arquivo .env e depois envi\u00e1-lo para um reposit\u00f3rio p\u00fablico elimina boa parte da vantagem dessa separa\u00e7\u00e3o. Por isso, podemos adicion\u00e1-lo ao .gitignore: node_modules\/.env Assim, o arquivo n\u00e3o deve ser versionado junto com o restante do projeto. Em produ\u00e7\u00e3o, essas informa\u00e7\u00f5es normalmente s\u00e3o configuradas no pr\u00f3prio ambiente onde a aplica\u00e7\u00e3o ser\u00e1 executada. O fluxo fica mais ou menos assim: DESENVOLVIMENTO \u2193Arquivo .env \u2193N\u00e3o enviar informa\u00e7\u00f5es sens\u00edveis ao reposit\u00f3rio \u2193PRODU\u00c7\u00c3O \u2193Vari\u00e1veis configuradas no ambiente 2. N\u00e3o armazene senhas em texto puro Outro ponto importante de seguran\u00e7a est\u00e1 relacionado \u00e0s senhas. Evite armazenar algo assim: constusuario= { email: &#8216;usuario@email.com&#8217;, senha: &#8216;123456&#8217;}; Nesse exemplo, temos a senha exatamente como ela foi informada. Durante a aula utilizamos o bcrypt para trabalhar com o hash da senha. constbcrypt=require(&#8216;bcryptjs&#8217;);constusuario= { id: 1, nome: &#8216;Marcos&#8217;, email: &#8216;marcos@email.com&#8217;, senhaHash: bcrypt.hashSync(&#8216;123456&#8242;, 10)}; No projeto da aula, utilizamos dados locais apenas para conseguirmos demonstrar o processo de autentica\u00e7\u00e3o sem precisar adicionar um banco de dados naquele momento. Em um projeto real, naturalmente essa informa\u00e7\u00e3o estaria associada \u00e0 camada de persist\u00eancia da aplica\u00e7\u00e3o. O importante aqui \u00e9 compreender o conceito: Senha informada \u2193Hash \u2193Valor armazenado Depois, durante o login, n\u00e3o precisamos recuperar a senha original. Fazemos a compara\u00e7\u00e3o utilizando o bcrypt. 3. Sempre valide os dados recebidos pela API REST Uma API REST recebe informa\u00e7\u00f5es externas. Por isso, n\u00e3o devemos simplesmente confiar que tudo chegar\u00e1 exatamente como esperamos. No nosso login precisamos de duas informa\u00e7\u00f5es: emailsenha Podemos criar uma fun\u00e7\u00e3o espec\u00edfica para validar esses dados: functionvalidarLogin(email, senha) {if (!email||!senha) {return&#8217;E-mail e senha s\u00e3o obrigat\u00f3rios&#8217;; }if (typeofemail!==&#8217;string&#8217;||typeofsenha!==&#8217;string&#8217; ) {return&#8217;E-mail e senha devem ser textos&#8217;; }returnnull;} Essa fun\u00e7\u00e3o possui uma responsabilidade bem definida: validar os dados do login. Se existir algum problema, retornamos uma mensagem. Caso contr\u00e1rio: returnnull; Na implementa\u00e7\u00e3o da aula, essa valida\u00e7\u00e3o acontece antes de continuarmos com a busca do usu\u00e1rio e a verifica\u00e7\u00e3o das credenciais. Al\u00e9m da seguran\u00e7a, separar a valida\u00e7\u00e3o em uma fun\u00e7\u00e3o tamb\u00e9m ajuda na organiza\u00e7\u00e3o e evita duplica\u00e7\u00e3o de c\u00f3digo. 4. Criando a rota de login no Backend Para receber os dados do login, criamos uma rota POST: app.post(&#8216;\/login&#8217;, async (req, res) =&gt; {}); O cliente pode enviar um JSON semelhante a: { &#8220;email&#8221;: &#8220;marcos@email.com&#8221;, &#8220;senha&#8221;: &#8220;123456&#8221;} No Backend, esses dados chegam pelo corpo da requisi\u00e7\u00e3o. Podemos acess\u00e1-los utilizando: req.body E podemos utilizar a desestrutura\u00e7\u00e3o: const { email, senha } =req.body; \u00c9 como se fiz\u00e9ssemos: constemail=req.body.email;constsenha=req.body.senha; Durante a aula, utilizamos justamente esse exemplo para mostrar o \u201cdesempacotamento\u201d das informa\u00e7\u00f5es que chegaram no JSON. O fluxo \u00e9: FRONT-END \u2193JSON \u2193REQUISI\u00c7\u00c3O \u2193API REST \u2193BACKEND \u2193req.body Entender esse caminho facilita bastante a compreens\u00e3o da integra\u00e7\u00e3o entre Front-end e Backend. 5. Validando a requisi\u00e7\u00e3o com o Status HTTP 400 Agora podemos utilizar a fun\u00e7\u00e3o criada anteriormente: consterroValidacao=validarLogin(email, senha); Se existir algum erro: if (erroValidacao) {returnres.status(400).json({ erro: erroValidacao });} Nesse caso utilizamos o Status HTTP 400. Somente depois que os dados passam por essa primeira valida\u00e7\u00e3o continuamos o processamento do login. Isso \u00e9 muito melhor do que simplesmente receber qualquer informa\u00e7\u00e3o e come\u00e7ar imediatamente a utiliz\u00e1-la dentro da aplica\u00e7\u00e3o. 6. Buscando o usu\u00e1rio Depois de validar os dados, precisamos descobrir se existe um usu\u00e1rio correspondente. Como estamos utilizando um vetor para simplificar o exemplo, podemos fazer: constusuario=usuarios.find(item =&gt; item.email ===email); O find() procura o primeiro elemento que atende \u00e0 condi\u00e7\u00e3o. Na aula, utilizamos exatamente essa l\u00f3gica para comparar o e-mail recebido pelo Backend com os usu\u00e1rios dispon\u00edveis no nosso exemplo. Se estiv\u00e9ssemos utilizando um banco de dados, essa etapa seria substitu\u00edda pela consulta correspondente. O racioc\u00ednio continuaria semelhante: Recebe o e-mail \u2193Valida \u2193Busca o usu\u00e1rio \u2193Encontrou? \u2193Continua a autentica\u00e7\u00e3o 7. Por que n\u00e3o retornar \u201cusu\u00e1rio n\u00e3o encontrado\u201d? Aqui temos um detalhe pequeno no c\u00f3digo, mas muito interessante quando falamos de seguran\u00e7a em API REST. Imagine que algu\u00e9m tenta fazer login e recebe: Usu\u00e1rio n\u00e3o encontrado Agora tenta outro e recebe: Senha incorreta Existe uma diferen\u00e7a importante. No segundo caso, a pr\u00f3pria aplica\u00e7\u00e3o acabou de informar que aquele usu\u00e1rio provavelmente existe. Quem estiver realizando tentativas indevidas j\u00e1 possui parte da informa\u00e7\u00e3o. Por isso podemos utilizar uma mensagem gen\u00e9rica: if (!usuario) {returnres.status(401).json({ erro: &#8216;Usu\u00e1rio ou senha inv\u00e1lidos&#8217; });} A mesma mensagem pode aparecer quando a senha estiver errada. Na aula, esse cuidado foi explicado justamente para evitar fornecer \u201c50% da informa\u00e7\u00e3o\u201d para algu\u00e9m que esteja tentando descobrir credenciais v\u00e1lidas. 8. Erro 401 na autentica\u00e7\u00e3o O Status HTTP 401 est\u00e1 relacionado \u00e0 autentica\u00e7\u00e3o. No nosso exemplo: returnres.status(401).json({ erro: &#8216;Usu\u00e1rio ou senha inv\u00e1lidos&#8217;}); Perceba que n\u00e3o precisamos informar: Usu\u00e1rio est\u00e1 correto, mas a senha est\u00e1 errada. Nem: Senha correta, usu\u00e1rio inexistente. Simplesmente: Usu\u00e1rio ou senha inv\u00e1lidos. Isso reduz a quantidade de informa\u00e7\u00e3o fornecida por nossa API REST durante uma tentativa de autentica\u00e7\u00e3o. 9. Async\/Await no Backend Durante a cria\u00e7\u00e3o da rota aparece outra d\u00favida muito comum de quem est\u00e1 come\u00e7ando com Node.js: asyncawait O conceito fica mais f\u00e1cil quando pensamos que algumas opera\u00e7\u00f5es precisam aguardar um resultado antes que o algoritmo continue. Isso acontece bastante quando trabalhamos com: API externaBanco de dadosArquivosAutentica\u00e7\u00e3oOutras opera\u00e7\u00f5es ass\u00edncronas No nosso exemplo: constsenhaCorreta=awaitbcrypt.compare(senha,usuario.senhaHash); Precisamos saber o resultado da compara\u00e7\u00e3o antes de decidir se o login pode continuar. Por isso utilizamos await. Na aula, esse conceito \u00e9 apresentado justamente dentro do contexto de opera\u00e7\u00f5es que dependem de respostas externas ou ass\u00edncronas no Backend. 10. Comparando a senha com bcrypt Depois de localizar o usu\u00e1rio, fazemos a compara\u00e7\u00e3o: constsenhaCorreta=awaitbcrypt.compare(senha,usuario.senhaHash); Depois verificamos: if (!senhaCorreta) {returnres.status(401).json({ erro: &#8216;Usu\u00e1rio ou senha inv\u00e1lidos&#8217; });} Observe novamente que utilizamos a mesma resposta. N\u00e3o importa se foi o usu\u00e1rio ou a senha que causou a falha na autentica\u00e7\u00e3o. Para quem est\u00e1 utilizando a API: Usu\u00e1rio ou senha inv\u00e1lidos Na constru\u00e7\u00e3o realizada durante a live, await, bcrypt.compare() e o Status 401 aparecem justamente nessa etapa. 11. Entendendo Try\/Catch Outra estrutura extremamente importante no desenvolvimento Backend \u00e9: try {} catch (erro) {} Dentro do try, executamos o c\u00f3digo principal. Se alguma opera\u00e7\u00e3o gerar uma exce\u00e7\u00e3o, podemos capturar o problema no catch. Exemplo: app.post(&#8216;\/login&#8217;, async (req, res) =&gt; {try {\/\/ l\u00f3gica do login } catch (erro) {console.error(&#8216;Erro interno no login:&#8217;, erro);returnres.status(500).json({ erro: &#8216;Erro interno do servidor&#8217; }); }}); Essa estrutura se torna ainda mais importante quando trabalhamos com APIs, banco de dados e servi\u00e7os externos. Na aula, o try\/catch tamb\u00e9m foi utilizado para mostrar que precisamos conseguir identificar internamente o que aconteceu quando alguma opera\u00e7\u00e3o falha. 12. O usu\u00e1rio n\u00e3o precisa ver o mesmo erro que o desenvolvedor Aqui temos uma distin\u00e7\u00e3o fundamental para a seguran\u00e7a do Backend. Quando algo falha, existem pelo menos duas necessidades diferentes. Desenvolvedor Precisa de informa\u00e7\u00f5es suficientes para investigar o problema. console.error(&#8216;Erro interno no login:&#8217;, erro); Usu\u00e1rio Precisa saber que alguma coisa deu errado, mas n\u00e3o necessariamente conhecer detalhes internos da aplica\u00e7\u00e3o. returnres.status(500).json({ erro: &#8216;Erro interno do servidor&#8217;}); S\u00e3o p\u00fablicos diferentes. E, portanto, as informa\u00e7\u00f5es tamb\u00e9m podem ser diferentes. 13. Erro 500: cuidado com o que sua API revela Um dos pontos que mais destacamos na aula foi o erro 500. Imagine fazer: catch (erro) {returnres.status(500).json({ erro: erro });} Dependendo do erro e da estrutura da aplica\u00e7\u00e3o, podemos acabar expondo informa\u00e7\u00f5es internas desnecess\u00e1rias. Uma abordagem melhor para nosso exemplo \u00e9: catch (erro) {console.error(&#8216;Erro interno no login:&#8217;, erro);returnres.status(500).json({ erro: &#8216;Erro interno do servidor&#8217; });} Assim: DESENVOLVEDOR \u2193Informa\u00e7\u00f5es detalhadas no logUSU\u00c1RIO \u2193Erro interno do servidor Durante a live, esse foi apresentado como um dos problemas mais graves da API inicial: retornar detalhes espec\u00edficos de um erro interno diretamente para quem fez a requisi\u00e7\u00e3o. E, durante a implementa\u00e7\u00e3o, refor\u00e7amos novamente que o erro detalhado deve ser \u00fatil internamente, enquanto o cliente recebe uma resposta gen\u00e9rica. 14. Logs ajudam a descobrir problemas no Backend Esconder informa\u00e7\u00f5es internas do usu\u00e1rio n\u00e3o significa esconder os erros do desenvolvedor. Precisamos conseguir descobrir o que est\u00e1 acontecendo. Podemos utilizar: console.log(&#8216;Servidor iniciado&#8217;); Para erros: console.error(&#8216;Erro interno no login:&#8217;, erro); E tamb\u00e9m avisos: console.warn(&#8216;JWT_SECRET n\u00e3o configurado&#8217;); Na aula tamb\u00e9m comentamos a diferen\u00e7a sem\u00e2ntica entre log, error e warn. Em aplica\u00e7\u00f5es maiores, naturalmente podemos utilizar ferramentas pr\u00f3prias para logs e monitoramento. Mas para quem est\u00e1 come\u00e7ando, \u00e9 importante compreender desde cedo a ideia: O usu\u00e1rio precisa de uma resposta segura. O desenvolvedor precisa de informa\u00e7\u00f5es para diagnosticar o problema. 15. JWT e informa\u00e7\u00f5es secretas Durante a aula tamb\u00e9m deixamos preparada a ideia do JWT_SECRET. O JWT pode fazer parte do processo de autentica\u00e7\u00e3o de uma aplica\u00e7\u00e3o, mas nesta aula n\u00e3o implementamos todo o processo de cria\u00e7\u00e3o do token, payload e demais configura\u00e7\u00f5es. O objetivo foi mostrar onde esse tipo de informa\u00e7\u00e3o entraria e, principalmente, refor\u00e7ar que uma chave secreta n\u00e3o deveria ficar exposta diretamente no c\u00f3digo. Podemos inclusive verificar sua exist\u00eancia: if (!process.env.JWT_SECRET) {console.warn(&#8216;JWT_SECRET n\u00e3o configurado&#8217;);} A implementa\u00e7\u00e3o completa de JWT fica para uma etapa espec\u00edfica, porque envolve outros conceitos que merecem ser estudados com mais calma. Isso tamb\u00e9m foi deixado claro durante a pr\u00f3pria aula. 16. Front-end e Backend precisam falar a mesma l\u00edngua Observe uma resposta da nossa API: returnres.status(401).json({ erro: &#8216;Usu\u00e1rio ou senha inv\u00e1lidos&#8217;}); Temos uma propriedade chamada: erro O Front-end precisa saber que essa propriedade existe para conseguir apresentar sua mensagem. A resposta da API REST ser\u00e1 semelhante a: { &#8220;erro&#8221;: &#8220;Usu\u00e1rio ou senha inv\u00e1lidos&#8221;} Isso mostra como entender Backend tamb\u00e9m ajuda no desenvolvimento Front-end. A interface n\u00e3o recebe uma informa\u00e7\u00e3o m\u00e1gica. Existe uma estrutura definida na API que precisa ser interpretada corretamente. Esse relacionamento entre a propriedade criada no JSON e aquilo que posteriormente ser\u00e1 utilizado pelo Front-end tamb\u00e9m foi demonstrado durante a aula. 17. Somente depois das valida\u00e7\u00f5es retornamos sucesso Depois de validar os dados, localizar o usu\u00e1rio e comparar a senha, podemos finalmente retornar uma resposta de sucesso: returnres.status(200).json({ mensagem: &#8216;Login realizado com sucesso&#8217;, usuario: { id: usuario.id, nome: usuario.nome, email: usuario.email }}); Observe quantas coisas aconteceram antes: Receber os dados \u2193Validar \u2193Buscar usu\u00e1rio \u2193Verificar credenciais \u2193Comparar senha \u2193Tratar poss\u00edveis erros \u2193Retornar sucesso Na aplica\u00e7\u00e3o constru\u00edda na aula, o 200 s\u00f3 \u00e9 retornado depois que essas verifica\u00e7\u00f5es s\u00e3o realizadas. Isso demonstra uma ideia importante: Seguran\u00e7a n\u00e3o \u00e9 uma \u00fanica fun\u00e7\u00e3o adicionada \u00e0 API. S\u00e3o v\u00e1rias decis\u00f5es tomadas durante o desenvolvimento. 18. Teste sua API durante&#8230;<\/p>\n","protected":false},"author":1,"featured_media":2337,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"footnotes":""},"categories":[21],"tags":[],"class_list":["post-2336","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-javascript"],"_links":{"self":[{"href":"https:\/\/desvendandoocodigo.com.br\/index.php?rest_route=\/wp\/v2\/posts\/2336","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/desvendandoocodigo.com.br\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/desvendandoocodigo.com.br\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/desvendandoocodigo.com.br\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/desvendandoocodigo.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2336"}],"version-history":[{"count":5,"href":"https:\/\/desvendandoocodigo.com.br\/index.php?rest_route=\/wp\/v2\/posts\/2336\/revisions"}],"predecessor-version":[{"id":2344,"href":"https:\/\/desvendandoocodigo.com.br\/index.php?rest_route=\/wp\/v2\/posts\/2336\/revisions\/2344"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/desvendandoocodigo.com.br\/index.php?rest_route=\/wp\/v2\/media\/2337"}],"wp:attachment":[{"href":"https:\/\/desvendandoocodigo.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2336"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/desvendandoocodigo.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2336"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/desvendandoocodigo.com.br\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2336"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}