Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. iOS SDK
Code

Segurança da comunicação no iOS

by
Length:LongLanguages:

Portuguese (Português) translation by David Batista (you can also view the original English article)

Segurança mobile se tornou um tema quente. Para qualquer aplicativo que se comunique remotamente, é importante considerar a segurança dos dados do usuário que estão sendo enviados através de uma rede. Neste post, vocês aprenderão as melhores práticas da atualidade para a segurança da comunicação no seu aplicativo iOS em Swift.

Uso do HTTPS

Ao desenvolver seus aplicativos, considere limitar as solicitações de rede apenas as que são essenciais. Para esses pedidos, tenha certeza que eles são feitas através em HTTPS e não HTTP - isso irá ajudar a proteger os dados dos seus usuários de ataques "man-in-the-middle", onde outro computador na rede age como um retransmissor para sua rede, mas que escuta ou altera os dados que passam por ele. A tendência nos últimos anos é ter todas as conexão feitas através do HTTPS. Felizmente para nós, as novas versões do Xcode já reforça isso.

Para criar uma simples solicitação HTTPS no iOS, tudo que precisamos fazer é acrescentar um "s" na seção "http" da URL. Isso funciona para APIs como URLSession, NSURLConnection e CFNetwork, bem como frameworks populares de terceiros, como AFNetworking.

App Transport Security

Ao longo dos anos, o HTTPS tem sofrido diversos ataques. Uma vez que é importante ter o HTTPS configurado corretamente, a Apple criou o App Transport Security (ATS abreviado). O ATS garante que as conexões do seu aplicativo estão usando os protocolos padrões da industria, de modo que você não envie acidentalmente os dados dos usuários de forma insegura. A boa noticia é que o ATS está ativo por padrão para aplicativos feitos com as versões atuais do Xcode.

O ATS está disponível a partir do iOS 9 e do OS X El Capitan. Os aplicativos disponíveis atualmente na loja, não necessariamente exigem o ATS, mas os aplicativos criados com as versões mais recentes do Xcode e seus SDKs o terão habilitados por padrão. Algumas das boas práticas aplicadas pelo ATS inclui o uso da versão 1.2 ou maior do TLS, sigilo através da troca de chaves ECDHE, criptografia AES-128 e o uso de pelo menos um certificado SHA-2.

É importante notar que apesar do ATS estar habilitado automaticamente, isso não significa necessariamente que o ATS esteja sendo aplicado no seu aplicativo. O ATS trabalha nas classes base, tais como URLSession e NSURLConnection e nas interfaces baseadas no fluxo CFNetwork. O ATS não está aplicado em interfaces de rede de baixo nível tais como sockets, sockets CFNetwork ou qualquer framework de terceiro que use essas chamadas de baixo nível. Então se você está usando conexão de baixo nível, você deve ser cuidadoso e implementar as boas práticas do ATS manualmente.

Excessões do ATS

Uma vez que o ATS reforça o uso do HTTPS e outros protocolos de segurança, você pode imaginar se você ainda poderá fazer conexões que não suportam o HTTPS, tais como quando você baixa imagens a partir de um cache CDN. Não se preocupe, você pode controlar o ATS configurando domínios específicos no arquivo plist do seu projeto, procure seu arquivo info.plist, clique com o botão direito nele e escolha Open As > Source Code.

Você encontrará uma seção chamada de NSAppTransportSecurity. Se ela não existir, você pode adiciona-la; o formato é como abaixo.

Isso permite que você altere as configurações do ATS para todas as suas conexões. Algumas das configurações mais comuns são as seguintes:

  • NSAllowsArbitraryLoads: Desabilita o ATS. Não use isso! Versões futuras do Xcode irão remover esta chave.
  • NSAllowsArbitraryLoadsForMedia: Permite carregar mídias sem as restrições do ATS para o frameworks AV Foundation. Você só deve permitir loads inseguro se sua mídia já estiver encriptada por outros meios. (Disponível no iOS 10 e macOS 10.12)
  • NSAllowsArbitraryLoadsInWebContent: Pode ser usado para desligar restrições do ATS para a web view do seu aplicativo. Pense antes de desliga-lo, pois isso permite que usuários carreguem conteúdo inseguros dentro do seu aplicativo. (Disponível no iOS 10 e macOS 10.12)
  • NSAllowsLocalNetworking: Isso é usado para permitir que recursos de rede local possam carregar sem as restrições do ATS. (Disponível no iOS 10 e macOS 10.12)

