Безопасность Swift приложений: топ-10 уязвимостей для начинающих

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Безопасность Swift приложений: топ-10 уязвимостей для начинающих

Разработка на Swift для iOS и macOS требует особого внимания к безопасности. Даже небольшие ошибки могут привести к утечке данных или взлому приложения. В этой статье мы разберём 10 самых распространённых уязвимостей, с которыми сталкиваются начинающие разработчики, и покажем, как их избежать.

1. Небезопасное хранение данных в UserDefaults

Многие новички сохраняют конфиденциальные данные (пароли, токены) в UserDefaults. Это зона общего пользования, данные хранятся в открытом виде.

// ❌ Опасно
UserDefaults.standard.set("secret_password", forKey: "userPass")

// ✅ Безопасно — используем Keychain
import Security
let query: [String: Any] = [
    kSecClass as String: kSecClassGenericPassword,
    kSecAttrAccount as String: "userPass",
    kSecValueData as String: "secret_password".data(using: .utf8)!
]
SecItemAdd(query as CFDictionary, nil)

2. Инъекции SQL в Core Data

Использование строковых предикатов с пользовательским вводом открывает путь к SQL-инъекциям.

// ❌ Уязвимо
let input = "admin' OR '1'='1"
let predicate = NSPredicate(format: "name == %@", input)

// ✅ Безопасно — используем параметризированные запросы
let safePredicate = NSPredicate(format: "name == %@", input)

3. Отсутствие валидации ввода

Доверие к пользовательскому вводу — одна из главных ошибок. Злоумышленник может отправить вредоносные данные через текстовые поля.

func processUserInput(_ text: String) {
    // ❌ Пропускаем любой ввод
    let url = URL(string: "https://api.example.com/search?q=\(text)")
    
    // ✅ Проверяем и экранируем
    guard let encoded = text.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else { return }
    let safeUrl = URL(string: "https://api.example.com/search?q=\(encoded)")
}

4. Небезопасное сетевое соединение (HTTP вместо HTTPS)

Использование HTTP делает данные уязвимыми для перехвата. Всегда используйте HTTPS.

// ❌ Опасно
let config = URLSessionConfiguration.default
config.waitsForConnectivity = false

// ✅ Безопасно — принудительно HTTPS
let config = URLSessionConfiguration.default
config.connectionProxyDictionary?.removeAll()
config.tlsMinimumSupportedProtocolVersion = .TLSv12

5. Утечка данных через логи

Разработчики часто оставляют print() с конфиденциальными данными в production-сборке.

// ❌ Опасно
print("User token: \(token)")

// ✅ Безопасно — используем условную компиляцию
#if DEBUG
print("Debug: token length = \(token.count)")
#endif

6. Неправильное управление памятью (Retain Cycles)

Утечки памяти могут привести к DoS-атакам. Используйте слабые ссылки в замыканиях.

// ❌ Утечка памяти
class ViewController: UIViewController {
    var handler: (() -> Void)?
    override func viewDidLoad() {
        handler = {
            self.view.backgroundColor = .red // Сильная ссылка
        }
    }
}

// ✅ Безопасно — слабая ссылка
handler = { [weak self] in
    self?.view.backgroundColor = .red
}

7. Отсутствие проверки подлинности URL-схем

Мошеннические приложения могут перехватывать URL-схемы вашего приложения.

// ❌ Уязвимо
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    // Обрабатываем любой URL
    return true
}

// ✅ Безопасно — проверяем источник
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    guard let sourceApp = options[.sourceApplication] as? String,
          sourceApp == "com.trusted.app" else {
        return false
    }
    // Обработка URL
    return true
}

8. Использование устаревших API

Старые функции (например, UIWebView) имеют известные уязвимости. Всегда используйте современные альтернативы.

// ❌ Устарело и небезопасно
let webView = UIWebView()
webView.loadHTMLString(htmlString, baseURL: nil)

// ✅ Современный подход
let webView = WKWebView()
webView.loadHTMLString(htmlString, baseURL: nil)

9. Небезопасное кэширование данных

Кэширование может сохранять конфиденциальные данные на устройстве.

// ❌ Опасно — кэшируем всё
let request = URLRequest(url: url)
URLCache.shared.storeCachedResponse(CachedURLResponse(response: response, data: data), for: request)

// ✅ Безопасно — отключаем кэш для чувствительных данных
var request = URLRequest(url: url)
request.cachePolicy = .reloadIgnoringLocalCacheData

10. Отсутствие защиты от Reverse Engineering

Код на Swift можно декомпилировать. Используйте обфускацию и проверки целостности.

// ❌ Лёгкий для анализа код
func checkLicense() -> Bool {
    return true
}

// ✅ Безопасно — обфускация и проверка
func checkLicense() -> Bool {
    #if !DEBUG
    // Проверка целостности бинарника
    guard Bundle.main.bundleIdentifier == "com.yourcompany.app" else {
        return false
    }
    #endif
    return true
}

Заключение

Безопасность Swift-приложений — это не разовая задача, а постоянный процесс. Начинающим разработчикам важно помнить:

  • Никогда не храните пароли и токены в UserDefaults
  • Всегда валидируйте пользовательский ввод
  • Используйте только HTTPS для сетевых запросов
  • Избегайте утечек данных через логи
  • Регулярно обновляйте зависимости и API

Применяя эти простые правила на практике, вы значительно снизите риск взлома вашего приложения. Помните: безопасность начинается с первого написанного вами кода. Удачи в разработке!

Блоги

Рекомендаций по книгам