<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Bernardo Bosak de Rezende</title>
    <description>The latest articles on DEV Community by Bernardo Bosak de Rezende (@bernardobrezende).</description>
    <link>https://dev.to/bernardobrezende</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F307451%2F5e887095-e2c8-457a-a103-a535932f1edd.jpeg</url>
      <title>DEV Community: Bernardo Bosak de Rezende</title>
      <link>https://dev.to/bernardobrezende</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bernardobrezende"/>
    <language>en</language>
    <item>
      <title>Dorking - O que podemos aprender sobre vazamento de dados por indexação involuntária em ferramentas de busca</title>
      <dc:creator>Bernardo Bosak de Rezende</dc:creator>
      <pubDate>Thu, 09 Jul 2020 19:52:08 +0000</pubDate>
      <link>https://dev.to/bernardobrezende/dorking-o-que-podemos-aprender-sobre-vazamento-de-dados-por-indexacao-involuntaria-em-ferramentas-de-busca-jdm</link>
      <guid>https://dev.to/bernardobrezende/dorking-o-que-podemos-aprender-sobre-vazamento-de-dados-por-indexacao-involuntaria-em-ferramentas-de-busca-jdm</guid>
      <description>&lt;p&gt;Esta semana o mercado da tecnologia aqui no Brasil foi ligeiramente movimentado pelo vazamento de alguns dados de correntistas de uma grande &lt;em&gt;fintech&lt;/em&gt;, que estavam disponíveis nos resultados de busca do Google.&lt;/p&gt;

&lt;p&gt;A empresa em questão (a qual sou um cliente bem satisfeito) já resolveu a situação e emitiu notas oficiais para esclarecimento, mas de qualquer forma acho que esta é uma boa oportunidade, diante de situações adversas, para evoluirmos e nos aperfeiçoarmos, por isso precisamos falar sobre o assunto.&lt;/p&gt;

&lt;h4&gt;
  
  
  Disclaimer
&lt;/h4&gt;

&lt;p&gt;Gostaria de deixar bem explícito que &lt;strong&gt;esta postagem não é uma crítica à empresa&lt;/strong&gt;, mas sim uma discussão técnica para evitar que futuramente isso venha a acontecer com outras equipes, produtos ou serviços.&lt;/p&gt;

&lt;h4&gt;
  
  
  Dito isso, vamos ao ocorrido.
&lt;/h4&gt;

&lt;p&gt;Para facilitar a transferência de valores entre correntistas, o serviço disponibiliza um link (público e sem autenticação) que pode ser compartilhado entre diferentes pessoas para, a partir da leitura de um QR code, realizar uma transferência no aplicativo autorizado. Cada link listava algumas informações pessoais, como Nome, CPF, Agência, Conta, entre outros.&lt;/p&gt;

&lt;p&gt;Estes links, que não são expirados e são públicos, acabaram sendo listados no índice de páginas do Google (de outros buscadores também), e com um pouco de "Google Hacking", uma pessoa desenvolvedora conseguiu encontrar vários destes links (contendo diferentes transferências entre contas), e escrever um script que "puxasse" estas informações de dentro do HTML dos documentos listados nos buscadores, podendo criar uma base com os dados extraídos. Estas informações podem ser usadas em tentativas de força-bruta ou até mesmo vendidas para terceiros, mas no caso citado a pessoa foi bem intencionada e reportou o problema para a empresa.&lt;/p&gt;

&lt;h4&gt;
  
  
  Tudo começa com uma busca no Google
&lt;/h4&gt;

&lt;p&gt;Digamos que queiramos listar todas as páginas da &lt;em&gt;Wikipédia&lt;/em&gt; que possuem &lt;code&gt;/computação/&lt;/code&gt; no endereço. Basta usar as diretivas &lt;code&gt;site:&lt;/code&gt; e &lt;code&gt;inurl:&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F526075%2F87069641-ef095e80-c1ed-11ea-9c0a-50be019e20fd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F526075%2F87069641-ef095e80-c1ed-11ea-9c0a-50be019e20fd.png" alt="Listar todas páginas da Wikipédia com computação na URL"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Esse tipo de técnica é conhecido como &lt;em&gt;Google Hacking&lt;/em&gt; ou &lt;em&gt;Google Dorking&lt;/em&gt;, e é muito utilizada por hackers ou profissionais de PenTesting. É importante dizer que existem &lt;a href="https://www.exploit-db.com/google-hacking-database" rel="noopener noreferrer"&gt;bancos de dados com estas brechas disponíveis&lt;/a&gt; para que outras pessoas consultem. Faça uma busca nas ferramentas e veja se alguma parte dos seus serviços estão listados. Existem várias diretivas que podem ser usadas, não somente &lt;code&gt;site:&lt;/code&gt; e &lt;code&gt;inurl:&lt;/code&gt;, no futuro compartilharei mais materiais sobre isso.&lt;/p&gt;

&lt;p&gt;Mas, voltando ao contexto do ocorrido desta semana, a parte da URL &lt;code&gt;/computação/&lt;/code&gt; pode ser substituída por algo específico como &lt;code&gt;/transferir/&lt;/code&gt;, que nos faria chegar na página de transferência de valores.&lt;/p&gt;

&lt;p&gt;Exemplo de link: &lt;code&gt;https://minhaempresa.com.br/transferir/sf9y8JV7b0Z&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Pesquisa no Google:&lt;br&gt;
&lt;code&gt;site:minhaempresa.com.br inurl:/transferir/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;A partir daí, basta escrever um script que acesse os links, interprete o conteúdo do documento HTML e extraia dele as informações desejadas (processo conhecido como &lt;a href="https://pt.wikipedia.org/wiki/Coleta_de_dados_web" rel="noopener noreferrer"&gt;&lt;em&gt;web scraping&lt;/em&gt;&lt;/a&gt;). O Google aplica alguns bloqueios como reCAPTCHA em muitas tentativas de busca com estas diretivas, mas é possível automatizar todo o processo com quebradores de captcha ou requisições intervaladas.&lt;/p&gt;
&lt;h4&gt;
  
  
  Solução
&lt;/h4&gt;

&lt;p&gt;Caso você se depare com esse tipo de exposição, você tem algumas opções:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://support.google.com/webmasters/answer/6332384" rel="noopener noreferrer"&gt;Solicitar remoção das informações para o Google&lt;/a&gt;, bem recomendado como medida emergencial;&lt;/li&gt;
&lt;li&gt;Alterar seu sistema para marcar os documentos como "não listáveis" em mecanismos de buscas;&lt;/li&gt;
&lt;li&gt;Avaliar colocar mecanismos de autenticação (ou até mesmo reCAPTCHA) antes de exibir as informações (essa opção afeta experiência de uso)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Por ser tratar de uma abordagem preventiva, vou focar no item 2. Podemos escolher quais páginas/documentos desejamos &lt;strong&gt;não ter indexados&lt;/strong&gt; nos buscadores e, mais ainda, instruir o mecanismo de busca para &lt;strong&gt;não seguir os links destes documentos&lt;/strong&gt;. O primeiro nós resolvemos com a instrução &lt;code&gt;noindex&lt;/code&gt;, e o segundo com a instrução &lt;code&gt;nofollow&lt;/code&gt;. Podemos configurar isso de duas maneiras (bem simples):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Adicionando a metatag &lt;code&gt;robots&lt;/code&gt; no HTML; ou&lt;/li&gt;
&lt;li&gt;Alterando o cabeçalho HTTP &lt;code&gt;X-Robots-Tag&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;
  
  
  Metatag robots
&lt;/h4&gt;

&lt;p&gt;Você pode instruir os mecanismos de busca a não indexarem seus documentos colocando a seguinte metatag no &lt;code&gt;head&lt;/code&gt; do HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"robots"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"noindex,nofollow"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Todo documento que você deseja não indexar deverá incluir esta metatag. Para evitar a replicação, você pode procurar utilizar hierarquia de layouts (&lt;a href="https://pugjs.org/language/inheritance.html" rel="noopener noreferrer"&gt;como este exemplo em pug&lt;/a&gt;), que é uma técnica comum em várias ferramentas e frameworks de desenvolvimento frontend.&lt;/p&gt;

&lt;p&gt;Você pode alterar a metatag para buscadores específicos, bastando alterar o valor de &lt;em&gt;name&lt;/em&gt;. Exemplo: para bloquear somente indexação no Bing, altere de &lt;code&gt;robots&lt;/code&gt; para &lt;code&gt;bingbot&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Cabeçalho X-Robots-Tag
&lt;/h4&gt;

&lt;p&gt;Alternativamente, você pode preencher o cabeçalho HTTP &lt;code&gt;X-Robots-Tag&lt;/code&gt; na resposta do documento HTML. Isto pode ser feito na configuração do servidor (ex: Apache, nginx, IIS, etc) ou no próprio código da aplicação. Vejamos alguns exemplos:&lt;/p&gt;