O dicionário NSExceptionDomains deixa você definir configurações para domínios específicos. Aqui está uma descrição de algumas chaves úteis que você pode usar em seus domínios:

  • NSExceptionAllowsInsecureHTTPLoads: Permite que o dominio especifico use conexões que não sejam HTTPS.
  • NSIncludesSubdomains: Especifica se a regras atuais são passadas para os subdomínios.
  • NSExceptionMinimumTLSVersion: Usado para especificar versões mais antigas e seguras do TLS mas que são permitidas.

Perfect Forward Secrecy

Embora o tráfego criptografado seja ilegível, ele ainda pode ser armazenado. Se a chave privada usada para criptografar o tráfego for comprometida no futuro, a chave pode ser usada para ler todo o tráfego armazenado anteriormente.

Para evitar esse tipo de acontecimento, o Perfect Forward Secrecy (PFS) gera uma chave de seção que é única para cada seção de comunicação. Se a chave de uma seção específica for comprometida, ela não comprometerá os dados de nenhuma outra seção. O ATS implementa o PFS por padrão e você pode controlar essa funcionalidade usando a chave NSExceptionRequiresForwardSecrecy na plist. Desliga-la permitirá ao TLS suportar cifras que não suportem o perfect forward secrecy.

Certificado de Transparência

Certificado de transparência é um próximo padrão projetado para ser capaz de verificar ou auditar os certificados apresentados durante a configuração de uma conexão HTTPS.

Quando seu host configura um certificado HTTPS, ele é emitido pelo que chamamos de Autoridade de Certificação (CA). O Certificado de Transparência visa ter monitoramento em tempo real para encontrar certificados emitidos de forma maliciosa ou se for emitido por uma autoridade de certificado comprometida.

Quando um certificado é emitido, a autoridade de certificação deve enviar o certificado em anexo para alguns registros de certificado, que podem ser verificados posteriormente pelo cliente e examinado pelo dono do domínio. O certificado deve existir em pelo menos dois logs para que o certificado seja válido.

A chave do plist para esta funcionalidade é a NSRequiresCertificateTransparency. Habilitando-a aplicará o Certificado de Transparência. Ela está disponível no iOS 10 e macOS 10.12 ou posterior.

Certificado e Chave Pública

Quando você adquiri um certificado para o uso do HTTPS em seu servidor, este certificado é considera legitimo porque esta assinado com um certificado de uma autoridade de certificação intermediaria. Este certificado usado pela autoridade intermediaria pode por sua vez ser assinado por outra autoridade intermediaria  e assim por diante, desde que o último certificado seja assinado por uma autoridade de certificação raiz confiável.

Quando uma conexão HTTPS é estabelecida, estes certificados são apresentados ao cliente. Esta cadeira de confiança é avaliada para se ter certeza que os certificados são assinados corretamente por uma autoridade de certificação confiável do iOS. (Existem maneiras de passar por esta verificação e aceitar seu certificado assinado por você mesmo para teste, mas não faça isso em ambiente de produção.)

Se um dos certificados da cadeia não for válido, então o cadeia inteira é considerada invalida e sua informação não será enviada pela conexão não confiável. Embora este seja um bom sistema, não é infalível. Existem vários pontos fracos que podem fazer o iOS confiar no certificado do invasor, ao invez de um certificado assinado legitimamente.

Por exemplo, proxies de interceptação podem possuir um certificado intermediaria que é verdadeiro. Uma engenharia reversa pode instruir manualmente o iOS a aceitar seu próprio certificado. Além disso, a política de uma empresa pode ter provisionado o dispositivo para aceitar seu próprio certificado. Tudo isso leva à capacidade de realizar um ataque "man-in-the-middle" no seu tráfego, permitindo que ele seja lido. No entanto, o deposito de certificados impedirá que as conexões sejam estabelecidas para todos esses cenários.

Deposito de certificado vem ao resgate verificando o certificado do servidor contra a cópia do certificado esperado.

Para implementar o deposito, o seguinte delegate deve ser implementado. Para URLSession, faça o seguinte:

Ou para NSURLConnection, você pode usar:

