iOSアプリのセキュリティ

こんにちは、Habr! Arlind Aliuによる、iOSアプリケーションの機密データのセキュリティの基本原則に関する記事「すべてのiOSアプリのアプリケーションセキュリティマストに関する記事の翻訳を紹介します。



アプリケーションセキュリティは、ソフトウェア開発の最も重要な側面の1つです。 アプリケーションユーザーは、提供する情報が安全に保護されることを望みます。 したがって、誰かに機密情報を与えることはできません。



幸いなことに、この記事では、開発者がアプリケーションで犯す間違いとその解決方法について説明します。

カットの下で続けた。



間違った場所でのデータストレージ



AppStoreのいくつかのアプリケーションの調査を行ったところ、多くの人が同じ間違いを犯しました。機密情報は本来あるべきではない場所に保管されています。

UserDefaultsに個人データを保存すると、リスクにさらされます。 UserDefaultsは、アプリケーションの「設定」フォルダー内にあるプロパティのリストを持つファイルに保存されます。 データは、暗号化のわずかなヒントなしでアプリケーションに保存されます。



iMazingなどのサードパーティプログラムをMacにインストールすると、電話をハッキングする必要はありませんが、AppStoreからインストールされたアプリケーションのすべてのUserDefaultsデータをすぐに見ることができます。 このようなプログラムを使用すると、iPhoneにインストールされているアプリケーションのデータを監視および管理できます。 任意のアプリケーションのUserDefaultsを簡単に取得できます。

これが、私が記事を書くことにした主な理由です-トークン、アクティブおよび更新可能なサブスクリプション、利用可能な金額など、 UserDefaultsにデータを保存する多数のアプリケーションをAppStoreで見つけました。 これらのデータはすべて、アプリケーションの有料サブスクリプションの管理からネットワークレベルでのハッキングまで、悪意を持って簡単に取得して使用できます。



そして今、データを保存する方法について。



アプリケーション内の設定、つまりユーザーに機密ではないデータなど、わずかな情報のみをUserDefaultsに保存する必要があることを忘れないでください。



Appleの専用セキュリティサービスを使用して、個人情報を保存します。 キーチェーンAPIサービスを使用すると、一定量のユーザーデータを暗号化されたデータベースに保存できます。 そこには、クレジットカード情報や小さな重要なメモなど、ユーザーのパスワードやその他の重要なデータを保存できます。

また、暗号化されたキーと証明書を使用する場合があります。



キーチェーンAPIサービス



以下は、キーチェーンにユーザーのパスワードを保存する方法の例です。



class KeychainService { func save(_ password: String, for account: String) { let password = password.data(using: String.Encoding.utf8)! let query: [String: Any] = [kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: account, kSecValueData as String: password] let status = SecItemAdd(query as CFDictionary, nil) guard status == errSecSuccess else { return print("save error") } }
      
      





kSecClass辞書の一部:kSecClassGenericPasswordは、暗号化する必要がある情報がパスワードであることを意味します。 次に、 SecItemAddメソッドを呼び出して、キーチェーンに新しいパスワードを追加します。 バンドルからのデータの取得は、保存に似ています。



 func retrivePassword(for account: String) -> String? { let query: [String: Any] = [kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: account, kSecMatchLimit as String: kSecMatchLimitOne, kSecReturnData as String: kCFBooleanTrue] var retrivedData: AnyObject? = nil let _ = SecItemCopyMatching(query as CFDictionary, &retrivedData) guard let data = retrivedData as? Data else {return nil} return String(data: data, encoding: String.Encoding.utf8) }
      
      





データの保存と受信の正確性に関する小さなチェックを書きましょう。



 func testPaswordRetrive() { let password = "123456" let account = "User" keyChainService.save(password, for: account) XCTAssertEqual(keyChainService.retrivePassword(for: account), password) }
      
      





一見すると、特に複数のパスワードを保存する必要がある場合、キーチェーンAPIを使用するのは非常に難しいように思われるので、これらの目的でFacadeパターンを使用することをお勧めします。 アプリケーションのニーズに応じてデータを保存および変更できます。



このパターンについて、さらに複雑なサブシステムの単純なラッパーを作成する方法について詳しく知りたい場合は、この記事が役立ちます。 また、インターネットには、 SAMKeychainSwiftKeychainWrapperなど、キーチェーンAPIの使用を支援するオープンライブラリが多数あります。



パスワードの保存と承認



私の開発キャリアでは、常に同じ問題に直面しています。 開発者は、アプリケーションにパスワードを保存するか、サーバーへのリクエストを作成し、サーバーがユーザー名とパスワードを直接送信します。



UserDefaultにデータを保存する場合、記事の最初の部分の情報を読んだ後、リスクの大きさをすでに理解しています。 パスワードをキーチェーンに保存すると、アプリケーションのセキュリティレベルが大幅に向上しますが、機密情報をどこかに保存する前に、まずそれを暗号化する必要があります。



ハッカーがネットワークを介して私たちを攻撃できるとします。 したがって、彼は生のテキストの形式でパスワードを受け取ります。 もちろん、すべてのパスワードをハッシュ化することをお勧めします。



個人データの暗号化



ハッシュを自分でやるのはやり過ぎのように思えるので、この記事ではCryptoSwiftライブラリを使用します。 Swiftで使用される多くの標準の信頼できる暗号化アルゴリズムを収集しました。



CryptoSwiftアルゴリズムを使用して、キーチェーンからパスワードを保存および取得してみましょう。



 func saveEncryptedPassword(_ password: String, for account: String) { let salt = Array("salty".utf8) let key = try! HKDF(password: Array(password.utf8), salt: salt, variant: .sha256).calculate().toHexString() keychainService.save(key, for: account) }
      
      





上記の関数は、ユーザー名とパスワードを記録し、暗号化された文字列としてキーチェーンに保存します。



内部で何が起こるか見てみましょう:



-ユーザー名とパスワードは文字列としてソルト変数に書き込まれます

-sha256はSHA-2ハッシュを埋めます

-HKDFは、メッセージ認証コード( HMAC )に基づくキー生成関数( KDF )です



ハッカーのタスクを複雑にするために、salt変数を作成しました。 パスワードを暗号化することしかできませんでしたが、この場合、攻撃者は最も頻繁に使用されるパスワードのリストを持つことができ、問題なくそれらを暗号化し、暗号化されたパスワードと比較します。 その後、特定のアカウントのパスワードを見つけることは難しくありません。

これで、アカウントと生成されたキーを使用してログインできます。



 authManager.login(key, user)
      
      





もちろん、サーバーはソルト変数で暗号化されているものを知っている必要があります。 バックエンドは、同じアルゴリズムを使用してユーザーを識別するキーを比較できます。

このアプローチを使用すると、アプリケーションのセキュリティが大幅に向上します。



完了として



アプリケーションのセキュリティを決して無視しないでください。 この記事では、まず、 UserDefaultsに機密データを保存した場合の結果と、キーチェーンが必要な理由を把握しました。



第二部では、より深刻なレベルのセキュリティ、データを保存する前に暗号化すること、および個人データを含む情報をサーバーに正しく転送する方法について説明します。



All Articles