Безопасность 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)
}
}