Swift na linha de frente: por que a segurança não é uma opção, mas uma necessidade
\nVocê programa em Swift, se orgulha do desempenho e da beleza do código. Mas já pensou o quão vulnerável sua aplicação é a ataques? Injeções SQL e XSS (Cross-Site Scripting) não são apenas histórias assustadoras de livros didáticos. São ameaças reais que podem custar seus dados de usuários, reputação e dinheiro.
\nNeste artigo, vamos abordar como proteger sua aplicação Swift (seja um cliente iOS ou um backend em Vapor) contra os dois tipos de ataques mais perigosos. Sem enrolação — apenas exemplos práticos, soluções prontas e código funcional. Vamos lá!
\n\nInjeções SQL em Swift: como hackers "enganam" o banco de dados
\nImagine: um usuário digita em um campo de texto '; DROP TABLE Users; --. Se você inserir diretamente essa string em uma consulta SQL, o banco de dados executará o comando de exclusão. Clássico do gênero.
Em Swift, essa vulnerabilidade é mais comum em frameworks de servidor (Vapor, Kitura) ou ao trabalhar com Core Data e SQLite através de wrappers inseguros.
\n\nExemplo perigoso: como NÃO fazer
\nimport SQLite\n\nlet username = userInput.text // "admin' OR '1'='1"\nlet query = "SELECT * FROM users WHERE name = '\\(username)'"\ntry db.execute(query) // AMEAÇA! Consulta comprometida\n\nEste código é um convite ao desastre. Um invasor pode obter acesso a quaisquer dados ou destruir a tabela.
\n\nAbordagem correta: consultas parametrizadas
\nRegra de ouro: nunca insira dados do usuário diretamente em uma string de consulta. Use parametrização.
\nimport SQLite\n\nlet db = try Connection("path/to/db.sqlite3")\nlet users = Table("users")\nlet name = Expression<String>("name")\n\nlet username = userInput.text // "admin' OR '1'='1"\nlet query = users.filter(name == username) // SEGURO\nlet result = try db.prepare(query)\n\nA biblioteca SQLite.swift escapa automaticamente os caracteres especiais. Para Vapor com Fluent, use o modelo e filtros:
\nimport Fluent\nimport Vapor\n\nstruct UserController: RouteCollection {\n func login(req: Request) async throws -> String {\n let input = try req.content.decode(LoginRequest.self)\n // Fluent parametriza automaticamente a consulta\n let user = try await User.query(on: req.db)\n .filter(\\.$name == input.username)\n .first()\n return user?.name ?? "Not found"\n }\n}\n\nImportante: mesmo se você usar SQL raw no Vapor, aplique SQLBind para vincular os parâmetros.
ORM e Core Data: a ilusão de segurança
\nMuitos desenvolvedores acreditam que Core Data ou Fluent protegem automaticamente contra injeções. Isso é verdade — se você não usar NSExpression com formatação de strings ou SQL raw. Mas lembre-se: qualquer NSPredicate construído através de interpolação de strings é um risco.
// PERIGOSO\nlet predicate = NSPredicate(format: "name == %@", userInput) // Seguro?\n// NÃO! Se userInput contiver '%', pode ocorrer injeção através de substituição.\n\nSempre use %@ com variáveis, nunca %K com chaves, e jamais insira strings através de \\().
Ataques XSS em Swift: quando o invasor injeta JavaScript
\nXSS é um ataque onde um script malicioso é executado no navegador do usuário. Para aplicações iOS, XSS é relevante ao usar WKWebView para exibir conteúdo HTML (por exemplo, em feeds de notícias ou chats).
Cenário real: chat com formatação HTML
\nUm usuário escreve: Olá! <script>alert('XSS')</script>. Se você exibir essa mensagem em uma WebView sem tratamento — o script será executado.
// PERIGOSO\nlet html = "<div>\\(message.text)</div>"\nwebView.loadHTMLString(html, baseURL: nil)\n