Zum Hauptinhalt springen
Version: Guardian v0.1.0

Android

Native Android-Integration für das Surt Guardian SDK, vertrieben über Maven (GitHub Packages). 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​

  • Android SDK 24+ (Android 7.0+)
  • Kotlin 1.9+
  • Gradle 8+
  • Java 17

1. Authentifizierung​

Fügen Sie Ihr Zugriffstoken zur gradle.properties Ihres Projekts hinzu (oder zu ~/.gradle/gradle.properties für alle Projekte):

gradle.properties
SURT_GITHUB_TOKEN=<YOUR_TOKEN>

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

warnung

Schreiben Sie gradle.properties mit Token nicht in die Versionsverwaltung. Fügen Sie es zu .gitignore hinzu oder verwenden Sie stattdessen ~/.gradle/gradle.properties.

2. Repository hinzufügen​

Fügen Sie in der settings.gradle (oder settings.gradle.kts) Ihres Projekts das Surt-Maven-Repository hinzu:

settings.gradle
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven {
url = uri("https://maven.pkg.github.com/surtTech/surt-guardian-sdk")
credentials {
username = "surt-customer"
password = settings.ext.find("SURT_GITHUB_TOKEN")
?: System.getenv("SURT_GITHUB_TOKEN") ?: ""
}
}
}
}
settings.gradle.kts
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven {
url = uri("https://maven.pkg.github.com/surtTech/surt-guardian-sdk")
credentials {
username = "surt-customer"
password = providers.gradleProperty("SURT_GITHUB_TOKEN").orNull
?: System.getenv("SURT_GITHUB_TOKEN")
}
}
}
}

3. Abhängigkeit hinzufügen​

In der build.gradle (oder build.gradle.kts) Ihrer App:

build.gradle
dependencies {
implementation 'com.surt.guardian:securitysdk:0.3.0'
}
build.gradle.kts
dependencies {
implementation("com.surt.guardian:securitysdk:0.3.0")
}

Core Library Desugaring​

Wenn Ihre App minSdk < 26 als Ziel hat, stellen Sie sicher, dass Core Library Desugaring in der build.gradle Ihrer App aktiviert ist:

build.gradle
android {
compileOptions {
coreLibraryDesugaringEnabled true
}
}

dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
}

4. AndroidManifest-Berechtigungen​

Wenn Sie die Standorterfassung aktivieren, fügen Sie diese Berechtigungen zu Ihrer AndroidManifest.xml hinzu:

AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

Wenn Sie die SIM-Karten-Informationserfassung aktivieren, fügen Sie diese Berechtigung hinzu:

AndroidManifest.xml
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

Das SDK fordert die Standortberechtigung während der Verifizierung automatisch an, wenn collectLocation aktiviert ist. Der standardmäßige Android-Berechtigungsdialog erscheint automatisch - es ist kein zusätzlicher Code erforderlich.

5. SDK initialisieren​

Einmal beim App-Start aufrufen (typischerweise in Ihrer Application-Klasse). Im SDK ist kein API-Schlüssel erforderlich - Ihr serverseitiger API-Schlüssel gelangt niemals auf das Gerät.

MyApplication.kt
import android.app.Application
import com.surt.guardian.GuardianSDK
import com.surt.guardian.core.Environment
import com.surt.guardian.core.FailurePolicy
import com.surt.guardian.core.GuardianOptions
import com.surt.guardian.utils.Logger

class MyApplication : Application() {
override fun onCreate() {
super.onCreate()

GuardianSDK.initialize(
context = this,
options = GuardianOptions(
environment = Environment.Production,
failurePolicy = FailurePolicy.Fail,
logLevel = Logger.Level.WARN,
collectLocation = true // GPS-Erfassung aktivieren (optional)
)
)
}
}

Umgebungen​

UmgebungBasis-URL
Environment.Productionhttps://api.surt.com
Environment.Sandboxhttps://sandbox-api.surt.com

Datenerfassungsoptionen​

OptionStandardBeschreibung
collectLocationfalseGPS-Koordinaten - erfordert Standortberechtigungen im Manifest
collectWifiInfofalseWiFi-Netzwerkdetails
collectSimCardInfofalseSIM-/Carrier-Informationen - erfordert READ_PHONE_STATE-Berechtigung
collectCameraInfofalseKameraanzahl/-info

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.

6. Activity-Referenz (für automatische Berechtigungsanfragen)​

Damit das SDK den Berechtigungsdialog anzeigen kann, benötigt es eine Referenz auf die aktuelle Activity. Rufen Sie setActivity() im Lebenszyklus Ihrer Activity auf:

MainActivity.kt
override fun onResume() {
super.onResume()
GuardianSDK.getInstance().setActivity(this)
}

override fun onPause() {
super.onPause()
GuardianSDK.getInstance().setActivity(null)
}
hinweis

Wenn Sie setActivity() nicht aufrufen, funktioniert das SDK weiterhin, kann jedoch keine Berechtigungen automatisch anfordern. Sie müssten die Berechtigungen dann selbst anfordern, bevor Sie verify() aufrufen.

7. 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
suspend fun fetchVerifyJwt(): String {
// Rufen Sie Ihren EIGENEN Backend-Endpoint auf, nicht Surt direkt
val response = httpClient.post("https://your-api.com/geolocation-jwt")
return response.body<YourJwtResponse>().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.

8. Eine Transaktion verifizieren​

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

Coroutines (recommended)
val jwt = fetchVerifyJwt()

val result = GuardianSDK.getInstance().verifySuspend(jwt = jwt)

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

Oder mit einem Callback:

Callback
val jwt = fetchVerifyJwt()

GuardianSDK.getInstance().verify(jwt = jwt) { result ->
result.onSuccess { verification ->
if (verification.allowed) { /* fortfahren */ }
}
result.onFailure { error ->
// SurtError behandeln
}
}

Standortüberschreibung pro Aufruf:

Per-call location override
// GPS für diesen Aufruf erzwingen, unabhängig vom Init-Standard
val result = GuardianSDK.getInstance().verifySuspend(
jwt = jwt,
collectLocation = true
)

9. 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
val result = GuardianSDK.getInstance().collectSuspend()

// Mit JWT - löst die öffentliche IP des Geräts auf (GET /geolocation/client-ip),
// bettet sie in das Payload ein (best-effort)
val jwtForCollect = fetchCollectJwt()
val result = GuardianSDK.getInstance().collectSuspend(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
data class VerificationResult(
val allowed: Boolean, // Backend-Entscheidung - true = fortfahren
val riskLevel: RiskLevel, // LOW / MEDIUM / HIGH / BLOCKED / UNKNOWN
val sessionId: String, // Transaktions-ID für Support-Referenz
val errors: List<String>?, // Backend-Fehlermeldungen, falls vorhanden
val timestamp: Long // Antwortzeitstempel (ms)
)

Transaktionstypen​

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

TypAnwendungsfall
TransactionType.LOGINBenutzeranmeldung
TransactionType.SIGN_UPNeues Konto erstellen
TransactionType.DEPOSITEinzahlung
TransactionType.WITHDRAWALAuszahlung

Fehlerbehebung​

FehlerUrsacheLösung
"Could not resolve com.surt.guardian:securitysdk"Token nicht konfiguriert oder Repo nicht hinzugefügtPrüfen Sie gradle.properties und settings.gradle
"401 Unauthorized" von maven.pkg.github.comToken abgelaufen oder ungültigHolen Sie ein neues Token von Surt
.notInitializedverify() wurde vor initialize() aufgerufenRufen Sie initialize() in Application.onCreate() 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