O Objective-C, ou ObjC, é uma linguagem de programação orientada a objeto derivada diretamente do C, mas sem relação com o C++. Essa linguagem é usada principalmente para o desenvolvimento no ambiente Cocoa, tanto para Mac quanto para os dispositivos iPhone e iPad. Não é uma linguagem nova – ela existe desde a década de 1980. Porém, com a recente popularização do iPhone, criou-se uma nova leva de programadores que estão aprendendo só agora essa linguagem.
Adicione a isso à própria plataforma Cocoa. Trata-se de uma plataforma de desenvolvimento extremamente completa e fácil de usar, porém radicalmente diferente das ferramentas do mundo Windows, do desenvolvimento Java e outras plataformas de desenvolvimento mais populares. Como seria de se esperar, uma plataforma “nova” de desenvolvimento com uma linguagem “nova” apresenta desafios para os desenvolvedores. Um desses desafios é a questão da segurança.
Para falar sobre todos os aspectos de segurança envolvidos na plataforma e na linguagem ObjC, seria necessário um livro com muitas e muitas páginas, não apenas um artigo. Escolhi, portanto, dois tópicos bastante relevantes no que tange à segurança nessa plataforma para fazer uma introdução do assunto.
A volta do buffer overflow
Desenvolvedores oriundos de linguagens como C# e Java vão perceber uma certa similaridade entre essas linguagens e o Objective-C. Claro, todas são derivadas da linguagem criada por Kernighan e Ritchie, o tão conhecido e usado “C”. Objective-C é portanto uma linguagem “prima” do C# e do Java. Porém, ao contrário de suas colaterais mais modernas, o Objective-C não conta com validação automática de tamanhos de array. O que isso quer dizer para a segurança do sistema? Isso significa a possibilidade de buffer overflow. Claro que o buffer overflow é uma preocupação em todas as linguagens, mesmo C#, Java e similares. Mas nelas é uma preocupação muito menor. Em ObjC, a possibilidade de gerar código inseguro aumenta significativamente.
Felizmente, a própria plataforma de desenvolvimento Cocoa oferece algumas alternativas para as situações mais comuns. Por exemplo, as strings podem ser manipuladas através das classes derivadas de NSString. Toda a plataforma é direcionada ao uso da NSString, NSMutableString e suas derivadas. E esses objetos, que nada mais são que strings unicode encapsuladas, dispõem de proteção contra buffer overflow. Assim, embora o Objective-C permita que você crie um “char *” e use “strcpy” ou “sprintf” como a linguagem “C” padrão, não existe de fato nenhum motivo para você fazer isso.
A regra é usar NSString no desenvolvimento Cocoa e isso, além de conveniente, evita o buffer overflow. Porém, o problema não se limita a strings. Arrays de qualquer tipo que envolvam dados de entrada ou de saída do sistema podem, potencialmente, causar problemas. Sempre verifique o tamanho da informação contra a capacidade do array, nesses casos.
A vulnerabilidade do cliente rico
Todas as aplicações com clientes ricos, independentemente da plataforma, compartilham um problema em comum: a possibilidade de contorno de código do cliente. Isso ocorre porque todo o código que está rodando no hardware do usuário é potencialmente alterável ou contornável por um usuário mal intencionado. Aplicativos cliente/servidor são sempre vulneráveis a esse tipo de ataque. Muito fácil reconhecer o problema tomando por analogia o código JavaScript de uma página web. Esse código roda no cliente, e todos nós sabemos o quão fácil é alterar o javascript de uma página ou meramente desabilitar aquele código.
O código escrito em ObjC não é assim tão fácil de alterar, mas não é impossível e, em algumas situações, pode ser bem simples. Suponha que você faça a verificação de uma regra crítica de segurança no cliente. Por exemplo, apresente determinada informação apenas se o usuário for administrador do sistema. Para isso, você define uma variável global “ehAdm” como true ou false no momento do logon. Depois disso, verifique apenas a variável local, para evitar ter que ir ao servidor para pegar a informação. Usando um iPad desbloqueado, um usuário pode fazer a engenharia reversa e alterar o código em questão e mostrar a informação sempre. Isso é mais fácil de fazer do que parece. Mas não seria a forma mais simples. Se o seu programa recebe os dados, mas só mostra se o usuário for administrador, basta contornar este controle: o usuário pode instalar um interceptador de mensagens na comunicação.
Existem algumas ferramentas para isso, sendo a mais comum o Pirni, que requer o jailbreak do iPad, e atua como um Wireshark ou Ethereal no dispositivo. Outra ferramenta útil para esse tipo de teste é o DiskAid, que pode ser usado mesmo em iPads ou iPhones bloqueados, porém requer a conexão física destes via cabo. O DiskAid abre o dispositivo como um sistema de disco, permitindo a obtenção do código executável dos aplicativos, bases de dados locais e arquivos temporários da aplicação.
A solução para o problema do contorno do cliente rico é basicamente a mesma para qualquer plataforma: todo controle de segurança deve ser feito no servidor, em código fora do alcance do usuário final. Se o dado só pode ser visível por administradores, o servidor só deve enviá-lo para o iPhone ou iPad quando o usuário for administrador. O cliente rico pode ser usado para fazer validações prévias, para apresentar a informação de uma forma atrativa visualmente, mas a validação de segurança final tem que ser sempre no servidor.
Conclusão
A plataforma Cocoa para desenvolvimento e a linguagem Objective-C são ferramentas poderosas para a criação de sistemas. Embora sejam novidade para muitos programadores, é uma plataforma estável e amadurecida há muitos anos. Como em qualquer linguagem ou plataforma, o maior risco é fazer o sistema sem se preocupar com os aspectos de segurança.