Zum Hauptinhalt springen
Version: Guardian v0.1.0

iOS

Native iOS-Integration für das Surt Guardian SDK, vertrieben über Swift Package Manager. Das SDK erfasst Gerätesignale, führt Geräteintegritätsprüfungen durch und gibt die Risikoentscheidung des Backends zurück.

Das SDK hält niemals einen Surt-API-Schlüssel. Ihr Backend hält den sp_live_*-Schlüssel (nur serverseitig) und tauscht ihn gegen ein kurzlebiges JWT, das die App an verify() übergibt.

Version

Dieser Leitfaden behandelt SDK v0.3.0, das auch die VPN-Erkennung korrigiert.

Voraussetzungen​

  • iOS 14.0+
  • Xcode 14+
  • Swift 5.7+

1. Authentifizierung​

Fügen Sie Ihr Zugriffstoken zu ~/.netrc hinzu, damit Xcode das private Repository klonen kann:

~/.netrc
machine github.com
login surt-customer
password <YOUR_TOKEN>

Ersetzen Sie <YOUR_TOKEN> durch das von Surt bereitgestellte Token.

tipp

Falls ~/.netrc nicht existiert, erstellen Sie es. Stellen Sie sicher, dass es eingeschränkte Berechtigungen hat:

chmod 600 ~/.netrc

2. Paket hinzufügen​

  1. Gehen Sie in Xcode zu File > Add Package Dependencies
  2. Geben Sie die Repository-URL ein: https://github.com/surtTech/surt-guardian-sdk
  3. Setzen Sie die Versionsregel auf "Up to Next Minor" ab 0.3.0
  4. Klicken Sie auf Add Package
  5. Wählen Sie die SurtGuardianSDK-Bibliothek aus und fügen Sie sie Ihrem Target hinzu

3. Info.plist-Berechtigungen konfigurieren​

Wenn Sie die Standorterfassung aktivieren, fügen Sie diesen Schlüssel zu Ihrer Info.plist hinzu:

Info.plist
<key>NSLocationWhenInUseUsageDescription</key>
<string>Your location helps verify your identity and protect your account.</string>

Wenn Sie die Kamerainformationserfassung aktivieren, fügen Sie diesen Schlüssel hinzu:

Info.plist
<key>NSCameraUsageDescription</key>
<string>Camera access helps verify device authenticity.</string>

Das SDK fordert die entsprechende Berechtigung während der Verifizierung automatisch an, wenn die passende Erfassungsoption aktiviert ist. Der Systemdialog erscheint automatisch - es ist kein zusätzlicher Code erforderlich.

4. SDK initialisieren​

Einmal beim App-Start aufrufen, vor jeder anderen SDK-Methode. Im SDK ist kein API-Schlüssel erforderlich - Ihr serverseitiger API-Schlüssel gelangt niemals auf das Gerät.

AppDelegate.swift
import SurtGuardianSDK

// In Ihrem AppDelegate oder App-Init:
GuardianSDK.initialize(
options: GuardianOptions(
environment: .production,
failurePolicy: .fail,
logLevel: .warn,
collectLocation: true // GPS-Erfassung aktivieren (optional)
)
)

Umgebungen​

UmgebungBasis-URL
.productionhttps://api.surt.com
.sandboxhttps://sandbox-api.surt.com

Datenerfassungsoptionen​

OptionStandardBeschreibung
collectLocationfalseGPS-Koordinaten - erfordert NSLocationWhenInUseUsageDescription in der Info.plist
collectWifiInfofalseWiFi-Netzwerkdetails
collectSimCardInfofalseSIM-/Carrier-Informationen
collectCameraInfofalseKameraanzahl/-info - erfordert NSCameraUsageDescription in der Info.plist

Wenn collectLocation aktiviert ist, fordert das SDK den Benutzer beim ersten Aufruf von verify() automatisch zur Standortberechtigung auf. Wenn der Benutzer ablehnt, fährt das SDK ohne GPS-Daten fort - das Backend bewertet die Transaktion mit geringerer Sicherheit.

5. JWT von Ihrem Backend erzeugen​

Vor jedem verify()-Aufruf muss Ihre App ein kurzlebiges GeolocationJwt von Ihrem eigenen Backend holen. Ihr Backend ruft POST /geolocation/preflight mit seinem serverseitigen API-Schlüssel und dem Transaktionskontext auf und gibt dann das JWT an die App zurück.

Beispiel-Backend-Aufruf (Ihr Server, nicht die App):

Backend preflight request
POST /geolocation/preflight
Authorization: Bearer sp_live_xxx
Content-Type: application/json

{
"customer_id": "user_abc123",
"transaction_type": "login",
"transaction_name": "User Login",
"name": "John Doe",
"email": "john@example.com"
}

