Nesse artigo iremos aprender a como um contrato malicioso age para acessar variáveis privadas e como previnir um ataque em seu contrato inteligente.
Vulnerabilidade
Todos os dados de um contrato inteligente podem ser lidos.
Vamos ver como podemos ler dados de variáveis definidas como private. No processo, você aprenderá como o Solidity armazena as variáveis de estado.
OBS: não pode usar web3 na JVM, então use o contrato implementado na Testenet Ropsten (ETH).
OBS: o navegador Web3 é antigo, então use o Web3 do console do Truffle.
Contrato implantado na Testnet Ropsten com endereço 0x3505a02BCDFbb225988161a95528bfDb279faD6b
Armazenar
- 2 ** 256 slots
- 32 bytes para cada slot
- os dados são armazenados sequencialmente na ordem de declaração
- o armazenamento é otimizado para economizar espaço. Se as variáveis vizinhas couberem em um único 32 bytes, elas serão empacotadas no mesmo slot, começando da direita
// SPDX-License-Identifier: MITpragma solidity ^0.8.13;contract Vault {// slot 0uint public count = 123;// slot 1address public owner = msg.sender;bool public isTrue = true;uint16 public u16 = 31;// slot 2bytes32 private password;// constantes não usam armazenamentouint public constant someConst = 123;// slot 3, 4, 5 (um para cada elemento da matriz)bytes32[3] public data;struct User {uint id;bytes32 password;}// slot 6 - comprimento do array// começando do slot hash(6) - elementos do array// slot onde o elemento do array é armazenado = keccak256(slot)) + (index * elementSize)// onde slot = 6 e elementSize = 2 (1 (uint) + 1 (bytes32))User[] private users;// slot 7 - vazio// as entradas são armazenadas em hash(chave, slot)// onde slot = 7, key = map keymapping(uint => User) private idToUser;constructor(bytes32 _password) {password = _password;}function addUser(bytes32 _password) public {User memory user = User({id: users.length, password: _password});users.push(user);idToUser[user.id] = user;}function getArrayLocation(uint slot,uint index,uint elementSize) public pure returns (uint) {return uint(keccak256(abi.encodePacked(slot))) + (index * elementSize);}function getMapLocation(uint slot, uint key) public pure returns (uint) {return uint(keccak256(abi.encodePacked(key, slot)));}}/*slot 0 - contarweb3.eth.getStorageAt("0x3505a02BCDFbb225988161a95528bfDb279faD6b", 0, console.log)slot 1 - u16, isTrue, proprietárioweb3.eth.getStorageAt("0x3505a02BCDFbb225988161a95528bfDb279faD6b", 1, console.log)slot 2 - senhaweb3.eth.getStorageAt("0x3505a02BCDFbb225988161a95528bfDb279faD6b", 2, console.log)slot 6 - tamanha da arraygetArrayLocation(6, 0, 2)web3.utils.numberToHex("111414077815863400510004064629973595961579173665589224203503662149373724986687")Nota: Também podemos usar o web3 para obter a localização dos dadosweb3.utils.soliditySha3({ type: "uint", value: 6 })1st usuárioweb3.eth.getStorageAt("0x3505a02BCDFbb225988161a95528bfDb279faD6b", "0xf652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f", console.log)web3.eth.getStorageAt("0x3505a02BCDFbb225988161a95528bfDb279faD6b", "0xf652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d40", console.log)Nota: use web3.toAscii para converter bytes32 em alfabeto2nd usuárioweb3.eth.getStorageAt("0x3505a02BCDFbb225988161a95528bfDb279faD6b", "0xf652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d41", console.log)web3.eth.getStorageAt("0x3505a02BCDFbb225988161a95528bfDb279faD6b", "0xf652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d42", console.log)slot 7 - vaziogetMapLocation(7, 1)web3.utils.numberToHex("81222191986226809103279119994707868322855741819905904417953092666699096963112")Nota: Também podemos usar o web3 para obter a localização dos dadosweb3.utils.soliditySha3({ type: "uint", value: 1 }, {type: "uint", value: 7})usuário 1web3.eth.getStorageAt("0x3505a02BCDFbb225988161a95528bfDb279faD6b", "0xb39221ace053465ec3453ce2b36430bd138b997ecea25c1043da0c366812b828", console.log)web3.eth.getStorageAt("0x3505a02BCDFbb225988161a95528bfDb279faD6b", "0xb39221ace053465ec3453ce2b36430bd138b997ecea25c1043da0c366812b829", console.log)*/
Técnicas Preventivas
- Não armazene informações confidenciais na blockchain.