Ambos os métodos permitem a você obter um objeto SecTrust do challenge.protectionSpace.serverTrust. Como estamos sobrescrevendo os delegates de autenticação, agora precisamos chamar explicitamente a função que executa as verificações padrão da cadeia de certificados que acabamos de discutir. Faça isso chamando a função SecTrustEvaluate. Então poderemos comparar o certificado do servidor com o esperado.

Aqui está um exemplo de implementação.

Para usar este código, atribua o delegate ao URLSession quando criar sua conexão.

Certifique-se de incluir o certificado no bundle do seu aplicativo. Se seu certificado é um arquivo .pem, você precisará converte-lo para um arquivo .cert no terminal do macOS.

openssl x509 -inform PEM -in mycert.pem -outform DER -out certificate.cer

Agora, se o certificado for alterado por um invasor, seu aplicativo pode detecta-lo e se recusar a manter uma conexão.

Saiba que alguns frameworks de terceiros, tal como AFNetworking, já suportam o deposito.

Sanitização e Validação

Com todas as proteções até agora, suas conexões devem ser bastante seguras contra o ataques "man-in-the-middle". Mas mesmo assim, uma regra importante a respeito das comunicações em rede é nunca confiar cegamento na informação que você está recebendo. De fato, é uma boa prática de programação a programação por contrato. Onde as entradas e saídas dos seus métodos tem um contrato que define as expectativas específicas da interface; se a interface diz que retornará um NSNumber, então deverá fase-lo. Se o seu servidor está esperando uma string com 24 caracteres ou menos, certifique-se que a interface retornará até 24 caracteres.

Isso ajuda a previnir erros inocentes, mas muito importantes, isso também reduz a probabilidade de vários ataques de injeções ou de corrupção de memória. Parsers comuns, como a classe JSONSerialization irá converter texto em tipos de dados do Swift onde esses tipos de teste pode ser feito.

Outros parsers podem funcionar com objetos equivalentes em Objective-C. Aqui está uma forma de validar se um objeto é do tipo esperado em Swift.

Antes de você chamar o método delegate, garanta que o objeto é do tipo certo para que ele responda ao método - caso contrário o aplicativo falhará com um erro "unrecognized selector".

Além disso, você pode ver se um objeto está em conformidade com um protocolo antes de tentar enviar uma mensagem para ele:

Ou você pode verificar se ele corresponde a um tipo de objeto do Core Foundation.

É uma boa ideia ser cuidadoso ao escolher qual informação do servidor o usuário pode ver. Por exemplo, é uma má ideia exibir um alerta de erro que passa diretamente uma mensagem do servidor. As mensagens de erro podem revelar informações de depuração e segurança. Uma solução é fazer com que o servidor envie códigos específicos de erro que fazem com que o cliente exiba uma mensagem pré definidas.

Além disso, certifique-se de codificar suas URLs para que elas contenham apenas caracteres válidos. O stringByAddingPercentEscapesUsingEncoding da NSString funcionará. Ele não codifica alguns caracteres, tipo o & e o sinal de mais, mas a função CFURLCreateStringByAddingPercentEscapes permite customizar o que será codificado.

Sanitizando os Dados do Usuário

Ao enviar dados a um servidor, seja extremamente cuidadoso com qualquer entrada de dados passada pelo usuário em comandos que serão executadas por um servidor SQL ou um servidor que executará o código. Apesar da segurança de um servidor contra ataques deste tipo, esteja fora do escopo deste artigo, como desenvolvedores mobile podemos fazer a nossa parte, removendo caracteres para a linguagem que o servidor está usando para que a entrada não seja suscetível a ataques de injeção de comando. Como exemplo temos as aspas, ponto e vírgula e barras quando não são necessários para a entrada do usuário específico.

É uma boa prática limitar o tamanho da entrada. Podemos limitar o número de caracteres digitados em um campo de texto configurando o delegate do UITextField e então implementar o método shouldChangeCharactersInRange.

Para um UITextView, o método a ser implementado é este:

A entrada do usuário pode ser validada de modo que a informação seja do formato esperado. Por exemplo, se um usuário entrar com um endereço de email, podemos verificar se é um email valido:

Se o usuário for subir uma image para o servidor, podemos verificar se essa imagem é valida. Por exemplo, para um arquivo JPEG, os dois primeiros bytes e os dois últimos são sempre FF D8 e DD D9. 