Die Preflight-Antwort gibt das Token zurück, das Ihre App benötigt:

Preflight response
{
"data": {
"token": "<jwt>"
}
}

Ihre App holt das JWT von Ihrem eigenen Backend-Endpoint:

Fetch JWT from your backend
// In Ihrer App - rufen Sie Ihr EIGENES Backend auf, nicht Surt direkt
func fetchVerifyJwt() async throws -> String {
let response = try await URLSession.shared.data(
for: URLRequest(url: URL(string: "https://your-api.com/geolocation-jwt")!)
)
// JWT-String aus der Antwort Ihres Backends parsen und zurückgeben
let body = try JSONDecoder().decode(YourJwtResponse.self, from: response.0)
return body.jwt
}
Holen Sie immer ein frisches JWT pro Aufruf

Holen Sie immer ein frisches JWT unmittelbar vor dem Aufruf von verify(). Jedes JWT ist einmalig verwendbar; die Wiederverwendung eines JWT wird vom Backend abgelehnt.

6. Eine Transaktion verifizieren​

Bei sicherheitssensiblen Momenten aufrufen (Login, Zahlung usw.). Holen Sie unmittelbar vor jedem Aufruf ein JWT von Ihrem Backend.

async/await (iOS 15+)
let jwt = try await fetchVerifyJwt()

let result = try await GuardianSDK.shared.verify(jwt: jwt)

if result.allowed {
// Mit der Transaktion fortfahren
} else {
// Abgelehnte Transaktion behandeln (result.riskLevel enthält Details)
}

Oder mit einem Completion-Handler (iOS 14+):

Completion handler (iOS 14+)
let jwt = try await fetchVerifyJwt()

GuardianSDK.shared.verify(jwt: jwt) { result in
switch result {
case .success(let verification):
if verification.allowed { /* fortfahren */ }
case .failure(let error):
// SurtError behandeln
}
}

Standortüberschreibung pro Aufruf:

Per-call location override
// GPS für diesen Aufruf erzwingen, unabhängig vom Init-Standard
let result = try await GuardianSDK.shared.verify(
jwt: jwt,
collectLocation: true
)

7. Collect (Server-zu-Server, optional)​

collect() gibt ein verschlüsseltes Payload zurück, das Ihr Backend an Surt weiterleitet. Während collect erfolgen keine direkten SDK-zu-Surt-Aufrufe.

Collect payload
// Ohne JWT - keine Surt-Netzwerkaufrufe, keine IP im Payload
let result = try await GuardianSDK.shared.collect()

// Mit JWT - löst die öffentliche IP des Geräts auf (GET /geolocation/client-ip),
// bettet sie in das Payload ein (best-effort)
let jwtForCollect = try await fetchCollectJwt()
let result = try await GuardianSDK.shared.collect(jwt: jwtForCollect)

// result.payload an Ihr Backend senden
JWT ist für collect optional

Das JWT für collect() ist optional. Übergeben Sie es nur, um die öffentliche IP des Geräts einzubetten. Anders als bei verify() darf ein JWT für collect() wiederverwendet oder weggelassen werden - collect() benötigt kein JWT pro Aufruf und macht keinen Surt-Netzwerkaufruf, wenn kein JWT übergeben wird.

Verifizierungsergebnis​

VerificationResult
struct VerificationResult {
let allowed: Bool // Backend-Entscheidung - true = fortfahren
let riskLevel: RiskLevel // .low / .medium / .high / .blocked / .unknown
let sessionId: String // Transaktions-ID für Support-Referenz
let errors: [String]? // Backend-Fehlermeldungen, falls vorhanden
let timestamp: TimeInterval // Antwortzeitstempel
}

Transaktionstypen​

Diese Werte werden von Ihrem Backend im Preflight-Feld transaction_type gesetzt. Sie werden in der App nicht an verify() übergeben.

TypAnwendungsfall
.loginBenutzeranmeldung
.signUpNeues Konto erstellen
.depositEinzahlung
.withdrawalAuszahlung

Fehlerbehebung​

FehlerUrsacheLösung
"Package resolution failed"Token nicht konfiguriert oder abgelaufenPrüfen Sie, ob ~/.netrc das richtige Token enthält
.notInitializedverify() wurde vor initialize() aufgerufenRufen Sie initialize() beim App-Start auf
.invalidJwtJWT fehlt, ist fehlerhaft oder wurde abgelehntStellen Sie sicher, dass Ihr Backend pro Aufruf ein frisches JWT erzeugt
.attestationFailedGeräteintegritätsprüfung fehlgeschlagen - meist ein wiederverwendetes JWTVerwenden Sie ein JWT niemals über mehrere verify()-Aufrufe hinweg wieder