MASTG-KNOW-0096: Bancos de Dados Realm

Realm Objective-C e Realm Swift não são fornecidos pela Apple, mas ainda assim merecem destaque. Eles armazenam todos os dados não criptografados, a menos que a configuração tenha a criptografia habilitada.

O exemplo a seguir demonstra como usar criptografia com um banco de dados Realm:

// Abre o arquivo Realm criptografado, onde getKey() é um método para obter uma chave do Keychain ou de um servidor
let config = Realm.Configuration(encryptionKey: getKey())
do {
  let realm = try Realm(configuration: config)
  // Use o Realm normalmente
} catch let error as NSError {
  // Se a chave de criptografia estiver incorreta, `error` indicará que é um banco de dados inválido
  fatalError("Erro ao abrir o realm: \(error)")
}

O acesso aos dados depende da criptografia: bancos de dados não criptografados são facilmente acessíveis, enquanto os criptografados exigem uma investigação sobre como a chave é gerenciada — seja ela embutida no código (hardcoded), armazenada sem criptografia em um local inseguro, como preferências compartilhadas (shared preferences), ou de forma segura no KeyStore da plataforma (que é a melhor prática). No entanto, se um invasor tiver acesso suficiente ao dispositivo (por exemplo, acesso com jailbreak) ou puder reempacotar o aplicativo, ele ainda poderá recuperar chaves de criptografia em tempo de execução usando ferramentas como o Frida. O seguinte script do Frida demonstra como interceptar a chave de criptografia do Realm e acessar o conteúdo do banco de dados criptografado.

function nsdataToHex(data) {
    var hexStr = '';
    for (var i = 0; i < data.length(); i++) {
        var byte = Memory.readU8(data.bytes().add(i));
        hexStr += ('0' + (byte & 0xFF).toString(16)).slice(-2);
    }
    return hexStr;
}

function HookRealm() {
    if (ObjC.available) {
        console.log("ObjC está disponível. Tentando interceptar classes do Realm...");
        const RLMRealmConfiguration = ObjC.classes.RLMRealmConfiguration;
        Interceptor.attach(ObjC.classes.RLMRealmConfiguration['- setEncryptionKey:'].implementation, {
            onEnter: function(args) {
                var encryptionKeyData = new ObjC.Object(args[2]);
                console.log(`Comprimento da Chave de Criptografia: ${encryptionKeyData.length()}`);
                // Exibe o conteúdo hexadecimal da chave de criptografia
                var encryptionKeyBytes = encryptionKeyData.bytes();
                console.log(hexdump(encryptionKeyBytes, {
                    offset: 0,
                    length: encryptionKeyData.length(),
                    header: true,
                    ansi: true
                }));

                // Converte os bytes da chave de criptografia para uma string hexadecimal
                var encryptionKeyHex = nsdataToHex(encryptionKeyData);
                console.log(`Chave de Criptografia em Hexadecimal: ${encryptionKeyHex}`);
            },
            onLeave: function(retval) {
                console.log('Saindo de RLMRealmConfiguration.- setEncryptionKey:');
            }
        });

    }

}