Skip to content
advanced Phase 12 · Security

Secure Coding Practices

Prevent common iOS vulnerabilities: injection, insecure storage, and privacy violations.

50m
3 problems
Topic Progress 0%

Common Vulnerabilities

OWASP Mobile Top 10

The OWASP Mobile Top 10 lists the most critical mobile security risks:

  1. Improper Credential Usage: Hardcoded API keys, weak storage
  2. Inadequate Supply Chain Security: Compromised third-party libraries
  3. Insecure Authentication: Weak session management
  4. Insufficient Input Validation: Injection attacks
  5. Insecure Communication: Unencrypted data transmission
  6. Inadequate Privacy Controls: Excessive data collection
  7. Insufficient Binary Protections: Lack of code obfuscation
  8. Security Misconfiguration: Incorrect ATS, overly permissive entitlements
  9. Insecure Data Storage: Plaintext sensitive data
  10. Insufficient Cryptography: Weak or outdated algorithms

Hardcoded Secrets

Never hardcode API keys, passwords, or secrets in source code:

// BAD: Hardcoded API key
let apiKey = "sk_live_abc123def456"

// GOOD: Read from environment or secure storage
let apiKey = Bundle.main.infoDictionary?["API_KEY"] as? String
// Or better: fetch from Keychain or server at runtime

Insecure Logging

// BAD: Logging sensitive data
print("User password: \(password)")
print("Credit card: \(cardNumber)")

// GOOD: Use os_log with privacy annotations
import os.log
let logger = Logger(subsystem: "com.app", category: "auth")
logger.info("Login attempt for user: \(privacy: .public, username)")
// Sensitive data is redacted automatically

Clipboard Exposure

Sensitive data in the clipboard can be accessed by other apps:

// BAD: Copying sensitive data to clipboard
UIPasteboard.general.string = authToken

// GOOD: Use ephemeral clipboard with timeout
UIPasteboard.general.string = otpCode
DispatchQueue.main.asyncAfter(deadline: .now() + 30) {
    if UIPasteboard.general.string == otpCode {
        UIPasteboard.general.string = nil
    }
}

Input Validation

Server-Side Validation

Never trust client-side validation alone. Always validate on the server:

// Client-side validation for UX
func validateEmail(_ email: String) -> Bool {
    let pattern = "^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$"
    return email.range(of: pattern, options: .regularExpression) != nil
}

// Server validates again regardless of client validation

SQL Injection Prevention

Use parameterized queries or Core Data instead of string interpolation:

// BAD: SQL injection vulnerability
let query = "SELECT * FROM users WHERE name = '\(userInput)'"

// GOOD: Parameterized query
let statement = try database.prepare(
    "SELECT * FROM users WHERE name = ?"
)
try statement.bind(userInput)

// BETTER: Use CoreData with predicate
let predicate = NSPredicate(format: "name == %@", userInput)
let request = NSFetchRequest<User>(entityName: "User")
request.predicate = predicate

URL Scheme Validation

Validate URLs before opening them to prevent phishing:

func handleIncomingURL(_ url: URL) {
    guard url.scheme == "myapp" else { return }
    guard url.host == "callback" else { return }
    
    // Validate and sanitize query parameters
    guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false) else { return }
    let token = components.queryItems?.first(where: { $0.name == "token" })?.value
    
    // Validate token format
    guard let token = token, token.count == 32 else { return }
    processToken(token)
}

WebView Security

// BAD: Allowing arbitrary JavaScript
webView.configuration.preferences.javaScriptEnabled = true

// GOOD: Restrict web content
let config = WKWebViewConfiguration()
config.suppressesIncrementalRendering = true

// Validate URLs loaded in webview
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction) async -> WKNavigationActionPolicy {
    guard let url = navigationAction.request.url else { return .cancel }
    let allowedHosts = ["trusted-domain.com"]
    
    if allowedHosts.contains(url.host ?? "") {
        return .allow
    }
    return .cancel
}

Privacy & Permissions

Info.plist Permissions

iOS requires usage descriptions for privacy-sensitive APIs:

<key>NSCameraUsageDescription</key>
<string>We need camera access to scan documents</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>We need photo access to save your edits</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>We use your location to show nearby stores</string>
<key>NSFaceIDUsageDescription</key>
<string>Face ID secures your account</string>

Runtime Permission Checks

Always check permission before accessing sensitive APIs:

import AVFoundation

class CameraManager {
    func checkPermission() async -> Bool {
        switch AVCaptureDevice.authorizationStatus(for: .video) {
        case .authorized: return true
        case .notDetermined:
            return await AVCaptureDevice.requestAccess(for: .video)
        case .denied, .restricted:
            return false
        @unknown default: return false
        }
    }
}

App Tracking Transparency

Required for tracking users across apps:

import AppTrackingTransparency

func requestTracking() async -> Bool {
    let status = await ATTrackingManager.requestTrackingAuthorization()
    return status == .authorized
}

Data Collection Minimization

Follow the principle of least privilege:

  • Only request permissions you actually need
  • Collect only the data required for your feature
  • Provide clear explanations for each permission request
  • Allow users to use your app with limited permissions when possible

Privacy Nutrition Labels

App Store requires privacy labels that declare data collection. Be accurate about:

  • What data you collect
  • How it is used
  • Whether it is linked to identity
  • Whether it is used for tracking

Quiz

1. Which OWASP category covers hardcoded API keys?

Question 1 options

2. Why should you never log sensitive data?

Question 2 options

3. How do you prevent SQL injection in iOS?

Question 3 options

4. What must you add to Info.plist for camera access?

Question 4 options

Flashcards

Question

What are the OWASP Mobile Top 10?

Answer

The ten most critical mobile security risks: improper credentials, supply chain, auth, input validation, insecure communication, privacy, binary protection, misconfiguration, data storage, and cryptography.

Question

Why use parameterized queries instead of string interpolation?

Answer

Parameterized queries separate SQL code from user data, preventing SQL injection where malicious input is interpreted as SQL commands.

Question

What is App Tracking Transparency?

Answer

An iOS framework that requires user permission before apps can track their activity across other companies apps and websites for advertising.

Revision Notes

Key Takeaways

  • 1. Never hardcode API keys or secrets in source code
  • 2. Always validate input on both client and server sides
  • 3. Use parameterized queries to prevent injection attacks
  • 4. Check and request permissions before accessing sensitive APIs
  • 5. Minimize data collection and follow privacy principles

Interview Tips

  • Discuss common iOS security vulnerabilities from OWASP Mobile Top 10
  • Explain how to prevent SQL injection in a CoreData app
  • Describe best practices for handling user credentials
  • Walk through implementing proper input validation

Cheat Sheet

Secure Coding Quick Reference

  • Never hardcode secrets in source code
  • Use os_log with privacy annotations
  • Validate all input on both client and server
  • Use parameterized queries to prevent SQL injection
  • Check permissions before accessing sensitive APIs
  • Follow data collection minimization principle