A lista continua, mas apenas você como desenvolvedor saberá qual as entradas e saídas esperadas, tendo em conta dos requisitos de desenvolvimento.

URLCache

A informação que você envia pela rede tem o potencial de ser cacheada em memória e no armazenamento do aparelho. Você pode ir mais longe para proteger sua rede de comunicação, como nós temos feito, apenas para descobrir que a comunicação esta sendo armazenada.

Várias versões do iOS tem tido algum comportamento inesperado quando se trata de configuração de cache, e algumas das regras sobre o que é mantido em cache no iOS continuam mudando a cada versão. Apesar do cache ajudar na performance da rede, reduzindo o número de requisições, pode ser uma boa ideia desliga-lo para alguns dados que você acredite ser altamente sensível. Você pode remover o cache compartilhado a qualquer momento (como na inicialização do aplicativo) chamando: 

Para desabilitar o cache em um nível global, use:

E se você estiver usando o URLSession, você pode desabilitar o cacha para a seção usando isso:

Se você esta usando um objeto NSURLConnection com um delegate, você pode desabilitar o cache por conexão com este método delegate:

E para criar uma requisição URL que não verificará o cache, use:

Varias versões do iOS 8 vinham com alguns bugs onde alguns desses métodos por contra própria não fariam nada sozinhos. Isso significa que é uma boa ideia implementar todos os códigos acima para comunicações sensíveis, quando você precisar evitar de forma confiável o cacheamento das requisições de rede.

O Futuro

É importante entender os limites do HTTPS para a proteção das comunicações de rede.

Na maioria dos casos, o HTTPS para no servidor. Por exemplo, minha conexão para um servidor corporativo pode ser através do HTTPS, mas uma vez que o trafego atinja o servidor, ele não é criptografado. Isso significa que a empresa será capaz de ver as informações que foram enviadas (na maioria dos casos ela precisa), e isso também significa que a empresa poderia então procurar ou passar essas informações novamente sem criptografia.

E não podemos finalizar este artigo sem cobrir mais um conceito que é uma tendência recente - a qual é chamada "criptográfica de ponta-a-ponta". Um bom exemplo é um aplicativo de chat criptografado onde dois aparelhos mobile se comunicam entre si através de um servidor. Os dois aparelhos criam chaves publicas e privadas - eles trocam as chaves publicas, enquanto suas chaves privadas nunca deixam o aparelho. Os dados ainda são enviados através do HTTPS para o servidor, mas eles são encriptados primeiro pela chave pública da outra parte de tal forma que apenas os aparelhos que têm a chave pública podem descriptografar as mensagens um do outros.

Uma analogia para ajuda-los a entender a criptografia de ponta-a-ponta, imagina que eu quero que alguém me envie uma mensagem com segurança que apenas eu possa ler. Então eu forneço a eles uma caixa com um cadeado aberto (a chave pública) enquanto eu fico com a chave do cadeado (chave privada). O usuário escreve uma mensagem, coloca dentro da caixa, fecha o cadeado, e envia de volta para mim. Apenas eu posso ler o que esta escrito na mensagem porque eu sou o único com a chave do cadeado fechado.

Com a criptografia de ponta-a-ponta, o servidores fornecem um serviço para comunicação, mas eles não podem ler o conteúdo da comunicação - eles enviam a caixa fechada, mas eles não tem a chave para abri-las. Apesar dos detalhes da implementação estão além do escopo deste artigo, ele é um conceito poderoso se você quer fornecer comunicação segura entre os usuário do seu aplicativo.

Se você quer aprender mais sobre esta abordagem, um lugar para começar é o repositório do GitHub Open Whisper System, um projeto open-source. 

Conclusão

Quase todos os aplicativo mobile de hoje em dia se comunicam através de uma rede, e a segurança é extremamente importante mas muitas vezes é um aspecto esquecido no desenvolvimento.

Neste artigo, nos cobrimos algumas das boas práticas de segurança, incluindo o simples HTTPS, o endurecimento de aplicação de comunicações de rede, sanitização de dados e a codificação de ponta-a-ponta. Estas boas práticas devem servir como uma base para segurança quando desenvolver seu aplicativo mobile.

E ja que está aqui, verifica algum dos outros cursos e tutorias populares de aplicativos iOS!

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.