&lt;p&gt;nginx (&lt;em&gt;httpd.conf&lt;/em&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="c1"&gt;# avoid crawling of all html files&lt;/span&gt;
&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.html&lt;/span&gt;$ &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kn"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;X-Robots-Tag&lt;/span&gt; &lt;span class="s"&gt;"noindex,&lt;/span&gt; &lt;span class="s"&gt;nofollow"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apache (&lt;em&gt;.htaccess&lt;/em&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;&lt;span class="c"&gt;# avoid crawling of all html files&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nl"&gt;Files&lt;/span&gt;&lt;span class="sr"&gt; ~ "\.html$"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="ss"&gt;set&lt;/span&gt; X-Robots-Tag "noindex, nofollow"
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nl"&gt;Files&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Flask (nível de código)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;make_response&lt;/span&gt;

&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;home&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
   &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;make_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;render_template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;index.html&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
   &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;X-Robots-Tag&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;noindex,nofollow&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Express&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;X-Robots-Tag&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;noindex,nofollow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Conclusão
&lt;/h4&gt;

&lt;p&gt;Os danos da extração de dados por esse tipo de &lt;em&gt;dorking&lt;/em&gt; podem ser muito altos, e como vimos, a solução preventiva é bem simples. Muitas vezes, falando de segurança da informação, as soluções são simples, mas infelizmente acabam não sendo priorizadas (não estou dizendo que foi o caso citado). Temos que manter o pilar da segurança aliado com os demais atributos que compõe a qualidade de um software e, ainda assim, correremos o risco constante de ciberataques.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Avalie seu portfólio de produtos e serviços e questione quais deles realmente precisam ser bem indexados em ferramentas de busca (como um dos maiores exemplos, geralmente sistemas administrativos internos não precisam ser indexados e ainda assim é fácil encontrá-los no Google).&lt;/li&gt;
&lt;li&gt;Sempre que possível, implemente a expiração dos links públicos.&lt;/li&gt;
&lt;li&gt;Utilizar autenticação sempre é uma ideia segura, mas por vezes ela interfere bastante na experiência de uso. Discuta com especialistas de produto e equilibre os pratos da balança, tente encontrar a solução com maior valor entregue ao seu cliente &lt;strong&gt;de uma forma segura&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>security</category>
      <category>devops</category>
      <category>webdev</category>
    </item>
    <item>
      <title>DevSecOps - Mass Assignment</title>
      <dc:creator>Bernardo Bosak de Rezende</dc:creator>
      <pubDate>Wed, 01 Jul 2020 18:32:30 +0000</pubDate>
      <link>https://dev.to/bernardobrezende/devsecops-mass-assignment-fkm</link>
      <guid>https://dev.to/bernardobrezende/devsecops-mass-assignment-fkm</guid>
      <description>&lt;p&gt;Seguindo a série de posts sobre segurança no processo de desenvolvimento de software, hoje o assunto abordado será &lt;strong&gt;Mass Assignment&lt;/strong&gt;, ou atribuição em massa, que é um sub-tipo de exploração utilizando alteração de parâmetros.&lt;/p&gt;

&lt;p&gt;A OWASP elencou este tipo de vulnerabilidade como a &lt;a href="https://apisecurity.io/encyclopedia/content/owasp/api6-mass-assignment.htm"&gt;6ª mais importante se tratando de segurança para APIs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Conheci este tipo de exploração quando o Rails 4 foi lançado em 2013, e junto com ele o conceito de &lt;a href="https://github.com/rails/strong_parameters"&gt;Strong Parameters&lt;/a&gt;. Percebi que de lá pra cá muitos times de desenvolvimento deixam escapar verificações importantes de segurança que impediriam esse tipo de exploração. Por isso a importância de ser compartilhado.&lt;/p&gt;

&lt;h4&gt;
  
  
  Como funciona essa exploração
&lt;/h4&gt;

&lt;p&gt;Basicamente, pessoas exploradoras podem tentar alterar valores críticos no seu banco de dados a partir de implementações no servidor que, ao evitar escrever códigos repetitivos, genericamente atualizam &lt;strong&gt;todos campos que foram enviados na requisição&lt;/strong&gt;, sem verificações. Como exemplo, tomemos a seguinte estrutura de registro, para armazenar usuários em um sistema&lt;sup id="fnref1"&gt;1&lt;/sup&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;department&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;address&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mobile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;isAdmin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Boolean&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Em poucas palavras, usuários possuem nome, departamento onde trabalham, endereço, número de celular e a informação se um usuário &lt;strong&gt;é administrador do sistema ou não&lt;/strong&gt;, que é utilizada em verificações de segurança.&lt;/p&gt;

&lt;p&gt;Digamos que uma das funcionalidades do sistema é a de poder &lt;strong&gt;atualizar&lt;/strong&gt; os dados de um usuário, como &lt;strong&gt;nome&lt;/strong&gt; (&lt;em&gt;name&lt;/em&gt;), &lt;strong&gt;endereço&lt;/strong&gt; (&lt;em&gt;address&lt;/em&gt;) e &lt;strong&gt;celular&lt;/strong&gt; (&lt;em&gt;mobile&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Uma implementação &lt;strong&gt;trivial&lt;/strong&gt;, para esta funcionalidade, seria:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;updateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;mobile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mobile&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Onde &lt;code&gt;newData&lt;/code&gt; é um objeto com os valores &lt;strong&gt;atualizados&lt;/strong&gt; dos campos de usuário, que provavelmente será enviado pela aplicação que controla a interface gráfica onde os usuários podem realizar as atualizações. Também estamos assumindo que &lt;code&gt;db.user.update&lt;/code&gt; é uma função que atualiza o registro no banco de dados, de acordo com &lt;code&gt;id&lt;/code&gt;. Foi realizado um tratamento mínimo de erro e, caso a operação não dê erro, retornamos &lt;code&gt;true&lt;/code&gt; (caso contrário, &lt;code&gt;false&lt;/code&gt;).&lt;/p&gt;
&lt;h4&gt;
  
  
  Onde começa o problema...
&lt;/h4&gt;

&lt;p&gt;Muitos campos podem ser adicionados na estrutura de usuários, e com o passar do tempo esta rotina para atualizar os campos pode tornar-se repetitiva, exigindo que a cada inclusão de campo novo a função &lt;code&gt;updateUser&lt;/code&gt; também seja alterada. Por este motivo, é comum que as pessoas desenvolvedoras tornem esta atualização "genérica", atualizando os registros de &lt;code&gt;user&lt;/code&gt; independente dos campos que forem enviados em &lt;code&gt;newData&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;updateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Do ponto de vista de engenharia e design de código, a segunda versão do código parece mais robusta, certo? Certo.&lt;/p&gt;

&lt;p&gt;Porém, o código acima abriu uma brecha crítica de segurança: uma tentativa mal-intencionada de atualizar estas informações pode colocar, também, o campo &lt;strong&gt;isAdmin&lt;/strong&gt; no objeto &lt;code&gt;newData&lt;/code&gt; (e defini-lo como &lt;code&gt;true&lt;/code&gt;). Caso o sistema não se proteja em relação a isso, mesmo que a interface gráfica do usuário não permita a edição deste campo, seria possível tornar qualquer usuário administrador do sistema.&lt;/p&gt;

&lt;p&gt;Em termos práticos, é possível "montar" uma requisição de atualização de campos para o servidor (com analisadores de rede ou até mesmo as ferramentas de desenvolvimento dos browsers) e, mesmo havendo autenticação no sistema, ainda assim seria possível alterar campos de acesso crítico.&lt;/p&gt;

&lt;p&gt;Em outros exemplos, seria possível &lt;strong&gt;zerar valores de produtos&lt;/strong&gt;, &lt;strong&gt;alterar endereços de entrega de um pedido&lt;/strong&gt; entre outras alterações de impacto crítico.&lt;/p&gt;
&lt;h4&gt;
  
  
  Resolvendo de forma trivial, porém segura...
&lt;/h4&gt;

&lt;p&gt;Caso não queiramos permitir que apenas o campo &lt;strong&gt;isAdmin&lt;/strong&gt; seja alterado, vamos retirá-lo do objeto que enviamos para &lt;code&gt;db.user.update&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;updateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// remove isAdmin from update using rest operator&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;isAdmin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;safeNewData&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newData&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;safeNewData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Existem formas diferentes para remover um campo de um objeto, inclusive na mesma linguagem. No código acima, optei por utilizar o &lt;a href="https://codeburst.io/use-es2015-object-rest-operator-to-omit-properties-38a3ecffe90"&gt;operador rest&lt;/a&gt; em uma &lt;a href="https://javascript.info/destructuring-assignment"&gt;atribuição por desestruturação&lt;/a&gt;, ambas construções do ECMAScript, para &lt;strong&gt;criar um novo objeto sem o campo&lt;/strong&gt; &lt;code&gt;isAdmin&lt;/code&gt;, em uma referência chamada &lt;code&gt;safeNewData&lt;/code&gt;. Desta forma, respeitamos o &lt;a href="https://en.wikipedia.org/wiki/Immutable_object"&gt;princípio da imutabilidade&lt;/a&gt;, bem importante na programação funcional. Agora, independente dos valores que cheguem no objeto &lt;code&gt;newData&lt;/code&gt;, o campo &lt;code&gt;isAdmin&lt;/code&gt; não será alterado.&lt;/p&gt;
&lt;h4&gt;
  
  
  Tornando a solução segura e robusta...
&lt;/h4&gt;

&lt;p&gt;Embora tenhamos resolvido o problema com segurança, agora temos dois &lt;em&gt;code smells&lt;/em&gt; no código: rigidez e fragilidade. Existe um grande risco de qualquer alteração na estrutura de &lt;code&gt;user&lt;/code&gt; demandar alterações na função &lt;code&gt;updateUser&lt;/code&gt;, aumentando o acoplamento e custo de manutenção do código. Novos campos críticos, que não devem ser mexidos pelos usuários, deverão ser manualmente removidos no código de &lt;code&gt;updateUser&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Como solução geral, independente da forma como for implementado, podemos criar uma lista com os campos que &lt;strong&gt;não podem&lt;/strong&gt; ser atualizados (a menos que o usuário possua permissão para tal), você pode chamar esta lista como &lt;em&gt;deny list&lt;/em&gt;, ou &lt;em&gt;forbidden list&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;FORBIDDEN_FIELDS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;isAdmin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Uma vez com a lista de campos que não podem ser alterados&lt;sup id="fnref2"&gt;2&lt;/sup&gt;, nosso código pode, antes de atualizar o registro no banco de dados, remover todos os campos que estão em &lt;code&gt;FORBIDDEN_FIELDS&lt;/code&gt; e também no objeto com os dados da tentativa de atualização.&lt;/p&gt;

&lt;p&gt;Versão imperativa:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;maliciousUpdate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;New Name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;New Address&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;isAdmin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;maliciousUpdate&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;FORBIDDEN_FIELDS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="nx"&gt;maliciousUpdate&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;maliciousUpdate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// { name: "New Name", address: "New Address" }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Versão funcional:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;removeUnsafeFields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;FORBIDDEN_FIELDS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;safeUpdate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;removeUnsafeFields&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;maliciousUpdate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;safeUpdate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// { name: "New Name", address: "New Address" }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Explicando um pouco a versão funcional: primeiro filtramos todas as tuplas &lt;code&gt;[chave, valor]&lt;/code&gt; do objeto e pegamos somente aquelas cujo campo não esteja na lista de proibição de atualização (&lt;code&gt;FORBIDDEN_FIELDS&lt;/code&gt;), depois nós juntamos todas estas tuplas restantes a partir de um objeto vazio, com uma operação de redução.&lt;/p&gt;

&lt;p&gt;Basta aplicar a função &lt;code&gt;removeUnsafeFields&lt;/code&gt; em pontos do código onde exista atualização. Caso você precise ter proibições diferentes para estruturas diferentes, basta parametrizar uma lista de proibição na função &lt;code&gt;removeUnsafeFields&lt;/code&gt;, invés de usar sempre a mesma referência para &lt;code&gt;FORBIDDEN_FIELDS&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;
  
  
  Unificando estas verificações no nível da aplicação
&lt;/h4&gt;

&lt;p&gt;Se você utilizar frameworks de desenvolvimento, provavelmente eles permitem que você &lt;strong&gt;execute código customizado toda vez que algum evento aconteça&lt;/strong&gt;. No exemplo abaixo, toda vez que uma web app Express.js recebe uma requisição HTTP e a ação for um &lt;code&gt;PATCH&lt;/code&gt; (update), realizamos a verificação de segurança no campo &lt;code&gt;body&lt;/code&gt; da requisição:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;massAssignmentProtector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PATCH&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;
    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;removeUnsafeFields&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;massAssignmentProtector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;O exemplo completo, incluindo cenários demonstrando a brecha de segurança, encontra-se no replit abaixo:&lt;/p&gt;


&lt;div class="ltag__replit"&gt;
  &lt;iframe height="550px" src="https://repl.it/@bernardobrezend/mass-assignment-attack-sample?lite=true"&gt;&lt;/iframe&gt;
&lt;/div&gt;



&lt;h4&gt;
  
  
  Conclusões
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Códigos genéricos, como essa atribuição em massa, tem pontos positivos (como a redução de &lt;em&gt;boilerplate&lt;/em&gt;), mas podem expôr brechas de segurança. Por isso, &lt;strong&gt;sempre questione o código também na dimensão da segurança&lt;/strong&gt;, pois ela é uma parte (bem) importante na qualidade do seu software.&lt;/li&gt;
&lt;li&gt;Se preciso, implemente verificações por &lt;code&gt;roles&lt;/code&gt; e permita que somente alguns perfis de usuários podem alterar todos os campos.&lt;/li&gt;
&lt;li&gt;Se você possui campos sensíveis e que não podem ser alterados por interações com usuário (mas podem ser autocalculados ou coisas do tipo), nunca confie 100% nas atualizações ou operações que alguma camada externa manda para seu software. Sempre realize as suas verificações de segurança.&lt;/li&gt;
&lt;/ol&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;a estrutura dos campos é meramente didática e não representa os padrões de modelagem e normalização de dados. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;em muitos bancos de dados alterar o campo &lt;code&gt;id&lt;/code&gt; gera um erro, mas o exemplo é didático. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>security</category>
      <category>devops</category>
    </item>
    <item>
      <title>DevSecOps - DoS - Paginação de APIs (Parte 3)</title>
      <dc:creator>Bernardo Bosak de Rezende</dc:creator>
      <pubDate>Wed, 24 Jun 2020 19:47:19 +0000</pubDate>
      <link>https://dev.to/bernardobrezende/devsecops-dos-paginacao-de-apis-parte-3-35df</link>
      <guid>https://dev.to/bernardobrezende/devsecops-dos-paginacao-de-apis-parte-3-35df</guid>
      <description>&lt;p&gt;Este post faz parte de uma coleção de posts sobre segurança de software ao longo do processo de desenvolvimento e operação (DevSecOps). O tipo de vulnerabilidade abordado neste artigo é &lt;strong&gt;negação de serviço&lt;/strong&gt; através da exploração de paginações de recursos de APIs.&lt;/p&gt;

&lt;p&gt;Se você não leu as duas partes anteriores da série, recomendo sua leitura antes de continuar, pois ali são explicados alguns conceitos importantes, como o próprio DoS e log de acessos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/bernardobrezende/devsecops-dos-throughput-e-rate-limit-parte-1-fk9"&gt;Parte 1 - DoS e throughput&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/bernardobrezende/devsecops-dos-ataque-de-payload-pesado-parte-2-123m"&gt;Parte 2 - DoS e payload&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;É comum, hoje em dia, que os sistemas precisem fornecer muitos registros de seus bancos de dados para que aplicações cliente consumam estas informações, seja exibindo em uma UI ou até mesmo realizando outros fluxos de operações com as informações obtidas. Seria impraticável, por vários motivos (latência, banda, tempo de resposta e, principalmente, experiência de usuário), fornecer todos os dados de uma tabela (muitas vezes gigantesca) de uma só vez. Como solução, os sistemas entregam seus dados em "lotes" pequenos. Estes lotes são chamados de páginas (de registros), e esse processo é chamado de &lt;em&gt;paginação&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Ok, mas qual a relação disso com DoS (Denial of Service)?&lt;/p&gt;

&lt;h4&gt;
  
  
  Exemplo de como derrubar uma aplicação por ausência ou má configuração de paginação
&lt;/h4&gt;

&lt;p&gt;Digamos que, um sistema de controle áudio visual, armazene informações sobre quais músicas estão disponíveis para serem ouvidas, e que você precisa disponibilizar estes dados para que várias aplicações possam tratá-los (ex: uma aplicação web, um aplicativo, uma planilha Excel com scripts VBA). Esta "exposição" dos dados pode ser feita de diversas formas (ex: SOAP, REST, protocolos binários, arquivos, etc), mas, como de costume, utilizarei um padrão forte de mercado que são as Web APIs modeladas em REST&lt;sup id="fnref1"&gt;1&lt;/sup&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /api/songs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Na prática, isso significa que as aplicações cliente podem dizer &lt;em&gt;"sistema de controle áudio visual, me disponibilize todas as músicas em sua base de dados"&lt;/em&gt;. Se a quantidade de músicas for gigantesca (dezenas de milhões de registros), você consegue imaginar o problema para transferir estes dados, correto? Seus servidores podem ficar sem memória, a operação levaria um tempo impraticável que degradaria qualquer experiência de uso, ou seria necessário uma arquitetura de streaming de dados para transferir tanta informação de forma robusta.&lt;/p&gt;

&lt;p&gt;Por estes motivos, nestas comunicações de software entre diferentes camadas físicas, é comum que os registros sejam disponibilizados de forma &lt;strong&gt;paginada&lt;/strong&gt;. Ou seja, fornecemos os primeiros X elementos, depois mais X e assim por diante. Desta forma, a modelagem da nossa API de músicas mudou um pouco:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /api/songs?limit=20&amp;amp;offset=0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;No endpoint acima, &lt;code&gt;offset&lt;/code&gt; representa a quantidade de registros que desejamos &lt;strong&gt;pular&lt;/strong&gt; antes de começar a consultá-los, e &lt;code&gt;limit&lt;/code&gt; é a quantidade máxima de registros que serão consultados. Neste exemplo, o valor 0 é passado para &lt;code&gt;offset&lt;/code&gt; e 20 para &lt;code&gt;limit&lt;/code&gt;, ou seja: desejamos obter, no máximo, as 20 primeiras canções do banco de dados (critério de ordenação natural, pois nada foi especificado). Se quisermos os "próximos 20", basta trocarmos &lt;code&gt;offset&lt;/code&gt; para 20 e continuar com o mesmo valor de &lt;code&gt;limit&lt;/code&gt;. Se quisermos a "terceira página de 20 registros", &lt;code&gt;offset&lt;/code&gt; recebe 40 e assim por diante. Também é comum que essa técnica de paginação utilize os termos &lt;code&gt;skip&lt;/code&gt; (invés de &lt;code&gt;offset&lt;/code&gt;) e &lt;code&gt;take&lt;/code&gt; (invés de &lt;code&gt;limit&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Outra alternativa é utilizar diretamente o conceito de página, onde informaríamos o número da página e o tamanho da mesma (20 primeiros registros = &lt;code&gt;page&lt;/code&gt; 1 e &lt;code&gt;pageSize&lt;/code&gt; 20).&lt;/p&gt;

&lt;p&gt;Mas, independente da técnica de paginação, o importante é que você esteja ciente da importância do uso de paginação para a experiência de uso do software, para sua performance e... &lt;strong&gt;para a sua segurança também&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;Isso mesmo, as paginações podem ser utilizadas para &lt;strong&gt;instabilizar&lt;/strong&gt; seu sistema (um dos objetivos do &lt;em&gt;DoS&lt;/em&gt;), pois &lt;strong&gt;se o código que realiza a paginação não controla o tamanho das páginas&lt;/strong&gt;, você está exposto a receber tamanhos gigantescos de página e ter seu serviço instabilizado!&lt;/p&gt;

&lt;p&gt;Vejamos, uma tentativa de ataque pode tentar realizar grandes quantidades da seguinte requisição:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /api/songs?limit=10000000&amp;amp;offset=0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Caso não exista uma "limitação" para o valor informado em &lt;code&gt;limit&lt;/code&gt;, não existe ganho prático de fazer paginação. Isso é ruim para a performance e também expõe uma brecha para instabilidade, pois é possível consultar páginas com grandes quantidades de dados.&lt;/p&gt;
&lt;h4&gt;
  
  
  Solução
&lt;/h4&gt;

&lt;p&gt;A solução é simples: estabelecer um limite seguro para o valor máximo que pode ser informado em &lt;code&gt;limit&lt;/code&gt; (ou &lt;code&gt;pageSize&lt;/code&gt;, &lt;code&gt;take&lt;/code&gt;, etc).&lt;/p&gt;

&lt;p&gt;Isso pode ser feito com uma verificação dos valores passados por parâmetro:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;DEFAULT_LIMIT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
&lt;span class="n"&gt;MAX_LIMIT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;

&lt;span class="n"&gt;limit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'limit'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_LIMIT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;MAX_LIMIT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# query database with pagination parameters
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Preferencialmente, centralize este controle de forma que todos os seus endpoints paginados realizem esta validação com facilidade e sem duplicação de código.&lt;/p&gt;

&lt;p&gt;Por exemplo, podemos utilizar &lt;a href="https://realpython.com/primer-on-python-decorators/"&gt;Python Decorators&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'/api/songs'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;ensure_safe_limit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_songs&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# normally here we'd call a database paginated query
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;jsonify&lt;/span&gt;&lt;span class="p"&gt;([{&lt;/span&gt;&lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'Respect'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'by'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'Aretha Franklin'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                   &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'Um dia frio'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'by'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'Djavan'&lt;/span&gt;&lt;span class="p"&gt;}])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;O decorator &lt;code&gt;@ensure_safe_limit&lt;/code&gt; garante que nossa página estará segura de limites muito altos. Basta aplicá-lo em todos os endpoints paginados. O mesmo pode ser feito com Higher-Order Functions e com middlewares. Procure a documentação do seu framework ou plataforma de desenvolvimento!&lt;/p&gt;

&lt;p&gt;A solução completa pode ser conferida no repl.it abaixo. A implementação do decorator está em &lt;code&gt;utils.py&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag__replit"&gt;
  &lt;iframe height="550px" src="https://repl.it/@bernardobrezend/api-pagination-with-safe-limit?lite=true"&gt;&lt;/iframe&gt;
&lt;/div&gt;



&lt;p&gt;Caso o limite "único" que você estabelece em todo seu software não atenda algumas situações específicas, aumente-o separadamente, sempre com bastante cautela e testes. Outra opção é você estabelecer estes limites por perfis de usuários do seu sistema. Por exemplo, usuários administradores possuem um limite de &lt;code&gt;1000&lt;/code&gt; registros por páginas, usuários "visualizadores" possuem um limite de &lt;code&gt;50&lt;/code&gt;, pois realizam esta operação com muito mais frequência, etc.&lt;/p&gt;

&lt;h4&gt;
  
  
  Conclusão
&lt;/h4&gt;

&lt;p&gt;É possível ver a importância de compor a proteção do seu software contra &lt;em&gt;DoS&lt;/em&gt; em várias técnicas diferentes, pois além de controlar a quantidade de recursos por página, também é preciso controlar o &lt;em&gt;throughput&lt;/em&gt; (quantidade de requisições por intervalo de tempo) com que isso é solicitado, conforme abordado na parte 1 desta série.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Caso seu software permitir que terceiros informem a quantidade de registros "por página", estabeleça um limite seguro dentro do seu contexto de aplicação. Adote isso como padrão de paginação.&lt;/li&gt;
&lt;li&gt;Faça as devidas mensurações para encontrar um tamanho limite ideal para atender seus usuários sem expor seu sistema.&lt;/li&gt;
&lt;li&gt;Conforme já dito, desenvolva uma visão "caixa preta" e analise a sua API com uma perspectiva externa, sem detalhes de implementação. A paginação é um possível ponto de brecha, mas existem outros. Por onde você pode estar vulnerável?&lt;/li&gt;
&lt;/ul&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;O exemplo dado em REST não anula ou inviabiliza o fato de que todo tipo de integração de dados, com a opção de paginar os recursos transferidos, tenha o mesmo tipo de preocupação abordado neste post, contra a exploração de grandes paginações para fazer a negação de serviço. Sempre questione a interface de programação que você está disponibilizando para terceiros! ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>security</category>
      <category>devops</category>
      <category>webdev</category>
    </item>
    <item>
      <title>DevSecOps - DoS - Heavy payload attack (Part 2)
</title>
      <dc:creator>Bernardo Bosak de Rezende</dc:creator>
      <pubDate>Tue, 16 Jun 2020 13:12:33 +0000</pubDate>
      <link>https://dev.to/bernardobrezende/devsecops-dos-heavy-payload-attack-part-2-2hb</link>
      <guid>https://dev.to/bernardobrezende/devsecops-dos-heavy-payload-attack-part-2-2hb</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.to/bernardobrezende/devsecops-dos-ataque-de-payload-pesado-parte-2-123m"&gt;Versão original em português disponível&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is part of a collection of posts about software security through the development and operation process (DevSecOps). The vulnerability covered in this article is &lt;strong&gt;denial of service&lt;/strong&gt; by exploiting heavy requests payloads.&lt;/p&gt;

&lt;p&gt;Denial of Service, or just &lt;a href="https://owasp.org/www-community/attacks/Denial_of_Service"&gt;DoS&lt;/a&gt; (a.k.a. DDoS), consists in several exploiting techniques that &lt;strong&gt;weaken&lt;/strong&gt; your service, aiming to find security breaches along the maintenance window, make your service unavailable or simply raise your infrastructure costs, even the system not being impacted.&lt;/p&gt;

&lt;p&gt;OWASP&lt;sup id="fnref1"&gt;1&lt;/sup&gt; considered this exploit &lt;a href="https://apisecurity.io/encyclopedia/content/owasp/api4-lack-of-resources-and-rate-limiting.htm"&gt;the fourth most popular&lt;/a&gt; in terms of API security breaches, in 2019.&lt;/p&gt;

&lt;p&gt;Once during the homologation phase for a brazilian information security label for e-commerces (&lt;strong&gt;SiteBlindado&lt;/strong&gt;), I encountered a warning that some system operations were vulnerable to receive a much more larger data traffic than really needed. Then I had to setup specific requests payload size limits and it turns out to be a good DoS protection.&lt;/p&gt;

&lt;h4&gt;
  
  
  How to identify a heavy payload DoS
&lt;/h4&gt;

&lt;p&gt;The most effective way to identify this attack situation is analyzing the &lt;strong&gt;requests size&lt;/strong&gt; incoming to your servers. This information generally is available in access log formatters (e.g: nginx uses the variable &lt;a href="http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_length"&gt;$request_length&lt;/a&gt;). A common traffic log would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2020-06-05T10:14:02Z GET / 1.1.1.1 459 "Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0"
2020-06-05T10:15:23Z GET /products 2.2.2.2 257 "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 523 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:17:20Z GET / 4.4.4.4 289 "Mozilla/5.0 (Android 4.4.2; Tablet; rv:65.0) Gecko/65.0 Firefox/65.0"
2020-06-05T10:18:22Z GET / 5.5.5.5 336 "Mozilla/5.0 (Android 4.4.2; Tablet; rv:65.0) Gecko/65.0 Firefox/65.0"
2020-06-05T10:19:11Z GET /products 318 6.6.6.6 "Mozilla/5.0 (Linux; U; Android 5.0.2; en-US; XT1068 Build/LXB22.46-28) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.10.2.1164 Mobile Safari/537.36"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The most important piece of information in this case is the number between the client IP address and the &lt;em&gt;User Agent&lt;/em&gt; header value. For example, in the third request, this number is 523. This is the request total length in bytes, including header and body.&lt;/p&gt;

&lt;p&gt;If your service is under attack with heavy requests payloads, you'll notice a huge difference between the normal requests length and what you are receiving during the attack attempt. &lt;strong&gt;That's why is important to know the common traffic limits of your software. Ordinarily, what's the average size of your requests?&lt;/strong&gt;. If you're being attacked, it would exist an increase on third request above (normally these attacks use your resources with data post, such as an image upload or data form):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2020-06-05T10:16:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;At this new log sample, we had an increase in the request's total length, &lt;strong&gt;from ~0.5kb up to 9mb&lt;/strong&gt;! Mostly this symptom comes together with high throughput of the same heavy request, like this hypothetical log situation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2020-06-05T10:14:02Z GET / 1.1.1.1 459 "Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0"
2020-06-05T10:15:23Z GET /products 2.2.2.2 257 "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:17:20Z GET / 4.4.4.4 289 "Mozilla/5.0 (Android 4.4.2; Tablet; rv:65.0) Gecko/65.0 Firefox/65.0"
2020-06-05T10:18:22Z GET / 5.5.5.5 336 "Mozilla/5.0 (Android 4.4.2; Tablet; rv:65.0) Gecko/65.0 Firefox/65.0"
2020-06-05T10:18:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:18:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:18:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:18:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:18:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:18:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:18:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:19:11Z GET /products 318 6.6.6.6 "Mozilla/5.0 (Linux; U; Android 5.0.2; en-US; XT1068 Build/LXB22.46-28) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.10.2.1164 Mobile Safari/537.36"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Something is wrong with this considerable size and throughput increase. It's time to act!&lt;/p&gt;

&lt;h4&gt;
  
  
  Rightly configuring your server limits
&lt;/h4&gt;

&lt;p&gt;The solution to mitigate this exploit is to establish hard limits to your requests size, avoiding your servers to unnecessarily work on heavy requests that exceeds the acceptable traffic to your system's common operation.&lt;/p&gt;

&lt;p&gt;You can set these hard limits from "outside in", from your cloud application firewalls (like AWS WAF, CloudFlare WAF and Akamai Web Protector) to your reverse proxy or application servers. The great majority of servers provide an option to limit the maximum length of incoming requests. I'll list a few, from different architecture layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Limiting at the firewall;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/waf/latest/developerguide/classic-web-acl-size-conditions.html"&gt;AWS WAF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.cloudflare.com/firewall/cf-firewall-language/"&gt;CloudFlare WAF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.akamai.com/en-us/webhelp/enterprise-threat-protector/enterprise-threat-protector/GUID-B9AB7A84-6504-4A0F-B097-A91AB5566023.html"&gt;Akamai Web Protector&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Limiting at reverse proxy or load balancer;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size"&gt;Nginx&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Limiting at application server;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://httpd.apache.org/docs/2.2/mod/core.html#limitrequestbody"&gt;Apache httpd&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tomcat.apache.org/tomcat-9.0-doc/config/http.html"&gt;Apache Tomcat&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/iis/configuration/system.webserver/security/requestfiltering/requestlimits/"&gt;Microsoft IIS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Limiting at application code;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.senchalabs.org/connect/limit.html"&gt;Express Connect&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/stream-utils/raw-body"&gt;Node raw-body&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.djangoproject.com/en/3.0/ref/settings/#data-upload-max-memory-size"&gt;Django DATA_UPLOAD_MAX_MEMORY_SIZE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spring.io/guides/gs/uploading-files/#_tuning_file_upload_limits"&gt;Spring Boot max-request-size&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Conclusions
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Regularly monitor your application and your servers;&lt;/li&gt;
&lt;li&gt;Know your application common limits and traffic;

&lt;ul&gt;
&lt;li&gt;If you're receiving an attack attempt, being aware of your common traffic average size will make your life much easier on identifying the resource under attack.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Adopt the philosophy of "limiting down until necessary";

&lt;ul&gt;
&lt;li&gt;Set low limits to ALL of your requests sizes (you can establish an average size based on your entrypoints with larger traffics).&lt;/li&gt;
&lt;li&gt;Raise these limits in a granular, specific and on-demand way (e.g: if you need a file upload, adjust the configuration to allow a higher request limit specifically to this upload operation).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;The &lt;a href="https://owasp.org/"&gt;OWASP&lt;/a&gt; is a valuable information security community. It's important to keep updated with their periodic reports and publications! ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>security</category>
      <category>devops</category>
      <category>webdev</category>
    </item>
    <item>
      <title>DevSecOps - DoS - Ataque de payload pesado (Parte 2)</title>
      <dc:creator>Bernardo Bosak de Rezende</dc:creator>
      <pubDate>Mon, 15 Jun 2020 20:48:14 +0000</pubDate>
      <link>https://dev.to/bernardobrezende/devsecops-dos-ataque-de-payload-pesado-parte-2-123m</link>
      <guid>https://dev.to/bernardobrezende/devsecops-dos-ataque-de-payload-pesado-parte-2-123m</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.to/bernardobrezende/devsecops-dos-heavy-payload-attack-part-2-2hb"&gt;English version available here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Este post faz parte de uma coleção de posts sobre segurança de software ao longo do processo de desenvolvimento e operação (DevSecOps). O tipo de vulnerabilidade abordado neste artigo é &lt;strong&gt;negação de serviço&lt;/strong&gt; através da exploração por requisições pesadas (payload).&lt;/p&gt;

&lt;p&gt;Se você não leu o primeiro artigo da série de DoS, &lt;a href="https://dev.to/bernardobrezende/devsecops-dos-throughput-e-rate-limit-parte-1-fk9"&gt;recomendo sua leitura antes de continuar&lt;/a&gt;, pois ali são explicados alguns conceitos importantes, como o próprio DoS e log de acessos!&lt;/p&gt;

&lt;p&gt;Certa vez, enquanto homologava um site para receber o selo &lt;strong&gt;SiteBlindado&lt;/strong&gt;, recebi uma notificação de que várias operações do sistema estavam suscetíveis a receber um tráfego muito maior de dados do que de fato necessitavam. Foi então que precisei configurar limites específicos para tamanhos de requisições e me dei conta que esta é uma boa proteção contra DoS.&lt;/p&gt;

&lt;h4&gt;
  
  
  Como identificar um DoS por requisições pesadas
&lt;/h4&gt;

&lt;p&gt;A maneira mais eficaz para identificar este ataque é analisando o &lt;strong&gt;tamanho das requisições&lt;/strong&gt; que seus servidores estão recebendo. Esta informação geralmente está disponível nos formatadores dos logs de acesso (por exemplo, no nginx usa-se a variável &lt;a href="http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_length"&gt;$request_length&lt;/a&gt;). Um log de tráfego normal seria:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2020-06-05T10:14:02Z GET / 1.1.1.1 459 "Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0"
2020-06-05T10:15:23Z GET /products 2.2.2.2 257 "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 523 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:17:20Z GET / 4.4.4.4 289 "Mozilla/5.0 (Android 4.4.2; Tablet; rv:65.0) Gecko/65.0 Firefox/65.0"
2020-06-05T10:18:22Z GET / 5.5.5.5 336 "Mozilla/5.0 (Android 4.4.2; Tablet; rv:65.0) Gecko/65.0 Firefox/65.0"
2020-06-05T10:19:11Z GET /products 318 6.6.6.6 "Mozilla/5.0 (Linux; U; Android 5.0.2; en-US; XT1068 Build/LXB22.46-28) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.10.2.1164 Mobile Safari/537.36"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;A informação mais importante neste caso é o número entre o IP do cliente que enviou a requisição e o valor do cabeçalho &lt;em&gt;User Agent&lt;/em&gt;. Por exemplo, na terceira requisição, este número é 523. É o tamanho total da requisição em bytes, incluindo cabeçalhos e corpo.&lt;/p&gt;

&lt;p&gt;Caso o seu serviço esteja sofrendo tentativas de ataque com requisições pesadas, você perceberá uma diferença grande entre o tamanho normal das suas requisições e o que está recebendo durante o ataque. &lt;strong&gt;Por isso a importância de conhecer os limites normais do seu software. Quanto costuma ser, em um tráfego de operação normal, o tamanho das suas requisições?&lt;/strong&gt;. Nesta situação, poderíamos ter um aumento no tamanho da terceira requisição (normalmente estes ataques utilizam os seus recursos que aceitam postagem de dados, como upload de imagens ou cadastramento de formulários):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2020-06-05T10:16:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Neste novo log, tivemos um aumento no tamanho da requisição, &lt;strong&gt;indo de ~0.5kb para 9mb&lt;/strong&gt;! Geralmente este sintoma vem acompanhado da repetição da requisição por várias vezes (o que abordamos no primeiro post):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2020-06-05T10:14:02Z GET / 1.1.1.1 459 "Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0"
2020-06-05T10:15:23Z GET /products 2.2.2.2 257 "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:17:20Z GET / 4.4.4.4 289 "Mozilla/5.0 (Android 4.4.2; Tablet; rv:65.0) Gecko/65.0 Firefox/65.0"
2020-06-05T10:18:22Z GET / 5.5.5.5 336 "Mozilla/5.0 (Android 4.4.2; Tablet; rv:65.0) Gecko/65.0 Firefox/65.0"
2020-06-05T10:18:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:18:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:18:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:18:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:18:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:18:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:18:53Z POST /admin 3.3.3.3 9000000 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:19:11Z GET /products 318 6.6.6.6 "Mozilla/5.0 (Linux; U; Android 5.0.2; en-US; XT1068 Build/LXB22.46-28) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.10.2.1164 Mobile Safari/537.36"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Algo não está certo neste tipo de aumento considerável e repetitivo. É hora de agir!&lt;/p&gt;

&lt;h4&gt;
  
  
  Configurando corretamente os limites dos seus servidores
&lt;/h4&gt;

&lt;p&gt;A solução para mitigar esta exploração é estabelecer limites para os tamanhos de requisições, evitando assim que seus servidores trabalhem desnecessariamente em requisições pesadas e que excedam o normal aceitável para a operação do serviço.&lt;/p&gt;

&lt;p&gt;Você pode configurar estes limites de "fora para dentro", desde firewalls cloud (como o AWS WAF, Akamai Web Protector e CloudFlare WAF) até seus servidores de proxy reverso ou de aplicação. A grande maioria dos servidores fornece a opção de limitar o tamanho das requisições. Vou citar alguns, em camadas diferentes da arquitetura:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Limitando no firewall;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/waf/latest/developerguide/classic-web-acl-size-conditions.html"&gt;AWS WAF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.cloudflare.com/firewall/cf-firewall-language/"&gt;CloudFlare WAF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.akamai.com/en-us/webhelp/enterprise-threat-protector/enterprise-threat-protector/GUID-B9AB7A84-6504-4A0F-B097-A91AB5566023.html"&gt;Akamai Web Protector&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Limitando no proxy reverso ou balancer;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size"&gt;Nginx&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Limitando no servidor de aplicação;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://httpd.apache.org/docs/2.2/mod/core.html#limitrequestbody"&gt;Apache httpd&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tomcat.apache.org/tomcat-9.0-doc/config/http.html"&gt;Apache Tomcat&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/iis/configuration/system.webserver/security/requestfiltering/requestlimits/"&gt;Microsoft IIS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Limitando no código da aplicação;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.senchalabs.org/connect/limit.html"&gt;Express Connect&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/stream-utils/raw-body"&gt;Node raw-body&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.djangoproject.com/en/3.0/ref/settings/#data-upload-max-memory-size"&gt;Django DATA_UPLOAD_MAX_MEMORY_SIZE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spring.io/guides/gs/uploading-files/#_tuning_file_upload_limits"&gt;Spring Boot max-request-size&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Conclusão
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Monitore constantemente sua aplicação e seus servidores;&lt;/li&gt;
&lt;li&gt;Conheça os limites normais da sua aplicação;

&lt;ul&gt;
&lt;li&gt;Caso você esteja sofrendo ataques, saber o tamanho do seu tráfego normal facilitará bastante na identificação.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Adote a filosofia de "limitar por baixo até que seja necessário";

&lt;ul&gt;
&lt;li&gt;Estabeleça limites pequenos para os tamanhos das suas requisições (a melhor dica é estabelecer uma média de tamanho com base nos seus pontos de entrada que recebem a maior quantidade de dados).&lt;/li&gt;
&lt;li&gt;Aumente estes limites de forma granular e especifica (por ex: se você precisa fazer upload de arquivos, ajuste a configuração para permitir um limite maior especificamente na operação de upload).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>security</category>
      <category>devops</category>
      <category>webdev</category>
    </item>
    <item>
      <title>DevSecOps - DoS - Throughput e Rate Limit (Parte 1)</title>
      <dc:creator>Bernardo Bosak de Rezende</dc:creator>
      <pubDate>Mon, 08 Jun 2020 23:24:39 +0000</pubDate>
      <link>https://dev.to/bernardobrezende/devsecops-dos-throughput-e-rate-limit-parte-1-fk9</link>
      <guid>https://dev.to/bernardobrezende/devsecops-dos-throughput-e-rate-limit-parte-1-fk9</guid>
      <description>&lt;p&gt;Este post faz parte de uma coleção de posts sobre segurança de software ao longo do processo de desenvolvimento e operação (DevSecOps). O tipo de vulnerabilidade abordado neste artigo é &lt;strong&gt;negação de serviço&lt;/strong&gt; através da exploração de alto volume de requisições (throughput).&lt;/p&gt;

&lt;p&gt;Negação de serviço, ou &lt;a href="https://owasp.org/www-community/attacks/Denial_of_Service" rel="noopener noreferrer"&gt;DoS&lt;/a&gt; (a.k.a. DDoS), consiste em uma série de técnicas de exploração que &lt;strong&gt;instabilizam&lt;/strong&gt; ou até mesmo &lt;strong&gt;indisponibilizam&lt;/strong&gt; um serviço, visando encontrar brechas de segurança ao longo da manutenção da instabilidade, retirá-lo do ar ou simplesmente fazer com que o seu custo de infraestrutura aumente consideravelmente, mesmo que o sistema não tenha sido impactado.&lt;/p&gt;

&lt;p&gt;A OWASP&lt;sup id="fnref1"&gt;1&lt;/sup&gt; considerou este tipo de exploração &lt;a href="https://apisecurity.io/encyclopedia/content/owasp/api4-lack-of-resources-and-rate-limiting.htm" rel="noopener noreferrer"&gt;o quarto mais popular&lt;/a&gt; em termos de brechas de segurança para APIs, em 2019.&lt;/p&gt;

&lt;p&gt;É possível tentar retirar um serviço do ar de diversas maneiras, e abordaremos como mitigar as três principais (mas neste artigo falaremos apenas da primeira):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1) Sabendo lidar com altas taxas de requisições (&lt;em&gt;throughput&lt;/em&gt;);&lt;/strong&gt;&lt;br&gt;
2) Sabendo lidar com altas cargas em cada requisição (&lt;em&gt;payload&lt;/em&gt;);&lt;br&gt;
3) Limitando tamanho de paginações de recursos.&lt;/p&gt;
&lt;h4&gt;
  
  
  Como identificar um DoS
