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

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

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

Начать курс

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

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

1. Небезопасное хранение данных (Insecure Data Storage)

Самая частая ошибка — сохранение конфиденциальных данных в UserDefaults или Plist-файлах без шифрования.

Проблемный код:

UserDefaults.standard.set("password123", forKey: "userPassword")
UserDefaults.standard.synchronize()

Безопасное решение: Используйте Keychain Services или Data Protection API.

import Security

func savePassword(_ password: String, for account: String) {
    let data = password.data(using: .utf8)!
    let query: [String: Any] = [
        kSecClass as String: kSecClassGenericPassword,
        kSecAttrAccount as String: account,
        kSecValueData as String: data,
        kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly
    ]
    SecItemAdd(query as CFDictionary, nil)
}

2. Отсутствие валидации ввода (Input Validation)

Пользовательский ввод часто содержит вредоносные данные. Всегда проверяйте и санируйте ввод.

Пример SQL-инъекции:

let query = "SELECT * FROM users WHERE name = '\(userInput)'" // Опасно!

Защита: Используйте параметризованные запросы.

let query = "SELECT * FROM users WHERE name = ?"
let statement = try database.prepare(query)
try statement.bind([userInput])

3. Небезопасное сетевое взаимодействие (Insecure Network Communication)

Использование HTTP вместо HTTPS, игнорирование SSL-сертификатов.

Опасный код:

let url = URL(string: "http://example.com/api")! // HTTP, не HTTPS
let task = URLSession.shared.dataTask(with: url) { data, response, error in
    // Обработка данных
}

Безопасный подход:

let url = URL(string: "https://example.com/api")!
let config = URLSessionConfiguration.default
config.tlsMinimumSupportedProtocolVersion = .TLSv12
let session = URLSession(configuration: config)
let task = session.dataTask(with: url) { data, response, error in
    guard let httpResponse = response as? HTTPURLResponse,
          httpResponse.statusCode == 200 else {
        return
    }
    // Обработка данных
}
task.resume()

4. Инъекция кода через WebView (WebView Injection)

Если вы используете WKWebView без ограничений, злоумышленник может выполнить JavaScript-код.

Уязвимый код:

webView.loadHTMLString(htmlContent, baseURL: nil)

Защита: Отключите JavaScript или используйте Content Security Policy.

let config = WKWebViewConfiguration()
let preferences = WKPreferences()
preferences.javaScriptEnabled = false
config.preferences = preferences
let webView = WKWebView(frame: .zero, configuration: config)

5. Незащищённые ключи API и токены (Hardcoded Secrets)

Никогда не храните API-ключи, токены или пароли в исходном коде.

Неправильно:

let apiKey = "sk_live_1234567890abcdef"

Правильно: Используйте .env файлы, серверную авторизацию или облачные сервисы (например, AWS Secrets Manager).

// В Info.plist зашифрованный ключ
if let apiKey = Bundle.main.object(forInfoDictionaryKey: "API_KEY") as? String {
    // Используем ключ
}

6. Недостаточная защита от обратной разработки (Reverse Engineering)

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

Пример защиты:

func isAppTampered() -> Bool {
    // Проверка подписи
    guard let executablePath = Bundle.main.executablePath else { return true }
    var signature = SecStaticCodeCheckValidity(...)
    return signature != errSecSuccess
}

7. Утечка данных через логи (Logging Sensitive Data)

Никогда не логируйте пароли, токены или персональные данные.

Опасно:

print("User password: \(password)")

Безопасно:

print("User authenticated successfully")
// Никогда не выводим sensitive data

8. Неправильная работа с памятью (Memory Management Issues)

Утечки памяти могут привести к раскрытию данных. Используйте weak/unowned ссылки.

class ViewController: UIViewController {
    var closure: (() -> Void)?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Опасно: strong reference cycle
        closure = { [weak self] in
            self?.doSomething()
        }
    }
    
    func doSomething() { }
}

9. Небезопасная обработка URL (Deep Link Hijacking)

Злоумышленники могут перехватывать deep links и перенаправлять пользователей.

Защита: Проверяйте источник URL.

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    guard let sourceApp = options[.sourceApplication] as? String,
          sourceApp == Bundle.main.bundleIdentifier else {
        return false
    }
    // Обработка URL
    return true
}

10. Отсутствие проверки прав доступа (Insufficient Authorization)

Не проверяйте права только на клиенте — злоумышленник может обойти проверку.

Неправильно:

if user.isAdmin {
    // Показываем админ-панель
}

Правильно: Все проверки должны дублироваться на сервере.

// Клиент запрашивает данные
apiClient.fetchAdminPanel { [weak self] result in
    switch result {
    case .success(let data):
        self?.showAdminPanel(data)
    case .failure(let error):
        self?.showError(error)
    }
}

Блоги

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