Keychain é um armazenamento seguro de credenciais no iOS, watchOS, macOS e tvOS que gerencia senhas, chaves e certificados a nível de hardware. Ao contrário do UserDefaults, os dados no Keychain são criptografados e isolados por sandbox da aplicação. De acordo com Apple Developer Documentation, o Keychain utiliza mecanismos Secure Enclave e criptografia de hardware AES-256 para proteger informações confidenciais.
Pontos principais
Keychain é um banco de dados seguro do sistema operacional Apple projetado para armazenamento seguro de senhas, chaves criptográficas, certificados e outros dados confidenciais. O Keychain apareceu pela primeira vez no Mac OS 8.6 em 1999, e no iOS — desde a primeira versão do SDK.
O Keychain resolve um problema fundamental do desenvolvimento móvel: armazenar segredos (tokens, senhas, chaves de criptografia) em um sistema de arquivos não seguro. Ao contrário do UserDefaults ou SQLite, os dados no Keychain são armazenados criptografados e são automaticamente criptografados ao serem escritos no disco.
Cada aplicação iOS opera em uma sandbox isolada e tem acesso apenas ao seu próprio keychain. No entanto, o desenvolvedor pode configurar acesso compartilhado ao Keychain entre aplicações do mesmo desenvolvedor através de keychain access groups. O iCloud Keychain do usuário sincroniza adicionalmente os dados entre dispositivos através de criptografia de ponta a ponta.
De acordo com o Apple Security White Paper (2025), o Keychain usa criptografia de hardware AES-256 com uma chave vinculada ao identificador único do dispositivo (UID), tornando os dados inacessíveis quando extraídos do dispositivo.
O Keychain funciona como um serviço em camadas: a aplicação acessa o Security framework, que se comunica com o daemon securityd que gerencia o banco de dados SQLite criptografado do Keychain. Cada registro é criptografado com uma chave separada, e as chaves são protegidas pelo módulo de hardware Secure Enclave em dispositivos com chip A7 e posteriores.
O Security framework fornece uma interface C para trabalhar com Keychain Services. Funções principais: SecItemAdd (adicionar), SecItemCopyMatching (pesquisar), SecItemUpdate (atualizar) e SecItemDelete (excluir). Cada operação aceita um dicionário de atributos CFDictionaryRef descrevendo o tipo de solicitação.
Os dados são classificados por classes: kSecClassGenericPassword (senha arbitrária), kSecClassInternetPassword (senha de serviço de internet), kSecClassCertificate (certificado), kSecClassKey (chave criptográfica) e kSecClassIdentity (par chave-certificado).
Ao salvar uma senha, a aplicação cria um dicionário com atributos: serviço, conta, nível de acesso, rótulo. O Security framework passa os dados para o daemon securityd, que criptografa o registro com uma chave vinculada ao dispositivo e o armazena no SQLite do Keychain. A recuperação funciona de forma similar: consulta por atributos, pesquisa, descriptografia e retorno de dados.
Uma característica importante: ao excluir uma aplicação, o iOS automaticamente limpa os registros do Keychain criados por essa aplicação (desde iOS 10.3+). Ao reinstalar a aplicação, os dados do Keychain da instalação anterior não estão disponíveis a menos que o iCloud Keychain tenha sido usado.
import Security
func savePassword(service: String, account: String, password: Data) {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: account,
kSecValueData as String: password,
kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked
]
SecItemAdd(query as CFDictionary, nil)
}
O Keychain suporta cinco classes principais de dados, cada uma com seu próprio conjunto de atributos e escopo de aplicação. A escolha da classe determina quais chaves de pesquisa estão disponíveis e como os dados são criptografados.
As classes kSecClassGenericPassword e kSecClassInternetPassword são projetadas para armazenar senhas de texto. A versão Internet armazena adicionalmente dados do servidor: domínio, protocolo, porta e caminho de autenticação. O GenericPassword é usado para armazenar qualquer senha sem vinculação ao servidor.
Ao salvar uma senha de internet, você pode especificar kSecAttrServer (domínio), kSecAttrProtocol (HTTPS, FTP, etc.), kSecAttrPort e kSecAttrPath. Isso permite identificar precisamente o registro durante o preenchimento automático via AutoFill.
A classe kSecClassKey armazena chaves simétricas (AES) e assimétricas (RSA, EC). A classe kSecClassCertificate armazena certificados X.509. A classe kSecClassIdentity combina uma chave privada e seu certificado correspondente em um único registro.
Para chaves assimétricas, o Keychain suporta atributos: kSecAttrKeyType (RSA, EC), kSecAttrKeySizeInBits (2048, 256), kSecAttrIsPermanent (salvar no Keychain). Para certificados: kSecAttrLabel (nome legível), kSecAttrSubject (DN do proprietário), kSecAttrIssuer (DN do emissor).
| Classe Keychain | Propósito | Tipo de dado |
|---|---|---|
| kSecClassGenericPassword | Senha de aplicação | Data (NSString) |
| kSecClassInternetPassword | Senha de servidor | Data + atributos do servidor |
| kSecClassCertificate | Certificado X.509 | SecCertificate |
| kSecClassKey | Chave criptográfica | SecKey |
| kSecClassIdentity | Chave + certificado | SecIdentity |
A interface principal para interagir com o Keychain no código nativo iOS são as funções do Security framework. Para Swift e Objective-C, uma única interface C está disponível, encapsulada em funções convenientes.
A função SecItemAdd adiciona um novo item ao Keychain. Ela recebe como entrada um dicionário com classe, dados e atributos. Retorna o status errSecSuccess (0) ou um código de erro. A função SecItemCopyMatching realiza uma pesquisa por atributos e retorna os dados encontrados.
Para pesquisa, usa-se o indicador kSecReturnData — se true, a função retorna o conteúdo do registro. O indicador kSecMatchLimit determina o número de resultados: kSecMatchLimitOne (um) ou kSecMatchLimitAll (todos).
func readPassword(service: String, account: String) -> Data? {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: account,
kSecReturnData as String: true,
kSecMatchLimit as String: kSecMatchLimitOne
]
var item: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &item)
guard status == errSecSuccess else { return nil }
return item as? Data
}
SecItemUpdate permite alterar atributos ou dados de um registro existente. SecItemDelete exclui todos os registros que correspondem ao dicionário passado. Ao excluir, é importante especificar atributos suficientes para não excluir acidentalmente registros de outros no keychain compartilhado.
func deletePassword(service: String, account: String) {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: account
]
SecItemDelete(query as CFDictionary)
}
Cada registro do Keychain tem o atributo kSecAttrAccessible, que determina quando os dados estão disponíveis para leitura. Isso é criticamente importante para a segurança: o nível de acesso errado pode tornar os dados vulneráveis ou, ao contrário, indisponíveis quando necessário.
kSecAttrAccessibleWhenUnlocked — dados disponíveis apenas quando o dispositivo está desbloqueado. kSecAttrAccessibleAfterFirstUnlock — disponíveis após o primeiro desbloqueio após reinicialização. kSecAttrAccessibleAlways — sempre disponíveis (não recomendado). O sufixo ThisDeviceOnly impede a transferência de dados através de backup.
Em dispositivos com Secure Enclave, a chave de criptografia do Keychain pode ser adicionalmente protegida por biometria: kSecAccessControlBiometryCurrentSet ou kSecAccessControlUserPresence. Isso adiciona um requisito de Face ID ou Touch ID para cada operação de leitura.
iCloud Keychain sincroniza registros entre dispositivos Apple através de criptografia de ponta a ponta. A Apple não tem acesso aos dados descriptografados. Para habilitar a sincronização, adicione o atributo kSecAttrSynchronizable com o valor kCFBooleanTrue.
Importante: registros sincronizados não podem conter o atributo ThisDeviceOnly, pois devem estar disponíveis em outros dispositivos. Se todos os dispositivos forem perdidos, o iCloud Keychain pode ser restaurado através de um código de recuperação ou chave de recuperação do iCloud.
Para tokens de autenticação, use kSecAttrAccessibleWhenUnlockedThisDeviceOnly — dados disponíveis apenas quando o dispositivo está desbloqueado e não copiados para backup. Para certificados que precisam estar disponíveis para tarefas em segundo plano, use kSecAttrAccessibleAfterFirstUnlock. Nunca use kSecAttrAccessibleAlways para dados confidenciais.
Recomenda-se sempre adicionar o sufixo ThisDeviceOnly para dados que não requerem sincronização. Isso evita a cópia acidental de segredos para o iCloud ou iTunes backup, onde poderiam ser extraídos por ferramentas de análise. Para dados críticos, combine acessibilidade com kSecAccessControlUserPresence — isso adiciona um requisito biométrico ou de código para descriptografar o registro.
Ao usar iCloud Keychain, lembre-se de que registros sincronizados estão disponíveis em todos os dispositivos do usuário: se um invasor obtiver acesso a um dispositivo, os dados podem ser comprometidos em todos. Para segredos isolados, use ThisDeviceOnly.
Perguntas frequentes
UserDefaults armazena dados em texto simples em um arquivo .plist, acessível durante a análise do IPA. O Keychain criptografa cada registro separadamente, usa criptografia de hardware e suporta níveis de acesso, biometria e sincronização via iCloud.
A cada inicialização do simulador iOS, o Keychain é limpo. Em um dispositivo real, exclua o aplicativo — o iOS removerá todos os registros Keychain desse desenvolvedor. Para limpeza seletiva, chame SecItemDelete com os atributos apropriados.
Sim, através de keychain access groups. Os aplicativos devem ter o mesmo team ID no perfil de provisionamento e entitlements com o mesmo keychain-access-groups. O desenvolvedor configura o acesso compartilhado no Xcode Capabilities.
A Apple não documenta um limite estrito, mas na prática recomenda-se não exceder 1–4 KB por registro. Para volumes maiores, use criptografia de arquivos e armazene a chave no Keychain, enquanto os dados em Documents.
Em um dispositivo com jailbreak, a proteção do Keychain é reduzida porque o invasor obtém acesso root e pode ler o SQLite do Keychain diretamente. Para dados críticos, use criptografia adicional com uma chave obtida do servidor.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também