&lt;/h4&gt;

&lt;p&gt;O primeiro passo é identificar uma situação de &lt;em&gt;DoS&lt;/em&gt;. Geralmente fazemos isso analisando métricas de acesso ou logs de requisição.&lt;/p&gt;

&lt;p&gt;Se você ainda não tem certeza da situação, comece analisando a quantidade de requisições que o seu sistema tem recebido nos últimos minutos / horas, preferencialmente procure pelo &lt;em&gt;throughput&lt;/em&gt; recente do sistema (ex: total de requisições por segundo ou requisições por minuto). Se existe uma tentativa de &lt;em&gt;DoS&lt;/em&gt;, você perceberá um aumento considerável no número de requisições em pequenos intervalos de tempo. Por exemplo, se você estiver visualizando um gráfico, ele representaria um crescimento:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F526075%2F83980914-b248ff80-a8ef-11ea-9b54-ae82b4e7c088.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F526075%2F83980914-b248ff80-a8ef-11ea-9b54-ae82b4e7c088.png" alt="Aumento no gráfico de requisições"&gt;&lt;/a&gt;&lt;/p&gt;
Crescimento no gráfico de requisições recebidas pelo sistema



&lt;p&gt;Aplicações como AWS CloudWatch, NewRelic, Datadog, Nginx Amplify possuem diversos destes tipos de gráficos. Geralmente eles são o primeiro indício de que algo está incomum.&lt;/p&gt;

