Swift での安全な iOS 開発:よくある落とし穴を回避し、アプリを強化する
最近では、攻撃者がアプリケーションを侵害しようとするさまざまな方法が存在します。また、サイバー攻撃が増加し続けているため、安全なモバイル アプリケーション、ひいては安全なコーディングに対する需要はかつてないほど高まっています。
したがって、iOS 開発者は、アプリ開発のあらゆる段階でセキュリティを優先する方法も学ぶ必要があります。
Apple の最新プログラミング言語である Swift は、正しく使用された場合にのみ、セキュリティを強化しながら開発を簡素化する豊富なツールとフレームワークを提供します。
この記事では、Swift ベースの iOS アプリによくある 10 のセキュリティ上の落とし穴を調査し、それらを軽減するための実践的な戦略を提供します。
前提条件
本格的に始める前に、次のものが必要です。
-
Swift と iOS 開発に関する実践的な知識
-
Xcode にアクセスします。
-
iOS アプリがサーバーと通信する方法についての基本的な理解。
-
ターミナル/コマンドラインの基本に精通していること。
コード例は実用的で、ステップバイステップで説明されているため、若い開発者でもアクセスしやすいと同時に、アプリのセキュリティを強化したいと考えている経験豊富な開発者にとっても価値があります。
説明する内容:
- Swift iOS アプリケーションで最も蔓延しているセキュリティ トラップは何ですか?
- 1.安全でないデータストレージ
- 2.ネットワーク通信が弱い
- 3.不適切な入力検証
- 4.ハードコーディングの秘密
- 5.不十分な認証と認可
- 6.安全でないロギングとエラー処理
- 7.コードの難読化とリバース エンジニアリングを無視する
- 8.安全でないサードパーティライブラリ
- 9.不十分な生体認証および多要素認証
- 10.定期的なセキュリティテストの無視
Swift iOS アプリケーションで最も蔓延しているセキュリティ トラップは何ですか?
Swift と iOS は堅牢なセキュリティ機能を提供しますが、それでも間違いは発生します。以下に、最も一般的なトラップとその修正方法を示します。
1.安全でないデータストレージ
開発者が犯す最も一般的な間違いの 1 つは、機密データを安全に保管しないことです。パスワード、トークン、さらには個々のユーザー データが、暗号化されていない形式で UserDefaults またはローカル ストレージに誤って残される可能性があります。
UserDefaults は少量のデータには便利ですが、デバイスが侵害された場合に攻撃者が簡単にアクセスできるため、機密データには安全ではありません。
修正方法:
キーチェーン サービス API を使用して、機密データを安全に保存します。キーチェーンはデータを暗号化してデバイスにバインドし、他の不正なアプリケーションやユーザーがアクセスできないようにします。
KeychainAccess や組み込みの SecItemAdd 関数や SecItemCopyMatching 関数などの Swift のライブラリを使用して、認証情報を安全に保存できます。
たとえば、機密データを確実に安全に保管するために、ユーザー パスワードをキーチェーンに保存する方法は次のとおりです。
do {
try keychain.set("userPassword123", key: "userPassword")
} catch {
print("Error saving to Keychain: \(error)")
}
keychain.set("userPassword123", key: "userPassword") を呼び出すと舞台裏で次のようになります。 Apple のネイティブ セキュリティ フレームワークをストレージに使用する KeychainManager クラス内:
import Security
class KeychainManager {
func set(_ value: String, key: String) throws {
// 1. Convert string to Data
guard let data = value.data(using: .utf8) else {
throw NSError(domain: "KeychainManager", code: -1)
}
// 2. Build the query dictionary
let query: [String: Any] = [
// Store as password
kSecClass as String: kSecClassGenericPassword,
// Your app's bundle identifier
kSecAttrService as String: "com.yourapp.keychain",
// "userPassword"
kSecAttrAccount as String: key,
// "userPassword123" encrypted
kSecValueData as String: data,
kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlock
]
// 3. Save to keychain (iOS encrypts it automatically)
let status = SecItemAdd(query as CFDictionary, nil)
// 4. Check if successful
guard status == errSecSuccess else {
throw NSError(domain: "KeychainManager", code: Int(status))
}
}
}
この関数が実行されると、iOS は「userPassword123」などの文字列値を暗号化されたバイナリ データに変換し、デバイスのキーチェーン データベースに安全に保存します。エントリは指定されたキー (たとえば、「userPassword」) の下に保存され、アプリだけがそれにアクセスできます。
キーチェーンはバックグラウンドで、デバイス固有のキーを使用したハードウェアによる暗号化、Face ID または Touch ID によるオプションの生体認証保護、保存されている認証情報を他のアプリが読み取ったり変更したりできないようにするアプリレベルの分離などの強力なセキュリティ機能を活用します。
2.ネットワーク通信が弱い
ネットワーク経由での機密データの送信も、脆弱性が発生しやすい領域です。暗号化されていない HTTP 接続を使用すると、アプリが中間者 (MITM) 攻撃にさらされ、攻撃者が転送中のデータを傍受して変更できるようになります。
問題 :安全でない接続を介してアプリとサーバーの間でデータが移動すると、同じネットワーク (公衆 Wi-Fi など) 上の攻撃者は次のことを行う可能性があります。
-
機密情報 (パスワード、個人データ、支払い詳細) を読み取る
-
リクエストとレスポンスを変更する
-
正規のサーバーになりすます
修正方法:
1.常に HTTPS を使用する
HTTPS は転送中のすべてのデータを暗号化し、攻撃者が読み取れないようにする。 iOS の App Transport Security (ATS) は、安全でない HTTP 接続をデフォルトでブロックすることでこれを強制します。
// ❌ INSECURE - HTTP connection (blocked by ATS by default)
let url = URL(string: "http://api.example.com/login")
// ✅ SECURE - HTTPS connection
let url = URL(string: "https://api.example.com/login")
絶対に必要な場合を除き、Info.plist に ATS 例外を追加しないようにしてください。サードパーティ API が HTTP のみをサポートしている場合は、サードパーティ API に連絡してアップグレードするか、より安全な代替手段を見つけてください。
2.証明書のピン留め (高度な保護) を実装する
HTTPS を使用している場合でも、アプリは依然として高度な MITM 攻撃に対して脆弱である可能性があります。たとえば、攻撃者は (マルウェアまたはソーシャル エンジニアリングを通じて) ユーザーのデバイスに不正な証明書をインストールし、有効に見える HTTPS トラフィックを傍受する可能性があります。攻撃者の偽の証明書はデバイスによって信頼され、「安全な」通信を復号して読み取ることができるようになります。
証明書のピン留めは、アプリが特定のサーバーの証明書のみを信頼し、他の証明書はすべて拒否するようにすることで、この問題を解決します。
証明書のピン留めの仕組み:
アプリは期待される証明書 (またはその公開鍵ハッシュ) を保存し、接続のたびにそれを検証します。
class SecureNetworkManager: NSObject, URLSessionDelegate {
// Store your server's certificate hash
// Get this by running: openssl x509 -in certificate.crt -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64
private let expectedPublicKeyHash = "YOUR_CERTIFICATE_HASH_HERE"
func urlSession(
_ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
) {
// Step 1: Check if this is a server trust challenge (certificate validation)
guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust,
let serverTrust = challenge.protectionSpace.serverTrust
else {
// Not a certificate challenge; use default handling
completionHandler(.performDefaultHandling, nil)
return
}
// Step 2: Validate that the server's certificate matches our pinned certificate
if isValidServerTrust(serverTrust) {
// Certificate matches - proceed with the connection
completionHandler(.useCredential, URLCredential(trust: serverTrust))
} else {
// Certificate doesn't match - reject the connection to prevent MITM attack
completionHandler(.cancelAuthenticationChallenge, nil)
}
}
// Validates the server's certificate against our pinned hash
private func isValidServerTrust(_ serverTrust: SecTrust) -> Bool {
// Extract the server's certificate
guard let serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0) else {
return false
}
// Get the public key from the certificate
let serverPublicKey = SecCertificateCopyKey(serverCertificate)
guard let publicKey = serverPublicKey else {
return false
}
// Convert the public key to data and hash it
var error: Unmanaged<CFError>?
guard let publicKeyData = SecKeyCopyExternalRepresentation(publicKey, &error) as Data? else {
return false
}
// Hash the public key using SHA-256
let publicKeyHash = SHA256.hash(data: publicKeyData)
let publicKeyHashString = Data(publicKeyHash).base64EncodedString()
// Compare with our expected hash
return publicKeyHashString == expectedPublicKeyHash
}
}
このコードの動作を段階的に説明します:
<オル>
urlSession(_:didReceive:completionHandler:) – このメソッドは、アプリが HTTPS 接続を行うたびに呼び出されます。 iOS は「このサーバーの証明書を信頼してもよいですか?」と尋ねます。
認証方法の確認 - これが他の種類の認証ではなく、サーバーの信頼性チャレンジ (証明書の検証) であることを確認します。
証明書を検証します – isValidServerTrust() と呼びます 、
-
接続からサーバーの証明書を抽出します
-
その証明書から公開キーを取得します
-
SHA-256 を使用して公開キーをハッシュします
-
ハッシュを、保存されている予想されるハッシュと比較します
-
ハッシュが一致する場合、サーバーは正当です。
.useCredentialに進みます。 . -
ハッシュが一致しない場合は、MITM 攻撃の可能性があります。
.cancelAuthenticationChallengeでキャンセルします .
では、これはどのようにして MITM 攻撃を防ぐのでしょうか?攻撃者がユーザーのデバイスに不正な証明書をインストールしてトラフィックを傍受したとしても、その証明書のハッシュは固定されたハッシュと一致しません。アプリは接続を拒否し、攻撃者がトラフィックを復号化するのを防ぎます。
3.追加の保護:公衆 Wi-Fi での VPN を推奨します。
また、セキュリティ層を強化するために公共 Wi-Fi を使用している場合は VPN 経由で接続することをユーザーに推奨し、VPN を効果的に使用してデータを安全に保つ方法に関するガイダンスを提供することもできます。
開発者にとって、強力なアプリのセキュリティを維持するには、適切に最適化されたシステムが必要です。遅い Mac を高速化する方法を学ぶことで、よりスムーズなビルド、より迅速なテスト、より安全な全体的な開発ワークフローを確保できます。
3.不適切な入力検証
一部の開発者は正しい入力検証を無視し、SQL インジェクション、リモート コード実行、データ破損などの多数の脆弱性を引き起こします。
Swift は強力な入力サポートを備えていますが、一部の開発者はユーザー入力や API 応答をサニタイズしていません。リアルタイムの API メール検証を組み込むことで、ユーザーは保存または処理される前に正当で適切な形式のメール アドレスを提供できるようになり、セキュリティ リスクとデータ品質の問題の両方が軽減されます。
修正方法:
入力検証は、悪意のあるデータに対する防御の第一線です。 iOS アプリケーションを保護する方法は次のとおりです。
1.パターンを使用してユーザー入力を検証する
処理する前に、正規表現または事前定義されたパターンを使用してユーザー入力を常に検証してください。たとえば、電子メール アドレスを受け入れる場合:
func isValidEmail(_ email: String) -> Bool {
let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
let emailPredicate = NSPredicate(format: "SELF MATCHES %@", emailRegex)
return emailPredicate.evaluate(with: email)
}
// Only accept properly formatted data
guard isValidEmail(userEmail) else {
// Reject invalid input
return
}
これにより、適切にフォーマットされたデータのみが受け入れられるようになり、不正な入力や悪意のある入力がシステムに侵入するのを防ぎます。
2. API レスポンスをサニタイズする
外部データを決して信用しないでください。 API レスポンスを使用する前に、必ず検証してサニタイズしてください。
if let userAge = apiResponse["age"] as? Int,
userAge >= 0 && userAge <= 150 {
// Safe to use
user.age = userAge
} else {
// Handle invalid data appropriately
throw ValidationError.invalidAge
}
3.パラメータ化されたクエリ (最も重要) を使用する
最も危険な間違いは、文字列の連結によってデータベース クエリを構築することです。次の脆弱なコードを考えてみましょう。
// ❌ NEVER DO THIS - Vulnerable to SQL Injection
let username = userInput // Could be: "admin' OR '1'='1"
let query = "SELECT * FROM users WHERE username = '\(username)'"
database.execute(query)
悪意のあるユーザーがユーザー名として admin' OR '1'='1 を入力すると、クエリは次のようになります。
SELECT * FROM users WHERE username = 'admin' OR '1'='1'
これにより、1 人だけではなくデータベース内のすべてのユーザーが返され、機密データが漏洩する可能性があります。安全なソリューションでは、パラメータ化されたクエリを使用します。
// ✅ SAFE - Using parameterized queries
let query = "SELECT * FROM users WHERE username = ?"
database.execute(query, withArgumentsIn: [username])
このアプローチでは、? データベースが SQL コマンドの一部としてではなくパラメータとして扱うプレースホルダーです。ユーザー名の値は、withArgumentsIn で個別に渡されます。 配列。
これは、ユーザーが admin' OR '1'='1 のような SQL コードを挿入しようとしても、 を指定すると、データベースは文字列全体を実行可能な SQL コードではなく、検索対象のリテラル ユーザー名として扱います。データベース エンジンは特殊文字を自動的にエスケープし、SQL インジェクションのリスクを完全に排除します。
パラメータ化されたクエリでは、クエリ構造をデータから分離することで、ユーザー入力によって SQL ステートメントの意図されたロジックが変更されることがなくなります。
4.ハードコーディングの秘密
API キー、認証情報、またはプライベート トークンがソース コードにハードコーディングされている場合も、重大なセキュリティ上の間違いです。攻撃者は、特に一般に公開されたアプリの場合、リバース エンジニアリング ツールを使用して、コンパイルされたバイナリからそのようなシークレットを抽出する可能性があります。
これらの認証情報が公開されると、バックエンド サービスへのアクセスに使用される可能性があり、データ侵害や不正請求につながる可能性があります。
問題 – ハードコードされたシークレット:
// NEVER DO THIS
class APIClient {
private let apiKey = "1234567890abcdef"
private let secretToken = "sk_live_51H..."
func makeRequest() {
// These secrets are embedded in your binary
let headers = ["Authorization": "Bearer \(apiKey)"]
}
}
修正方法:
機密の資格情報をコードに直接保存しないでください。安全な代替手段は次のとおりです。
解決策 1:実行時にバックエンドからシークレットを取得する
最も安全なアプローチは、クライアントにシークレットをまったく保存しないことです。代わりに、ユーザーを認証し、バックエンドで承認された API 呼び出しを実行できるようにします。
class APIClient {
private var sessionToken: String?
// User logs in and receives a temporary session token
func authenticateUser(email: String, password: String) async throws {
let response = try await backend.login(email: email, password: password)
// Store only a temporary, user-specific session token
self.sessionToken = response.sessionToken
}
// Backend handles the actual API calls with the real API key
func fetchUserData() async throws -> UserData {
guard let token = sessionToken else {
throw AuthError.notAuthenticated
}
// Your backend receives this request, validates the session token,
// then uses its own API keys to fetch data from third-party services
return try await backend.getUserData(sessionToken: token)
}
}
仕組み:
アプリが実際の API キーを知ることはありません。ユーザーがデータを必要とする場合、アプリはセッション トークンを使用してリクエストを独自のバックエンド サーバーに送信します。バックエンドはトークンを検証し、安全に保存された独自の API キーを使用して実際のサードパーティ API 呼び出しを行います。こうすることで、本当の秘密がサーバーから流出することはありません。
解決策 2:環境変数または構成ファイル (開発のみ)
開発環境の場合は、バージョン管理から除外されている .xcconfig ファイルを使用します。
// Secrets.xcconfig (add to .gitignore!)
API_KEY = your_dev_api_key_here
API_SECRET = your_dev_secret_here
// Access in your code through Info.plist
class Config {
static let apiKey: String = {
guard let key = Bundle.main.object(forInfoDictionaryKey: "API_KEY") as? String else {
fatalError("API_KEY not found in configuration")
}
return key
}()
}
重要 :このアプローチは、非実稼働環境にのみ適しています。たとえ構成ファイルであっても、本番 API キーをアプリと一緒に配布しないでください。
5.不十分な認証と認可
クライアント側の認証と認可チェックに依存するのは危険です。攻撃者は、ブルート フォースやアプリ/ランタイムの改ざんにより、アプリがこれらのチェックをバイパスし、不正な方法でアクセスできるようにする可能性があります。
修正方法:
-
クライアント側ではなくサーバー側で認証と認可を実行します。
-
認証されたユーザーのログインには、JWT (JSON Web トークン) または OAuth 2.0 を使用します。
-
トークンの盗難の可能性を最小限に抑えるために、トークンの有効期限と更新ロジックを実装する必要があります。
例:JWT を安全に送信する:
let request = URLRequest(url: apiURL)
request.setValue("Bearer \(jwtToken)", forHTTPHeaderField: "Authorization")
6.安全でないロギングとエラー処理
広範かつ安全でないロギング手法や、捕捉されない例外により、ユーザー名、パスワード、API キーなどの機密情報が漏洩する可能性があります。
修正方法:
-
機密情報は慎重に記録してください。
-
制御されたエラー管理を実装し、ユーザーが提示するメッセージに最小限の情報を提供します。
-
個人データをマスクまたは暗号化する安全なロギング ライブラリを実装します。
do {
try someRiskyOperation()
} catch {
// Log error securely
Logger.log("Operation failed: \(error.localizedDescription)")
}
7.コードの難読化とリバース エンジニアリングを無視する
Swift バイナリをリバース エンジニアリングして、機密のビジネス ロジック、アルゴリズム、または隠された秘密を暴露することができます。攻撃者は、Hopper 逆アセンブラー、クラスダンプ、IDA Pro などのツールを使用してアプリを逆コンパイルし、内部でどのように動作するかを分析します。このリスクは、特に小規模なアプリの場合、過小評価されることがよくありますが、どのアプリもターゲットになる可能性があります。
これは、Swift アプリをコンパイルすると、結果のバイナリには以下が含まれることを意味します。
-
クラス名とメソッドのシグネチャ
-
文字列リテラル (URL、エラー メッセージ、キー)
-
コードロジックの構造
-
アルゴリズムの実装
攻撃者はこの情報を抽出し、それを使用してアプリの認証フローを理解してバイパスしたり、独自のアルゴリズムをコピーしたり、ハードコードされた API エンドポイントや「隠されている」と思われたキーを見つけたり、料金を支払わずにロックを解除できるプレミアム機能を発見したりすることができます。
それが悪い理由 – 実際の例:
アプリにプレミアム機能のチェックがあると想像してみましょう。
class FeatureManager {
func isPremiumUser() -> Bool {
// Check if user has premium access
let hasSubscription = UserDefaults.standard.bool(forKey: "premium_unlocked")
return hasSubscription
}
func unlockPremiumFeature() {
guard isPremiumUser() else {
showPaywall()
return
}
// Show premium content
showPremiumContent()
}
}
攻撃者はアプリのリバース エンジニアリングを行い、メソッド isPremiumUser() を発見する可能性があります。 アクセスを制御し、単に UserDefaults をチェックするだけであること premium_unlocked というキー 。その後、ランタイム操作ツールを使用してこの値を true に設定し、ペイウォールを完全にバイパスできることがわかります。
修正方法:
1. Swift コンパイラーの最適化を使用する
デバッグ シンボルを削除し、バイナリを読みにくくする最適化フラグを有効にします。
// In your build settings:
// - Set "Optimization Level" to "-O" (or -Osize) for release builds
// - Enable "Strip Debug Symbols During Copy" = YES
// - Set "Strip Style" to "All Symbols"
これにより、関数名が削除され、コンパイルされたコードが読みにくくなりますが、クラス/メソッド名は部分的に表示されたままになります。
2.シンボル難読化ツールを使用する
SwiftShield などのツールを使用すると、クラス、メソッド、プロパティの名前を意味のない名前に変更できます。
// Before obfuscation (readable to attackers):
class FeatureManager {
func isPremiumUser() -> Bool { ... }
}
// After obfuscation (harder to understand):
class a7f3b2 {
func x9k2m() -> Bool { ... }
}
これによってリバース エンジニアリングが防止されるわけではありませんが、攻撃者がコードの動作を理解することが大幅に困難になります。
3.機密性の高いロジックをサーバーに移動する (ベスト プラクティス)
プレミアム ステータスをローカルで確認するのではなく、サーバー側で確認します。
// ✅ Secure approach - Server validates everything
class FeatureManager {
func unlockPremiumFeature() async {
do {
// Server checks if user truly has premium access
let hasAccess = try await backend.verifyPremiumAccess(userId: currentUserId)
if hasAccess {
showPremiumContent()
} else {
showPaywall()
}
} catch {
// Handle error
showPaywall()
}
}
}
仕組み:
バックエンドは、プレミアム アクセスに関する信頼できる情報源を維持します。たとえ攻撃者がアプリをリバースエンジニアリングしてチェックを回避しようとしても、サーバーは不正なリクエストを拒否します。アプリは単なる UI レイヤーになり、重要な決定はすべてサーバー側で行われ、攻撃者が操作することはできません。
重要な原則は、アプリ コードがパブリックであると想定することです。支払い、アクセス制御、認証などのセキュリティ クリティカルな操作については、クライアント側のチェックに決して依存しないでください。難読化を使用してリバース エンジニアリングを困難にしますが、最終的には機密ロジックを安全なバックエンドに移動します
8.安全でないサードパーティ ライブラリ
サードパーティのライブラリがハッキングされたり、古くなったりすると、危険にさらされます。開発者は、依存関係による潜在的なセキュリティ リスクよりもアプリの機能を誤って優先してしまう可能性があります。ETL ツールは、依存関係関連データの監視と処理を合理化し、脆弱性をより効率的に特定することでさらに役立ちます。
より広範な規模で、強力なデータセンター セキュリティ対策を実装することで、たとえサードパーティのコンポーネントがリスクをもたらしたとしても、基盤となるインフラストラクチャが攻撃に対する耐性を維持できるようになります。
修正方法:
-
高品質でよく管理されたライブラリのみを使用してください。
-
依存関係を更新し、CVE (一般的な脆弱性とエクスポージャ) を監視します。
-
ライブラリ コードが機密データを処理する場合は監査します。
9.不十分な生体認証および多要素認証
ほとんどのアプリケーションはパスワードのみに依存しているため、ハッキングされる可能性があります。 Face ID や Touch ID などの生体認証を有効にすると、ユーザーのセキュリティが強化されます。
修正方法:
-
LocalAuthentication フレームワークを生体認証に結び付けます。
-
生体認証とサーバーベースの認証を組み合わせて、多要素認証 (MFA) を実現します。
import LocalAuthentication
let context = LAContext()
var error: NSError?
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics,
localizedReason: "Access your account") { success, authError in
DispatchQueue.main.async {
if success {
// Proceed securely
} else {
// Handle failure (authError may contain the reason)
print("Authentication failed: \(authError?.localizedDescription ?? "Unknown error")")
}
}
}
} else {
// Biometrics not available, check error for details
print("Biometrics unavailable: \(error?.localizedDescription ?? "Unknown error")")
}
10.定期的なセキュリティテストの無視
アプリには、開発中にベスト プラクティスに従っているにもかかわらず、複雑な相互作用、サードパーティの依存関係、または新たに発見された攻撃ベクトルから生じる未調査の脆弱性が含まれていることがよくあります。攻撃者が悪用する前にこれらの脆弱性を発見するには、定期的なセキュリティ テストが不可欠です。
セキュリティ テストは、アクセス可能なツールと実践方法を使用して、複数の段階で実施する必要があります。
<オル>自動セキュリティ スキャン: ビルドごとに自動的に実行して、一般的な問題を検出します。
自己実施のコード監査: 確立されたガイドラインを使用して、セキュリティに重点を置いて独自のコードを定期的にレビューします。
脆弱性スキャン ツール: MobSF などの無料ツールを使用して、アプリにセキュリティ上の欠陥がないか分析します。
依存関係の監査: サードパーティのライブラリに既知のセキュリティ脆弱性がないかチェックします。
修正方法:
1. CI/CD で自動セキュリティ スキャンを実装します。
セキュリティ スキャン ツールを継続的統合パイプラインに統合して、すべてのコード変更が自動的にチェックされるようにします。
# Example: GitHub Actions workflow for automated security scanning
name: Security Scan
on: [push, pull_request]
jobs:
security-scan:
runs-on: macos-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Run MobSF Security Scan
run: |
# Mobile Security Framework - scans for common vulnerabilities
docker run -v $(pwd):/app opensecurity/mobile-security-framework-mobsf
- name: Dependency Vulnerability Check
run: |
# Check CocoaPods/SPM dependencies for known CVEs
brew install dependency-check
dependency-check --scan ./Podfile.lock --format JSON
- name: Secret Detection
run: |
# Detect accidentally committed secrets
brew install truffleHog
truffleHog filesystem . --json
- name: Fail build on critical issues
run: |
if grep -q "CRITICAL" security-report.json; then
echo "Critical security issues found!"
exit 1
fi
自動スキャンでは以下がチェックされます:
-
ハードコードされた API キー、トークン、またはパスワード
-
安全でないネットワーク構成 (HTTPS の代わりに HTTP を許可)
-
弱い暗号アルゴリズム
-
サードパーティ ライブラリの既知の脆弱性
-
不適切な SSL/TLS 証明書の検証
-
安全でないデータ ストレージ (UserDefaults に機密データを保存)
-
過剰なアプリ権限
自動スキャンからの出力例:
Security Scan Results:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[CRITICAL] Hardcoded API Key Found
File: APIClient.swift:15
Issue: API key "sk_live_abc123..." detected in source code
[HIGH] Insecure HTTP Connection
File: NetworkManager.swift:42
Issue: App allows cleartext HTTP traffic to api.example.com
Fix: Enforce HTTPS or add exception to Info.plist if required
[MEDIUM] Weak Encryption Algorithm
File: DataEncryption.swift:28
Issue: Using MD5 for hashing (cryptographically broken)
Fix: Use SHA-256 or better
[LOW] Outdated Dependency
Library: Alamofire 4.2.0
Issue: Known vulnerability CVE-2021-12345
Fix: Update to version 5.6.0 or later
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Build Failed: 2 critical issues must be fixed before deployment
2.脆弱性分析にはMobSF (モバイル セキュリティ フレームワーク) を使用します。
MobSF は、iOS アプリのセキュリティ問題を分析する無料の自動ツールです。
# Install and run MobSF locally
docker pull opensecurity/mobile-security-framework-mobsf
docker run -it -p 8000:8000 opensecurity/mobile-security-framework-mobsf
# Upload your .ipa file through the web interface at localhost:8000
# MobSF will analyze and provide a detailed security report
MobSF がチェックする内容:
-
ハードコードされたシークレットのバイナリ分析
-
安全でないデータ ストレージ パターン
-
弱い暗号実装
-
安全でないネットワーク接続
-
コードの品質とセキュリティのベスト プラクティス
-
セキュリティ基準への準拠
3. OWASP MSTG を使用して定期的にコード監査を実施する
OWASP モバイル セキュリティ テスト ガイドをチェックリストとして使用して、独自のコードを監査します。
// Example: Following OWASP MSTG recommendations for secure storage
class SecureStorage {
// ❌ Insecure - UserDefaults is not encrypted
func saveTokenInsecurely(_ token: String) {
UserDefaults.standard.set(token, forKey: "authToken")
}
// ✅ Secure - Using Keychain as OWASP recommends
func saveTokenSecurely(_ token: String) throws {
let data = token.data(using: .utf8)!
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: "authToken",
kSecValueData as String: data,
kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly
]
SecItemDelete(query as CFDictionary)
let status = SecItemAdd(query as CFDictionary, nil)
guard status == errSecSuccess else {
throw StorageError.saveFailed
}
}
}
自己監査用の OWASP MSTG チェックリスト:
-
[ ] すべての機密データは保存時に暗号化されていますか?
-
[ ] HTTPS はすべてのネットワーク呼び出しに対して強制されますか?
-
[ ] 証明書は適切に検証されていますか?
-
[ ] 機密データはログから除外されますか?
-
[ ] API キーとシークレットはハードコーディングされていませんか?
-
[ ] ユーザー入力は検証され、サニタイズされていますか?
-
[ ] 認証トークンはキーチェーンに安全に保存されていますか?
4.自動依存関係スキャン
新しく発見された脆弱性がないか依存関係を継続的に監視します。
# For CocoaPods projects
gem install cocoapods-audit
pod audit
# For Swift Package Manager
# Use GitHub Dependabot (free for public repos) or
brew install swift-outdated
swift-outdated
また、次のツールを使用して自動アラートを設定します。
-
GitHub 依存ボット: 脆弱な依存関係が検出されたときに PR を自動的に作成します (無料)
-
スニック :オープンソース プロジェクトで利用できる無料枠
-
OWASP 依存関係チェック: 無料のコマンドライン ツール
結論
Swift を使用して安全な iOS アプリを開発するには、先進的な考え方が必要です。安全でないデータの保存、不十分なネットワーク通信、ハードコーディングされたシークレット、不適切な認証などの一般的なエラーを回避するためにできる限りのことを行う必要があります。
機密情報にキーチェーンを使用すること、HTTPS を要求すること、入力検証、多要素認証はすべてリスクを軽減する手順です。
セキュリティの脆弱性を定期的にテストし、サードパーティ ライブラリの使用を制限することによって、アプリのセキュリティをさらに強化することもできます。
セキュリティには継続的な責任が伴います。 Swift はツールを提供しますが、開発者はそれらのツールを慎重に適用する必要があります。最初からセキュリティに取り組むことで、ユーザーの情報が保護され、信頼が生まれ、アプリケーションの評判が保護されます。
無料でコーディングを学びましょう。 freeCodeCamp のオープンソース カリキュラムは、40,000 人以上の人々が開発者としての職に就くのに役立ちました。始めましょう
-
Outlook の連絡先を iCloud にすばやくエクスポート:4 つの実績のある方法
「Outlook の連絡先を iCloud にすばやくエクスポートする方法を知っている人はいますか?」 Outlook の連絡先は、さまざまな方法を使用して iCloud にエクスポートできます。 iCloud と Outlook はさまざまな連絡先形式をサポートしていますが、技術的な知識を必要とせずにシームレスに操作できます。 多くの人がバックアップ目的で Outlook の連絡先を iCloud に保存しようとしていますが、タスクを実行するための知識がないため、難しいと感じています。したがって、これを念頭に置いて、Outlook の連絡先を iCloud に効率的にエクスポートするさま
-
究極ガイド:新しい iPhone に SIM カードを挿入する – ステップバイステップの説明
[究極ガイド] 新しい iPhone に SIM カードを挿入する方法 この記事では、新しいiPhoneにSIMカードを挿入する方法を説明します。新しい SIM カードを新しい iPhone で使用するには、このまま読み続けてください。 5 月まで / 2024 年 9 月 5 日に更新 これを共有してください: 新しい iPhone に SIM カードを挿入する方法 SIM カードのサイズは時間の経過とともに進化しており、互換性は iPhone ごとに異なります。まず最初に、SIM が iPhone のモデルに適合しているかどうかを確認する必要があります。 i