Johdanto iOS-järjestelmän turvalliseen tietojen varastointiin

Arkaluonteisten käyttäjätietojen suojaaminen on jokaisen iOS-sovelluksen perusvastuu. Tallennatpa sitten tunnistetunnuksia, salausavaimia tai yksityisiä tunnusmerkkejä, alusta tarjoaa erityisen laitteiston tukeman ratkaisun: [Keychain[]. Toisin kuin [] tai omaisuusluettelotiedostoja, Keychain salaa tiedot levällään ja valvoo tiukasti pääsyn valvontaa. Tämä artikkeli tarjoaa kattavan oppaan tietoturvallisen tiedon tallentamisen toteuttamisesta Keychainin kanssa, joka kattaa sekä alkuperäisen turvallisuuskehyksen että tuotantosovellusten käytännön parhaat käytännöt.

iOS-avainketjun ymmärtäminen

Avainketju on käyttöjärjestelmän hallinnoima turvallinen säilytysastia. Se tallentaa pieniä, arkaluonteisia kohteita. Se tallentaa salasanat, salausavaimet tai varmenteet. Avainketjuun kirjoitettu tieto on suojattu myös silloin, kun laite on lukittu. Avaintoiminnot ovat:

  • Salaus levossa käyttäen laitteistolla varustettua AES-256:ta.
  • Käyttöoikeuden hallinta[] laitteen salasanalla, Kosketustunnuksella tai kasvotunnuksella.
  • Pysyvyys sovelluksen läpi uudelleenasennukset[ (jos konfiguroitu) ja valinnainen iCloud-syncing.
  • Isolaatio[] sovellusten välillä: oletuksena, yksi sovellus ei voi lukea toista sovellusta.

Avainketjua ei ole suunniteltu suurille läiskille; pidä jokainen kohde muutaman kilotavun alla. Suurempien tietojen saamiseksi harkitse API:n tai :n kehyksen käyttöä yhdessä tiedostopohjaisen salauksen kanssa.

Avainketjupalvelut API vs. kolmannen osapuolen kirjastot

Apple tarjoaa natiivi Keychain Services[] API (C-pohjainen, ]), joka on voimakas mutta verbose. Voit käyttää sitä suoraan, tai hyväksyä Swift-ystävällinen wrapper. Suosittu kolmannen osapuolen kirjastot kuten [KeychainAccess[] tai SwiftKeychainWrapper[] vähentää kattilalevy. Kuitenkin ymmärtäminen taustalla API on olennaista vianmääritykseen ja kun tarvitset hienosäätöä hallintaan pääsykäytännöt. Tänään aiomme keskittyä natiivi API kanssa Swift.

Avainketjujen tallennus

Ennen kuin mitään tallennat, sinun täytyy päättää [Keychain-tuoteluokka[. Yleisin yleisillä salasanoilla on [. Internet-salasanat tai varmenteet on olemassa muita luokkia. Jokaiseen kohtaan viitataan attribuuteilla.

Perusvirtaus noudattaa aina tätä kaavaa:

  1. Rakenna kyselysanakirja kohteen luokan ja ominaisuudet.
  2. Soita soveltuva toiminto (, , , ).
  3. Tarkista palautettu () tai virhekoodi.

Ennen kuin kirjoitat koodin, tuo turvamoduuli:

import Security
import Foundation // for Data and String utilities

Tietojen säilyttäminen avainketjussa

Kirjoitetaan yleissalasana

Tallenna poletin (esim. JWT) nykyiselle käyttäjälle:

func saveToken(_ token: String, forAccount account: String) -> Bool {
 guard let tokenData = token.data(using: .utf8) else { return false }

 let query: [String: Any] = [
 kSecClass as String: kSecClassGenericPassword,
 kSecAttrAccount as String: account,
 kSecValueData as String: tokenData,
 // Optional: restrict access to when device is unlocked
 kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly
 ]

 // Delete any existing item first to avoid duplicates
 SecItemDelete(query as CFDictionary)

 let status = SecItemAdd(query as CFDictionary, nil)
 return status == errSecSuccess
}

Keskeiset seikat:

  • toimii ensisijaisena avaimena; valitse yksilöllinen merkkijono (esim. käyttäjätunnus tai vakionumero ).
  • valvoo, milloin kohde voidaan lukea. Käytä parhaan turvallisuuden vuoksi; se estää iCloud-varmistuksen ja rajoittaa pääsyä nykyiseen laitteeseen.
  • Kutsumme ennen kuin lisäät, jotta vältät päällekkäisten kohteiden keräämisen. Vaihtoehtoisesti voit käyttää .

Lisätään kulunvalvonta (biometria tai salakoodi)

Erittäin arkaluonteisten tietojen osalta vaaditaan kosketustunniste tai kasvotunniste ennen lukemista:

let accessControl = SecAccessControlCreateWithFlags(
 nil,
 kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
 .userPresence, // requires passcode, Face ID, or Touch ID
 nil
)

let query: [String: Any] = [
 kSecClass as String: kSecClassGenericPassword,
 kSecAttrAccount as String: account,
 kSecValueData as String: tokenData,
 kSecAttrAccessControl as String: accessControl as Any
]
SecItemAdd(query as CFDictionary, nil)

Nyt mikä tahansa kutsu tämän kohteen käynnistää biometrinen tai salasanan pikaviesti. Käytä alkaen Paikallisen luvan käsitellä käyttäjän vuorovaikutusta hienovaraisesti.

Avainketjusta saatujen tietojen noutaminen

Tallennetun rahakkeen lukemiseksi:

func retrieveToken(forAccount account: String) -> String? {
 let query: [String: Any] = [
 kSecClass as String: kSecClassGenericPassword,
 kSecAttrAccount as String: account,
 kSecReturnData as String: true,
 kSecMatchLimit as String: kSecMatchLimitOne
 ]

 var item: CFTypeRef?
 let status = SecItemCopyMatching(query as CFDictionary, &item)

 guard status == errSecSuccess,
 let data = item as? Data,
 let token = String(data: data, encoding: .utf8) else {
 return nil
 }
 return token
}

Aseta kohtaan saadaksesi tiedot takaisin. Käytä hakeaksesi yhden tuloksen. Jos jätät rajan, API voi palauttaa matriisin.

Tärkeintä:[] Käyttäessään kulunhallintaa (biometriaa) ] puhelu saattaa palata ], jos käyttäjä peruuttaa. Käsittele tämä tapaus erikseen eikä koskaan palaa tavalliseen tekstitallenteeseen.

Avainketjujen osien päivittäminen ja poistaminen

Olemassa olevan esineen päivittäminen

Käyttää poiston ja uudelleen lisäämisen sijasta :

func updateToken(_ newToken: String, forAccount account: String) -> Bool {
 guard let newData = newToken.data(using: .utf8) else { return false }

 let query: [String: Any] = [
 kSecClass as String: kSecClassGenericPassword,
 kSecAttrAccount as String: account
 ]

 let attributesToUpdate: [String: Any] = [
 kSecValueData as String: newData
 ]

 let status = SecItemUpdate(query as CFDictionary, attributesToUpdate as CFDictionary)
 return status == errSecSuccess
}

Tämä on tehokkaampaa kuin device+add, ja se välttää mahdolliset kilpailuolosuhteet.

Kohteen poistaminen

func deleteItem(forAccount account: String) -> Bool {
 let query: [String: Any] = [
 kSecClass as String: kSecClassGenericPassword,
 kSecAttrAccount as String: account
 ]
 let status = SecItemDelete(query as CFDictionary)
 return status == errSecSuccess
}

Ole varovainen, ettet poista muita sovelluksia, jotka jakavat saman hakuryhmän.Aina voit laajentaa kyselyäsi :lla, jos käytät jaettuja avaimenperäketjuja.

Käyttöoikeuden valvonta- ja saavutettavuusominaisuudet

vakio määrittelee ], kun[ voidaan lukea. Valitse kaikkein rajoittavin vaihtoehto, joka vastaa vielä sovelluksesi tarpeita:

AttributeMeaning
kSecAttrAccessibleWhenUnlockedAvailable only while device is unlocked (default).
kSecAttrAccessibleAfterFirstUnlockAvailable after device boots and is unlocked once. Allows background access.
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnlyRequires a passcode to be set. Strictest option—prevents access even after unlock if passcode is removed.
kSecAttrAccessibleWhenUnlockedThisDeviceOnlySame as WhenUnlocked but does not back up to iCloud, and cannot be restored to another device.

Useimmissa sovelluksissa on oikea tasapaino turvallisuuden ja käytettävyyden välillä. Jos haluat lukea taustaesineitä (esim. taustan virkistysmerkki), sinun on käytettävä (ja hyväksyt, että tiedot ovat hieman vähemmän suojattuja).

Virheiden käsittely ja yhteiset jäljet

-toiminnot palauttavat . Tarkista aina ja käsittele vikaa asianmukaisesti.

  • (.25300) ... Mikään kohta ei vastaa kyselyä.
  • (.25299) ... Saman ensisijaisen avaimen sisältävä kohta on jo olemassa (jos et poistanut ensin).
  • (.128) . Käyttäjä peruutti biometrisen hälytyksen.
  • (.25293) ...

Älä koskaan jätä huomiotta epäonnistumistilaa. Armollisesti hajoaa: näytä virheviesti tai yritä uudelleen, mutta älä koskaan tallenna arkaluonteisia tietoja Keychainin ulkopuolelle varalle. Voit käyttää tarkistaa biometrisen saatavuuden ennen kuin yrität päästä käsiksi.

Parhaat käytännöt ja tuotannon näkökohdat

  • Käytä yksilöllisiä, kuvailevia tilinimiä[] käyttäjää tai tuotetyyppiä kohti välttääksesi törmäykset.
  • Aina on ilmoitettava esteettömyysattribuutti[; muussa tapauksessa sovelletaan järjestelmän oletusarvoa ([]), joka ei välttämättä ole ihanteellinen.
  • Tyhjennä avainketjutiedot, kun käyttäjä kirjautuu ulos[].
  • Käytä avainketjua Käyttöryhmät[] vain, kun jaat omia sovelluksia. Vältä laajoja ryhmiä.
  • Älä koskaan säilytä ei-herkkiä tietoja[] (kuten käyttäjäasetukset) Keychain-käytössä tai sen sijaan tietokannassa.
  • ]Siirto, jossa käytetään ja [ edistyneitä skenaarioita varten (macOS Catalyst).
  • Testaa oikealla laitteella[; Simulator käyttää ohjelmistoa, joka toimii eri tavalla kuin laitteistotuki.

Avainketjun käyttö SwiftUI:n ja Async/Awaitin kanssa

Nykyaikaisten sovellusten osalta kiedo avainketjutoiminta näyttelijän tai async-turvaluokan avulla, jotta päälanka ei estyisi. Esimerkkinä :

actor KeychainManager {
 func saveToken(_ token: String, for account: String) async -> Bool {
 // same implementation as above, but now it's safe to call from any context
 return saveToken(token, forAccount: account)
 }
}

Jos käytät biometrisiä tietoja, -puhelu voi estää langan kulun odottaessa käyttäjän vuorovaikutusta. Kääri se taustajonoon tai paremmin, käytä ][-menetelmää ennen Keychain-puhelua.

Päätelmä

The iOS Keychain is the correct place to store small, sensitive pieces of data. By using the native Keychain Services API, you gain direct control over encryption, accessibility, and authentication policies. Always pair your Keychain usage with solid error handling and remember to clear data when appropriate. For further reading, refer to the Apple Keychain Service Documentation and the Keychain Concepts overview. Adopting these practices will help you ship iOS apps that respect user privacy and withstand security scrutiny.