&lt;p&gt;Se você não tiver essas informações, procure nos logs de acesso de seus servidores. Comece analisando "de fora para dentro" (por exemplo, se a sua arquitetura tem um load balancer ou proxy reverso, comece por eles, e depois os servidores de aplicação e assim por diante).&lt;/p&gt;

&lt;p&gt;Por exemplo, um &lt;a href="https://docs.nginx.com/nginx/admin-guide/monitoring/logging/" rel="noopener noreferrer"&gt;log de acesso normal do &lt;em&gt;nginx&lt;/em&gt;&lt;/a&gt; seria:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2020-06-05T10:14:02Z GET / 1.1.1.1 "Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0"
2020-06-05T10:15:23Z GET /products 2.2.2.2 "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:17:20Z GET / 4.4.4.4 "Mozilla/5.0 (Android 4.4.2; Tablet; rv:65.0) Gecko/65.0 Firefox/65.0"
2020-06-05T10:18:22Z GET / 5.5.5.5 "Mozilla/5.0 (Android 4.4.2; Tablet; rv:65.0) Gecko/65.0 Firefox/65.0"
2020-06-05T10:19:11Z GET /products 6.6.6.6 "Mozilla/5.0 (Linux; U; Android 5.0.2; en-US; XT1068 Build/LXB22.46-28) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.10.2.1164 Mobile Safari/537.36"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Nesta situação, garanta que seus logs utilizam timestamp (data e hora da requisição), mas principalmente preocupe-se em identificar o IP de origem das requisições (ex: &lt;em&gt;1.1.1.1&lt;/em&gt;, &lt;em&gt;2.2.2.2&lt;/em&gt;, etc) e o &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent" rel="noopener noreferrer"&gt;cabeçalho User Agent&lt;/a&gt;, pois &lt;strong&gt;quando essas duas informações se repetem por várias requisições, temos o principal sintoma de &lt;em&gt;DoS&lt;/em&gt;&lt;/strong&gt;. As repetições podem seguir um padrão variável, mas muitas vezes elas serão constantes. Exemplo:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2020-06-05T10:14:02Z GET / 1.1.1.1 "Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0"
2020-06-05T10:15:23Z GET /products 2.2.2.2 "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:16:53Z POST /admin 3.3.3.3 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
2020-06-05T10:17:20Z GET / 4.4.4.4 "Mozilla/5.0 (Android 4.4.2; Tablet; rv:65.0) Gecko/65.0 Firefox/65.0"
2020-06-05T10:18:22Z GET / 5.5.5.5 "Mozilla/5.0 (Android 4.4.2; Tablet; rv:65.0) Gecko/65.0 Firefox/65.0"
2020-06-05T10:19:11Z GET /products 6.6.6.6 "Mozilla/5.0 (Linux; U; Android 5.0.2; en-US; XT1068 Build/LXB22.46-28) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.10.2.1164 Mobile Safari/537.36"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;O log acima demonstra um padrão repetitivo em excesso em um curto espaço de tempo (menos de um segundo), em requisições com o verbo &lt;em&gt;POST&lt;/em&gt; na rota &lt;em&gt;/admin&lt;/em&gt; (ex: um ataque de força bruta ao tentar submeter o formulário de login várias vezes):&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2020-06-05T10:16:53Z POST /admin 3.3.3.3 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;O que nos leva a crer que existe, sim, uma tentativa de &lt;em&gt;DoS&lt;/em&gt;. É importante ressaltar que o mesmo ataque pode gerar inúmeras requisições de origens e user agents diferentes. Portanto, se você não encontrar um padrão para bloquear um conjunto específico de requisições, a melhor abordagem é intervalar o acesso ao seu sistema em uma janela de tempo, que veremos mais tarde.&lt;/p&gt;

&lt;p&gt;Não deixe para configurar ferramentas em horas emergenciais, garanta que seu software possui um monitoramento adequado e que atende suas necessidades de manutenção de uma forma segura.&lt;/p&gt;
&lt;h4&gt;
  
  
  Exemplo de ataque por throughput
&lt;/h4&gt;

&lt;p&gt;Um ataque mal-intencionado pode tentar reproduzir em alto volume qualquer requisição que seu sistema disponibilize, mesmo estando sob autenticação. Se o ataque possui acesso a fazer uma requisição, ele possui acesso a fazer 1 milhão, a menos que isso seja tratado, como veremos a seguir.&lt;/p&gt;

&lt;p&gt;Uma pessoa com conhecimento não muito avançado de redes e desenvolvimento web conseguiria identificar como são enviadas as requisições para o seu sistema, através de analisadores de pacotes (bem usados para analisar tráfego de aplicativos), como &lt;a href="https://www.wireshark.org/" rel="noopener noreferrer"&gt;WireShark&lt;/a&gt; ou &lt;a href="https://www.tcpdump.org/" rel="noopener noreferrer"&gt;TcpDump&lt;/a&gt;, ou simplesmente com as ferramentas de desenvolvimento dos navegadores Web (ex: &lt;a href="https://developers.google.com/web/tools/chrome-devtools" rel="noopener noreferrer"&gt;Chrome DevTools&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Por exemplo, imagine que seu sistema possui um dashboard analítico, com várias métricas complexas e consultas de dados cruzados que demandam bastante recurso computacional para apresentá-los em tempo real&lt;sup id="fnref2"&gt;2&lt;/sup&gt;, como o exemplo abaixo (&lt;a href="http://creativecommons.org/licenses/by-sa/3.0/" rel="noopener noreferrer"&gt;Opsview, Ltd / CC BY-SA&lt;/a&gt;):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2F8%2F8d%2FOpsview_Monitor_6.0_Dashboard.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2F8%2F8d%2FOpsview_Monitor_6.0_Dashboard.jpg" alt="Opsview Monitor 6.0 Dashboard sample"&gt;&lt;/a&gt;&lt;/p&gt;
Exemplo de dashboard com várias métricas



&lt;p&gt;Suponhamos que, para atender a este dashboard, exista a seguinte API:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /api/dashboard
Authorization: token-do-usuario-id-1 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Uma vez que o ataque conheça a estrutura dessa requisição, e estando o token do usuário id-1 devidamente válido (em muitos sistemas, basta cadastrar um usuário para obter um token válido), é possível criar scripts que executem muitas vezes a requisição acima, afim de instabilizar o seu sistema:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://seuservico.com/api/dashboard&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;token-do-usuario-id-1&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000000&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Idealmente (do ponto de vista de programação), o código que dispara essas requisições mal-intencionadas deveria ser assíncrono e paralelo, mas isso está fora do escopo abordado aqui, o importante é conhecer o funcionamento desses scripts para conseguir evitá-los. Ainda seria possível utilizar frameworks de testes de carga, como &lt;a href="https://artillery.io/" rel="noopener noreferrer"&gt;artillery&lt;/a&gt;, &lt;a href="https://jmeter.apache.org/" rel="noopener noreferrer"&gt;JMeter&lt;/a&gt;, &lt;a href="https://k6.io" rel="noopener noreferrer"&gt;k6&lt;/a&gt;, &lt;a href="https://gatling.io/" rel="noopener noreferrer"&gt;Gatling&lt;/a&gt;, etc.&lt;/p&gt;

&lt;p&gt;Existem dois tipos de solução bem comuns para isso lidar com altas taxas de requisições:&lt;/p&gt;

&lt;p&gt;1) Bloquear a origem das requisições (ex: IP, user agent, sessão ou token); ou&lt;br&gt;
2) Estabelecer um limite para a quantidade de requisições que uma ou mais origens podem realizar em um determinado período de tempo. Ex: permitir que o token do usuário id-1 execute apenas uma requisição por segundo. Essa abordagem é conhecida como &lt;a href="https://en.wikipedia.org/wiki/Throttling_process_(computing)" rel="noopener noreferrer"&gt;throttling&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ambas alternativas podem ser resolvidas em nível de infraestrutura ou código de aplicação.&lt;/p&gt;
&lt;h4&gt;
  
  
  Resolvendo com infraestrutura
&lt;/h4&gt;

&lt;p&gt;Resolver essa exploração com recursos de infraestrutura tem as vantagens de ser uma solução bem mais rápida (geralmente envolve configurar corretamente os servidores de firewall ou aplicação) e comprometer menos a arquitetura da solução. Bloquear ou intervalar requisições via software exige mais recursos computacionais de servidores que são provisionados para atender a aplicação, ao invés de realizar estas tarefas em servidores de firewall ou proxy reversos (como &lt;em&gt;nginx&lt;/em&gt;), otimizados para esse tipo de responsabilidade.&lt;/p&gt;

&lt;p&gt;Os pontos negativos ficam por conta do gargalo de conhecimento em infraestrutura que, infelizmente, muitas equipes enfrentam e do custo financeiro de algumas dessas soluções.&lt;/p&gt;

&lt;p&gt;Já utilizei o &lt;em&gt;AWS Web Application Firewall&lt;/em&gt; e gostei bastante, inclusive existem concorrentes de players gigantes do mercado de &lt;a href="https://pt.wikipedia.org/wiki/Site_Reliability_Engineering" rel="noopener noreferrer"&gt;SRE&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/pt/waf/" rel="noopener noreferrer"&gt;AWS Web Application Firewall&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.cloudflare.com/pt-br/waf/" rel="noopener noreferrer"&gt;CloudFlare Web Application Firewall&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.akamai.com/br/pt/products/security/web-application-protector-enterprise-waf-firewall-ddos-protection.jsp" rel="noopener noreferrer"&gt;Akamai Web Application Protector&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Converse com os interessados pela arquitetura e infraestrutura do seu software, avalie serviços e soluções (em alguns casos configurar uma instância de proxy reverso é mais vantajoso) e monte um plano de ação para, de preferência, ter prevenção contra esse tipo de exploração.&lt;/p&gt;
&lt;h4&gt;
  
  
  Resolvendo com software
&lt;/h4&gt;

&lt;p&gt;Podemos escrever pedaços de código que façam estas verificações anti-DoS (bloquear ou intervalar) e incluí-los &lt;strong&gt;no início&lt;/strong&gt; do ciclo de vida das requisições no servidor de aplicação (os &lt;em&gt;endpoints&lt;/em&gt;). Porém, muito provavelmente esse tipo de código já foi criado previamente e existe na stack de desenvolvimento que você utiliza, seja de forma incorporada (&lt;em&gt;built-in&lt;/em&gt;) ou via código terceiro.&lt;/p&gt;

&lt;p&gt;Por exemplo, para quem trabalha com o Express framework, existe uma biblioteca open-source chamada &lt;em&gt;express-rate-limit&lt;/em&gt;:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/express-rate-limit" rel="noopener noreferrer"&gt;
        express-rate-limit
      &lt;/a&gt; / &lt;a href="https://github.com/express-rate-limit/express-rate-limit" rel="noopener noreferrer"&gt;
        express-rate-limit
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Basic rate-limiting middleware for the Express web server
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt; &lt;code&gt;express-rate-limit&lt;/code&gt; &lt;/h1&gt;
&lt;/div&gt;

&lt;div&gt;
&lt;p&gt;&lt;a href="https://github.com/express-rate-limit/express-rate-limit/actions/workflows/ci.yaml" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c25f040705ccb7699e6f6f45b845858d7120ced37e6ea03abc69196393e653cf/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f657870726573732d726174652d6c696d69742f657870726573732d726174652d6c696d69742f63692e79616d6c" alt="tests"&gt;&lt;/a&gt;
&lt;a href="https://npmjs.org/package/express-rate-limit" title="View this project on NPM" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e147805a5438940b6994e924fc7531a4b087dc185d7fb47e42204389fe5c9160/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f657870726573732d726174652d6c696d69742e737667" alt="npm version"&gt;&lt;/a&gt;
&lt;a href="https://www.npmjs.com/package/express-rate-limit" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a130fcb0ce8ef67eee3164e74e0af310f0c44e5b1269ba4294dd7cf32b7a7e9a/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f646d2f657870726573732d726174652d6c696d6974" alt="npm downloads"&gt;&lt;/a&gt;
&lt;a href="https://github.com/express-rate-limit/express-rate-limitlicense.md" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/56717ebde0b93602a2dfca552707295cd686d8d1ea722f599b8fb3a222031477/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f6c2f657870726573732d726174652d6c696d6974" alt="license"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Basic rate-limiting middleware for &lt;a href="http://expressjs.com/" rel="nofollow noopener noreferrer"&gt;Express&lt;/a&gt;. Use to
limit repeated requests to public APIs and/or endpoints such as password reset
Plays nice with
&lt;a href="https://www.npmjs.com/package/express-slow-down" rel="nofollow noopener noreferrer"&gt;express-slow-down&lt;/a&gt; and
&lt;a href="https://www.npmjs.com/package/ratelimit-header-parser" rel="nofollow noopener noreferrer"&gt;ratelimit-header-parser&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;a href="https://express-rate-limit.mintlify.app/overview" rel="nofollow noopener noreferrer"&gt;full documentation&lt;/a&gt; is
available on-line.&lt;/p&gt;
&lt;div class="highlight highlight-source-ts notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-s1"&gt;rateLimit&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt; &lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s"&gt;'express-rate-limit'&lt;/span&gt;

&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-s1"&gt;limiter&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;rateLimit&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt;
    &lt;span class="pl-c1"&gt;windowMs&lt;/span&gt;: &lt;span class="pl-c1"&gt;15&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt; &lt;span class="pl-c1"&gt;60&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt; &lt;span class="pl-c1"&gt;1000&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-c"&gt;// 15 minutes&lt;/span&gt;
    &lt;span class="pl-c1"&gt;limit&lt;/span&gt;: &lt;span class="pl-c1"&gt;100&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-c"&gt;// Limit each IP to 100 requests per `window` (here, per 15 minutes).&lt;/span&gt;
    &lt;span class="pl-c1"&gt;standardHeaders&lt;/span&gt;: &lt;span class="pl-s"&gt;'draft-7'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-c"&gt;// draft-6: `RateLimit-*` headers; draft-7: combined `RateLimit` header&lt;/span&gt;
    &lt;span class="pl-c1"&gt;legacyHeaders&lt;/span&gt;: &lt;span class="pl-c1"&gt;false&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-c"&gt;// Disable the `X-RateLimit-*` headers.&lt;/span&gt;
    &lt;span class="pl-c"&gt;// store: ... , // Redis, Memcached, etc. See below.&lt;/span&gt;
&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;

&lt;span class="pl-c"&gt;// Apply the rate limiting middleware to all requests.&lt;/span&gt;
&lt;span class="pl-s1"&gt;app&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;use&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;limiter&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Data Stores&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;The rate limiter comes with a built-in memory store, and supports a variety of
&lt;a href="https://express-rate-limit.mintlify.app/reference/stores" rel="nofollow noopener noreferrer"&gt;external data stores&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Configuration&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;All function options may be async…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/express-rate-limit/express-rate-limit" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Através desta biblioteca, podemos configurar facilmente um &lt;em&gt;middleware&lt;/em&gt; para o Express framework, conforme a própria documentação:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rateLimit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express-rate-limit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;limiter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;rateLimit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;windowMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 15 minutes&lt;/span&gt;
  &lt;span class="na"&gt;max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="c1"&gt;// limit each IP to 100 requests per windowMs&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;//  apply to all requests&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;limiter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;De forma mais "automática", existem bibliotecas que fazem o bloqueio para você e aumentam o intervalo seguindo sequências, pré-determinadas, como a lib &lt;em&gt;express-brute&lt;/em&gt;:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/AdamPflug" rel="noopener noreferrer"&gt;
        AdamPflug
      &lt;/a&gt; / &lt;a href="https://github.com/AdamPflug/express-brute" rel="noopener noreferrer"&gt;
        express-brute
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Brute-force protection middleware for express routes by rate limiting incoming requests
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;express-brute&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="http://badge.fury.io/js/express-brute" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/00c829c06f722d2342b097edab25f41ba05574dbb7e3e0b4a6b0ca4df60e91e8/68747470733a2f2f62616467652e667572792e696f2f6a732f657870726573732d62727574652e706e67" alt="NPM Version"&gt;&lt;/a&gt;
&lt;a href="http://badge.fury.io/js/express-brute" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d1056dddac7aca2621fb2b6d850a95bc7a1d18662b29573c2cffccf8076edd6c/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f646d2f657870726573732d62727574652e7376673f6d61784167653d32353932303030" alt="NPM Downloads"&gt;&lt;/a&gt;
&lt;a href="https://travis-ci.org/AdamPflug/express-brute" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/32e407fdc2c249ed5f5fcc1e6a3def8dd11b5374f7514d8e05c472bf32db4ae2/68747470733a2f2f696d672e736869656c64732e696f2f7472617669732f4164616d50666c75672f657870726573732d62727574652e7376673f6d61784167653d32353932303030" alt="Build Status"&gt;&lt;/a&gt;
&lt;a href="http://coveralls.io/github/AdamPflug/express-brute?branch=master" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/d3109a08f9caa7a703af81356a4a4d90dfb976052e39d9680117bd01dca17456/68747470733a2f2f696d672e736869656c64732e696f2f636f766572616c6c732f4164616d50666c75672f657870726573732d62727574652e7376673f6d61784167653d32353932303030" alt="Coverage Status"&gt;&lt;/a&gt;
&lt;a href="https://david-dm.org/adampflug/express-brute" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f7e27e3ad4c82da6f860044c6c5a03ca7fdc0c154c235d55cc2a7c9f5c86b9a9/68747470733a2f2f696d672e736869656c64732e696f2f64617669642f4164616d50666c75672f657870726573732d62727574652e7376673f6d61784167653d32353932303030" alt="Dependency Status"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A brute-force protection middleware for express routes that rate-limits incoming requests, increasing the delay with each request in a fibonacci-like sequence.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;via npm:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;  $ npm install express-brute
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;A Simple Example&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="highlight highlight-source-js notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;var&lt;/span&gt; &lt;span class="pl-v"&gt;ExpressBrute&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;require&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'express-brute'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-c"&gt;// stores state locally, don't use this in production&lt;/span&gt;
&lt;span class="pl-k"&gt;var&lt;/span&gt; &lt;span class="pl-s1"&gt;store&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;new&lt;/span&gt; &lt;span class="pl-v"&gt;ExpressBrute&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;MemoryStore&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-k"&gt;var&lt;/span&gt; &lt;span class="pl-s1"&gt;bruteforce&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;new&lt;/span&gt; &lt;span class="pl-v"&gt;ExpressBrute&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;store&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-s1"&gt;app&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;post&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'/auth'&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt;
    &lt;span class="pl-s1"&gt;bruteforce&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;prevent&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-c"&gt;// error 429 if we hit this route too often&lt;/span&gt;
    &lt;span class="pl-k"&gt;function&lt;/span&gt; &lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;req&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;res&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;next&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
        &lt;span class="pl-s1"&gt;res&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;send&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'Success!'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
    &lt;span class="pl-kos"&gt;}&lt;/span&gt;
&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Classes&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;ExpressBrute(store, options)&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;store&lt;/code&gt; An instance of &lt;code&gt;ExpressBrute.MemoryStore&lt;/code&gt; or some other ExpressBrute store (see a list of known stores below).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;options&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;freeRetries&lt;/code&gt;             The number of retries the user has before they need to start waiting (default: 2)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;minWait&lt;/code&gt;                 The initial wait time (in…&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/AdamPflug/express-brute" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;ExpressBrute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express-brute&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// stores state locally, don't use this in production - VEJA NOTA ABAIXO -&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ExpressBrute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MemoryStore&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;bruteforce&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ExpressBrute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;bruteforce&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prevent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// error 429 if we hit this route too often&lt;/span&gt;
    &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Success!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O mesmo pode ser feito em demais tecnologias e frameworks, consulte a documentação da stack que você está utilizando! Veja as principais:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.django-rest-framework.org/api-guide/throttling/" rel="noopener noreferrer"&gt;Django REST Framework Throttling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/DianaIonita/serverless-api-gateway-throttling" rel="noopener noreferrer"&gt;Serverless Framework API Gateway Throttling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/koajs/ratelimit" rel="noopener noreferrer"&gt;Koa Rate Limit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/shlomokoren/spring-boot-throttling" rel="noopener noreferrer"&gt;Spring Boot Throttling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/stefanprodan/AspNetCoreRateLimit" rel="noopener noreferrer"&gt;ASP.NET Core Rate Limit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kickstarter/rack-attack" rel="noopener noreferrer"&gt;Rack Attack for Rails&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Importante&lt;/strong&gt; ⚠️&lt;/p&gt;

&lt;p&gt;Independente da sua escolha, &lt;strong&gt;lembre-se que estas soluções devem funcionar bem em arquiteturas escaláveis&lt;/strong&gt;, então se você configurar uma destas bibliotecas no modo "in-memory", todo o bloqueio de requisições funcionará de forma separada em cada nodo da arquitetura, ou seja, &lt;strong&gt;a requisição maliciosa X será bloqueada no servidor A mas não no servidor B&lt;/strong&gt;. Por este motivo, a grande maioria destas bibliotecas oferecem a forma de configurá-las com um armazenamento compartilhado das informações (geralmente utilizando &lt;a href="https://redis.io/" rel="noopener noreferrer"&gt;Redis&lt;/a&gt; ou &lt;a href="https://memcached.org/" rel="noopener noreferrer"&gt;memcached&lt;/a&gt;). &lt;/p&gt;

&lt;h4&gt;
  
  
  Conclusão
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Monitore constantemente sua aplicação e seus servidores;&lt;/li&gt;
&lt;li&gt;Ajuste seu software e sua arquitetura para, a qualquer momento (faça simulações!), bloquear ou intervalar requisições.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Questione &lt;em&gt;"que ferramentas e técnicas a stack tecnológica me fornece para evitar DoS?"&lt;/em&gt;. Então consulte as documentações e faça os devidos testes! Em termos de segurança de informação, a máxima &lt;strong&gt;prevenir é melhor que remediar&lt;/strong&gt; vale muito.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;A &lt;a href="https://owasp.org/" rel="noopener noreferrer"&gt;OWASP&lt;/a&gt; é uma comunidade muito valiosa em segurança de informação. É sempre muito importante estarmos atentos aos dados e relatórios periódicos que eles publicam! ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Para facilitar a didática e o exemplo, vamos assumir que o cálculo dessas métricas é feito em tempo real. Porém, muitos desses sistemas utilizam estruturas analíticas pré-calculadas. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>security</category>
      <category>devops</category>
      <category>webdev</category>
    </item>
    <item>
      <title>DevSecOps - Ataque de alteração de parâmetros da requisição</title>
      <dc:creator>Bernardo Bosak de Rezende</dc:creator>
      <pubDate>Mon, 01 Jun 2020 17:44:35 +0000</pubDate>
      <link>https://dev.to/bernardobrezende/devsecops-ataque-de-alteracao-de-parametros-da-requisicao-4ip9</link>
      <guid>https://dev.to/bernardobrezende/devsecops-ataque-de-alteracao-de-parametros-da-requisicao-4ip9</guid>
      <description>&lt;h2&gt;
  
  
  Segurança para devs
&lt;/h2&gt;

&lt;p&gt;Este post faz parte de uma coleção de posts sobre segurança de software ao longo do processo de desenvolvimento (DevSecOps). O tipo de vulnerabilidade abordado neste artigo é &lt;strong&gt;Alteração de parâmetros da requisição&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A tradução deste nome é livre, mas o termo mais comum, em inglês, é &lt;em&gt;Parameter Tampering&lt;/em&gt;. Você pode conferir a &lt;a href="https://owasp.org/www-community/attacks/Web_Parameter_Tampering"&gt;documentação&lt;/a&gt; no catálogo da OWASP &lt;sup id="fnref1"&gt;1&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Basicamente, &lt;em&gt;Parameter Tampering&lt;/em&gt; consiste em qualquer tipo de exploração de segurança baseada em &lt;em&gt;alterar&lt;/em&gt; as informações que uma aplicação cliente envia para o servidor (ex: uma requisição REST ou um formulário HTML), afim de obter resultados diferentes, como acessar informações de outros usuários ou alterar informações que, normalmente por restrições de UI, não seria possível.&lt;/p&gt;

&lt;p&gt;Alguns exemplos do que pode ser feito com esse tipo de exploração:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Em um sistema com troca de mensagens instantâneas (chat), poder enviar uma mensagem se passando por outra pessoa (usuário X envia mensagem para usuário A como se fosse usuário B).&lt;/li&gt;
&lt;li&gt;Em um sistema de vendas, poder alterar o valor do desconto de uma compra.&lt;/li&gt;
&lt;li&gt;Em um sistema de rastreamento, poder acompanhar a entrega de um pedido de outra pessoa.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Por se tratar de uma gama bem ampla de ataques, vamos focar aqui nos problemas que podem ser resolvidos com design de APIs e um pouquinho de código. Para isso, vamos tomar a seguinte especificação de funcionalidade:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Como usuário de um ecommerce&lt;br&gt;
E estando autenticado na área do cliente&lt;br&gt;
Quando acessar "Meus Pedidos"&lt;br&gt;
Então devo visualizar pedidos realizados apenas pelo mesmo usuário que está autenticado&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Gosto desse exemplo, pois ilustra bem uma situação corriqueira em equipes de desenvolvimento: criar consultas de dados. Implementamos esse tipo de consulta a todo momento, por centenas de vezes e em muitos sistemas, mas nem sempre questionamos o &lt;strong&gt;nível de permissão de acesso&lt;/strong&gt; à essas consultas.&lt;/p&gt;

&lt;p&gt;Para atender a funcionalidade descrita acima, suponhamos a seguinte modelagem do servidor, seguindo a arquitetura REST:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /api/usuarios/{id}/pedidos
Authorization: token-do-usuario-id-{id}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Provavelmente a implementação em alto nível (Python)&lt;sup id="fnref2"&gt;2&lt;/sup&gt;, para atender à esta rota, seria algo como:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'/usuarios/&amp;lt;int:id_usuario&amp;gt;/pedidos'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pedidos_unsafe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id_usuario&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;decodificar_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'valido'&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Unauthorized
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;consultar_pedidos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id_usuario&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Aparentemente, não há nada de errado com o código acima. A função &lt;code&gt;decodificar_token&lt;/code&gt; interpreta o cabeçalho &lt;code&gt;Authorization&lt;/code&gt; (enviado com a requisição), e confere se o token&lt;sup id="fnref3"&gt;3&lt;/sup&gt; está válido (na grande maioria dos casos, essa validação consiste em verificar se o preenchimento do token está correto e se o mesmo não expirou ou foi invalidado - o que pode ser disparado por um evento de troca de senha, por exemplo -). Caso esteja válido, o sistema prossegue o fluxo, consultando (no banco de dados) pelos pedidos referentes ao id enviado na requisição.&lt;/p&gt;

&lt;p&gt;Porém, além de não atender à especificação&lt;sup id="fnref4"&gt;4&lt;/sup&gt;, esta implementação expõe uma falha de segurança. Note que apesar de validarmos o token, &lt;strong&gt;não verificamos se o usuário relacionado aquele token é o mesmo usuário recebido no parâmetro da requisição&lt;/strong&gt;. Aqui está a brecha para o &lt;em&gt;Parameter Tampering&lt;/em&gt;, pois podemos enviar o token para o usuário 1 e ainda assim pedir os dados do usuário 2:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /api/usuarios/2/pedidos
Authorization: token-do-usuario-id-1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Uma forma simples de evitar esse &lt;em&gt;exploit&lt;/em&gt; seria &lt;strong&gt;garantir que o usuário do token é o mesmo informado no parâmetro&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'id_usuario'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;id_usuario&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Forbidden
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Implementação completa:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'/usuarios/&amp;lt;int:id_usuario&amp;gt;/pedidos'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pedidos_safe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id_usuario&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;decodificar_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'valido'&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Unauthorized
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'id_usuario'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;id_usuario&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Forbidden
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;consultar_pedidos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id_usuario&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Pronto! Agora as requisições que possuem o argumento id do usuário &lt;strong&gt;diferente&lt;/strong&gt; do id do usuário vinculado ao token serão respondidas com um código de erro do servidor 403 (forbidden).&lt;/p&gt;

&lt;p&gt;Podemos fazer duas simples evoluções:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Centralizar e unificar esta lógica de verificação de token x parâmetro de query, pois provavelmente muitas rotas terão essa brecha; e&lt;/li&gt;
&lt;li&gt;Quando algum usuário tentar acessar informações que não são suas, registrar esta intenção para futuras auditorias.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Centralizando e unificando as regras de segurança
&lt;/h3&gt;

&lt;p&gt;Para o item 1, podemos utilizar o padrão de projeto &lt;a href="https://refactoring.guru/pt-br/design-patterns/decorator/"&gt;Decorator&lt;/a&gt;, presente nativamente em linguagens / frameworks como Python, Java e C# ou &lt;a href="https://eloquentjavascript.net/05_higher_order.html"&gt;Higher-Order Functions&lt;/a&gt; para linguagens funcionais que ainda não possuem suporte a decorators (ex: JavaScript até junho de 2020), de forma que o código da solução se reduziria a:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'/usuarios/&amp;lt;int:id_usuario&amp;gt;/pedidos'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;garantir_mesmo_usuario&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nome_argumento&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'id_usuario'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pedidos_safe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id_usuario&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;consultar_pedidos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id_usuario&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Neste caso, toda "mágica" fica por conta de &lt;code&gt;garantir_mesmo_usuario&lt;/code&gt;&lt;sup id="fnref5"&gt;5&lt;/sup&gt;, uma função decoradora que nos permite executar código &lt;strong&gt;antes&lt;/strong&gt; e &lt;strong&gt;depois&lt;/strong&gt; da implementação que desejamos executar quando a rota for acionada por uma aplicação cliente (neste exemplo, consultar pedidos). Desta forma, conseguimos reduzir bastante o código e ainda reaproveitar esta lógica em outros pontos de alteração. A implementação do &lt;em&gt;decorator&lt;/em&gt; pode ser conferida no link no final deste artigo.&lt;/p&gt;

&lt;p&gt;Similarmente, poderíamos criar esse comportamento de verificar a segurança em uma função externa que "empacota" (&lt;em&gt;wrapper&lt;/em&gt;) a implementação da consulta (exemplo para node.js express):&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/usuarios/:idUsuario/pedidos&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;garantirMesmoUsuario&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;idUsuario&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pedidos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;consultarPedidos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;idUsuario&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pedidos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Perceba que &lt;code&gt;garantirMesmoUsuario&lt;/code&gt; é um função que recebe como argumento... uma outra função. Essa "outra função" é a implementação que desejamos executar quando a rota &lt;code&gt;/usuarios/:idUsuario/pedidos&lt;/code&gt; for acionada com o método GET. Primeiro fazemos as verificações devidas de segurança, e aí invocamos a "outra função" em &lt;code&gt;return func(req, res)&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;garantirMesmoUsuario&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;func&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;decodificarToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;valido&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sendStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;idUsuario&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;
  &lt;span class="c1"&gt;// comparação estrita vai falhar se token.idUsuario for Number&lt;/span&gt;
  &lt;span class="c1"&gt;// e idUsuario for String&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;idUsuario&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;idUsuario&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sendStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Esta implementação funciona de forma muito similar aos mecanismos de &lt;em&gt;middleware&lt;/em&gt;, presente em alguns frameworks para desenvolvimento Web, como &lt;a href="https://expressjs.com/pt-br/guide/writing-middleware.html"&gt;Express&lt;/a&gt; e &lt;a href="https://docs.djangoproject.com/pt-br/3.0/topics/http/middleware/"&gt;Django&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Registrando tentativas de acesso inadequado
&lt;/h3&gt;

&lt;p&gt;Agora que temos toda estrutura de verificação centralizada, é fácil registrar as tentativas de acessos inadequados. Isso pode ser importante caso o software esteja sob tentativas de ataque ou se algum usuário teve suas credenciais comprometidas, permitindo ao sistema reagir corretamente a isso.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight diff"&gt;&lt;code&gt;    if token['id_usuario'] != id_usuario:
&lt;span class="gi"&gt;+       registrar_tentativa(token, id_usuario)
&lt;/span&gt;        abort(403) # Forbidden
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;code&gt;registrar_tentativa&lt;/code&gt; é uma função que pode gravar a tentativa no output do sistema (geralmente um &lt;em&gt;stdout&lt;/em&gt; de terminal), em um algum arquivo de log transacional, em algum banco de dados gerenciado ou em um serviço especializado de processamento de logs de auditoria (AWS CloudTrail, ELK, Papertrail, etc).&lt;/p&gt;

&lt;p&gt;Os detalhes de implementação desta função são, como o próprio termo diz, detalhes. O que importa é que seu sistema &lt;strong&gt;armazene estas informações&lt;/strong&gt; e saiba &lt;strong&gt;reagir corretamente&lt;/strong&gt; a essas tentativas de acesso. Por exemplo: enviar uma notificação para o usuário sobre o acesso inadequado e invalidar todos os tokens relacionados a ele.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"UX também é segurança!"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;(Alguma pessoa lúcida, em algum momento lúcido)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Lembre-se: &lt;strong&gt;segurança de informação não é apenas sobre tecnologias, frameworks e padrões que inserimos no código e na arquitetura&lt;/strong&gt;. É também sobre projetar fluxos e interações com o usuário final que garantam a máxima integridade de todos os dados que forem tratados no uso do software.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;EDIT 1: essa vulnerabilidade de alterar o ID do recurso a ser consultado também é conhecida como &lt;a href="https://apisecurity.io/encyclopedia/content/owasp/api1-broken-object-level-authorization.htm"&gt;BOLA&lt;/a&gt; (Broken Object Level Authorization) ou IDOR (Insecure Direct Object Reference) (créditos &lt;a href="https://github.com/jradesenv"&gt;@jradesenv&lt;/a&gt;). Porém, Parameter Tampering permite outros tipos de explorações, como veremos a seguir.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Outras considerações
&lt;/h3&gt;

&lt;p&gt;Nem sempre os parâmetros que podem ser alterados estarão na URL da requisição, é preciso cuidar os campos que podem ser enviados no corpo ou até mesmo os cabeçalhos. Exemplo:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;POST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/api/mensagens&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;Authentication:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;token-usuario-id&lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"de"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"para"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mensagem"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"oi! pode me passar seu endereço?"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Se nada for feito no servidor (backend), é possível mandar mensagem do usuário 2 para 3 tendo apenas as credenciais do usuário 1, que pode ter sido criado simplesmente para executar algum ataque. Essa alteração de parâmetros acontece no campo &lt;code&gt;de&lt;/code&gt; (id do usuário remetente).&lt;/p&gt;

&lt;p&gt;Pode ser mais fácil explorar esta vulnerabilidade se os identificadores únicos dos usuários forem incrementais (ex: 1, 2, 3, ... 10401), facilitando a vida de quem for executar o ataque (ou até mesmo escrever um script para automatizar o &lt;em&gt;exploit&lt;/em&gt;). Identificadores incrementais também podem trazer problemas de concorrência de escrita (embora nos últimos anos as tecnologias de banco de dados tenham evoluído bastante nesse aspecto). &lt;strong&gt;Prefira abordagens de identificação única com baixa previsibilidade&lt;/strong&gt;, como &lt;a href="https://en.wikipedia.org/wiki/Universally_unique_identifier"&gt;UUID&lt;/a&gt; ou &lt;a href="https://en.wikipedia.org/wiki/Hi/Lo_algorithm"&gt;Hi/Lo&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Outra vulnerabilidade muito comum referente a &lt;em&gt;Parameter Tempering&lt;/em&gt; é o acesso irrestrito a informações &lt;strong&gt;retirando parâmetros específicos&lt;/strong&gt; (como um id de busca) e acessando todos registros de uma tabela (consulta mais ampla sem filtros), também conhecido como &lt;a href="https://apisecurity.io/encyclopedia/content/owasp/api5-broken-function-level-authorization.htm"&gt;Broken Function Access Authorization&lt;/a&gt;, tomemos as seguintes especificações:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Funcionalidade: Detalhar pedido específico&lt;br&gt;
Como usuário do ecommerce&lt;br&gt;
E estando autenticado na área do cliente&lt;br&gt;
Quando entrar em "Meus Pedidos" e escolher o pedido 1&lt;br&gt;
Então deve abrir a tela com os detalhes do pedido 1&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Funcionalidade: Listar todos pedidos&lt;br&gt;
Como usuário administrador do ecommerce&lt;br&gt;
E estando autenticado na área administrativa&lt;br&gt;
Quando clicar no item "Todos os pedidos" do menu&lt;br&gt;
Então devo visualizar todos os pedidos do ecommerce&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Para a primeira funcionalidade, podemos assumir a seguinte API:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /api/pedidos/{id}
Authentication: token-do-usuario-{id}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Para a segunda funcionalidade:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /api/pedidos
Authentication: token-do-usuario-admin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Porém, se nada for feito, o usuário 1 (que não é administrador), poderá acessar &lt;code&gt;/api/pedidos&lt;/code&gt; apenas retirando o id do pedido da URL, podendo então visualizar todos os pedidos. Ao criar Web APIs que vão expôr dados de forma ampla e com poucos filtros, questione &lt;strong&gt;quem deve poder acessar essas informações&lt;/strong&gt; e faça os devidos ajustes, pois com um conhecimento básico de Web e protocolos de rede, é possível tentar acessar praticamente todos os dados que seu sistema "expõe" para as aplicações utilizarem.&lt;/p&gt;

&lt;p&gt;Muitos frameworks Web já possuem mecanismos para auxiliar a autorização por diferentes papéis de usuários (Role Based Security), a exemplo dos &lt;a href="https://docs.djangoproject.com/pt-br/2.2/_modules/django/contrib/auth/decorators/"&gt;decoradores de autorização do Django&lt;/a&gt; ou a &lt;a href="https://docs.spring.io/spring-security/site/docs/current/reference/html5/#ns-global-method"&gt;anotação @Secured do Spring framework&lt;/a&gt;. Consulte a documentação das tecnologias que você usa antes de escrever manualmente esses filtros!&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Esse tipo de vulnerabilidade nos parâmetros de requisições nem sempre é fácil de identificar e pode se manifestar de diferentes formas, mas elenco algumas práticas que podem ajudar na grande maioria dos casos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Questionar, o quanto antes e de forma contínua, que &lt;strong&gt;tipo de papéis de usuário poderão acessar as informações&lt;/strong&gt; que serão disponibilizadas. Refletir as respostas no desenho da solução.&lt;/li&gt;
&lt;li&gt;Analisar todos os parâmetros que são trocados entre camada pública (cliente) e camada privada (servidor). Identificar quais desses parâmetros:

&lt;ol&gt;
&lt;li&gt;São utilizados para localizar registros que podem ser lidos ou alterados (ex: ids de busca). Questionar o quanto o usuário que está autenticado (seja por token, cookie, sessão, etc) pode alterar dos parâmetros destes parâmetros elencados.&lt;/li&gt;
&lt;li&gt;Precisam ser re-validados (além da validação já realizada na camada de UI). Por exemplo, em um sistema com restrição de idade, é preciso garantir, no servidor, que o campo "data de nascimento" atende às regras exigidas, mesmo que essas já tenham sido impostas na camada de UI, pois em uma tentativa maliciosa esta informação pode ser alterada fora da aplicação cliente confiável.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Sempre que possível, preferir mecanismos de geração de identificadores únicos de baixa previsibilidade, como os já citados UUID ou Hi/Lo.&lt;/li&gt;
&lt;li&gt;Desenvolva uma visão "caixa preta" e analise a sua API com uma perspectiva externa, sem detalhes de implementação. O que uma pessoa maliciosa poderia tentar fazer com as URLs e parâmetros públicos?&lt;/li&gt;
&lt;li&gt;Principal: tente incutir as práticas e revisões de segurança de informação na cultura de desenvolvimento do time, de forma que isso seja diluído em preocupações e tarefas constantes e frequentes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Segurança da informação também é qualidade de software!&lt;/strong&gt;&lt;/p&gt;


&lt;div class="ltag__replit"&gt;
  &lt;iframe height="550px" src="https://repl.it/@bernardobrezend/parameter-tampering-sample-pt-br?lite=true"&gt;&lt;/iframe&gt;
&lt;/div&gt;






&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;A &lt;a href="https://owasp.org/"&gt;OWASP&lt;/a&gt; é uma comunidade muito valiosa em segurança de informação. É sempre muito importante estarmos atentos aos dados e relatórios periódicos que eles publicam! ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Por motivos didáticos e de brevidade, a implementação omite algumas definições de funções, rotas, servidor, etc. Se você quiser todos os detalhes, confira a &lt;a href="https://repl.it/@bernardobrezend/parameter-tampering-sample-pt-br"&gt;implementação completa&lt;/a&gt;. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;Todos os exemplos podem ser interpretados com qualquer mecanismo de autenticação (token, cookie, session id, etc). Por ser uma das abordagens mais populares atualmente, utilizaremos ao longo do artigo a autenticação por token. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;É comum que as especificações (independente do formato) não contenham algumas preocupações básicas de segurança. Neste caso, o critério de aceite pode aparecer como &lt;em&gt;"Então devo visualizar pedidos"&lt;/em&gt;. Uma pessoa que trabalha com produtos digitais deve se preocupar com muitas coisas, então é completamente compreensível que alguns detalhes de segurança passem desapercebidos, por isso a importância da equipe de desenvolvimento se preocupar com &lt;em&gt;infosec&lt;/em&gt; de uma forma iterativa ao longo das entregas (e não apenas no final dos projetos através de auditorias), revisando as especificações e fortalecendo uma cultura onde qualidade de software está diretamente relacionada à segurança de informação. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn5"&gt;
&lt;p&gt;Também por motivos didáticos e de brevidade, a função decoradora &lt;code&gt;garantir_mesmo_usuario&lt;/code&gt; possui duas responsabilidades: 1) verificar se o token é válido; e 2) verificar se o usuário do token é o mesmo da requisição. Em termos de boas práticas e design de código, o mais correto seria "dividir" esta função em duas menores, onde cada qual possuiria sua responsabilidade única. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>security</category>
      <category>devops</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
