Zum Inhalt springen
flutter 2026-07-08

Akamai Bot Protection in Flutter: BMP-SDK-Integration

Wie ich Akamai Bot Manager Premier in eine Flutter-E-Commerce-App integriert habe - SDK-Sensor-Daten, Challenge-Handling und die Dio-Interceptor-Kette.


Akamai Bot Protection in Flutter: BMP-SDK-Integration

Für CTOs, Tech Leads und Senior-Entwickler, die Enterprise-Mobile-Apps mit CDN-Infrastruktur bauen - oder es planen.

TL;DR: Akamai als CDN und Bot-Protection-Layer vor deinem Backend klingt nach reinem Infrastruktur-Thema. Bis deine Flutter-App plötzlich 403-Fehler bekommt, weil Akamai sie für einen Bot hält. Akamai bietet ein BMP-SDK (Bot Manager Premier) für Flutter an, das auf dem Gerät Verhaltens-Sensordaten sammelt und per HTTP-Header mitschickt. Aber das SDK liefert nur die Bausteine - die Orchestrierung musst du selbst bauen. Dieser Artikel beschreibt, wie ich die Dio-Interceptor-Kette aufgebaut habe: Sensordaten-Injektion, Zwei-Stufen-Antwortbehandlung (428 Challenges und 403 Blocks) und pfadbasierte URL-Filterung mit Remote Config.


Was Akamai mit deinem App-Traffic macht

Ich habe rund zehn Monate an diesem Projekt gearbeitet und die App von Grund auf mit aufgebaut. Die Akamai-Integration hat das Networking, das Bild-Loading, den Auth-Flow und den Checkout berührt.

Akamai sitzt als Reverse Proxy zwischen deiner App und dem Backend. Jeder API-Call, jede Bild-Anfrage, jeder Request geht durch Akamais Edge-Netzwerk. Das bringt drei Dinge mit:

CDN-Caching beschleunigt statische Assets und API-Responses. Image Manager optimiert Bilder automatisch nach Device und Viewport. Und der Bot Manager analysiert jeden Request auf verdächtiges Verhalten.

Request-Flow: Flutter App → Akamai Edge-Netzwerk → Backend

Für Browser ist das unsichtbar. Der Browser hat Cookies, führt JavaScript aus, verhält sich “menschlich”. Eine Flutter-App? Macht HTTP-Requests über Dio. Kein Cookie-Jar beim ersten Start. Kein JavaScript-Kontext. Ein User-Agent, der nach Library aussieht statt nach Chrome.

Aus Akamais Perspektive sieht das verdächtig aus. Und genau da fangen die Probleme an.

Der einfache Teil: Image Manager

Bevor es kompliziert wird, erstmal der angenehme Teil. Akamai Image Manager kann Bilder on-the-fly transformieren - Größe anpassen, Format konvertieren, Qualität optimieren. Für eine E-Commerce-App mit hunderten Produktbildern ist das ein massiver Performance-Gewinn.

Für CMS-Content-Bilder, die über einen dedizierten Asset-Host ausgeliefert werden, ist die Integration eine String-Extension, die die optimierte URL zusammenbaut:

extension on String {
  String? get toOptimizedContentUrl {
    return Uri.https('assets.example.ch', this, {
      'imdensity': '2',
      'impolicy': 'contentstack',
      'imwidth': '480',
    }).toString();
  }
}

Der impolicy-Parameter verweist auf eine serverseitig konfigurierte Transformations-Policy. imwidth bestimmt die Zielbreite, imdensity berücksichtigt hochauflösende Displays. Akamai cached jede Variante am Edge, sodass der zweite Aufruf mit denselben Parametern sofort beantwortet wird.

Diese Extension wird überall angewendet, wo die App CMS-verwalteten Content rendert - Home-Feed-Items, Banner, Produkt-Badges, Such-Vorschläge. Eine zentrale Transformation, an über einem Dutzend Stellen im Code verwendet.

Das war der Teil, der funktioniert hat, ohne Überraschungen. Dokumentation gelesen, Parameter gesetzt, fertig. Wenn nur alles so wäre.

Warum die App plötzlich geblockt wurde

Der Launch rückte näher, und mit ihm eine bewusste Entscheidung: Die Akamai-Regeln wurden verschärft. Die App sollte vor DDoS-Attacken und automatisiertem Missbrauch geschützt werden. Clients mussten nun aktiv beweisen, dass sie keine Bots sind.

Für den Web-Shop war das kein Problem. Browser-Traffic bringt alles mit, was Akamais Bot Manager braucht: das _abck-Session-Cookie aus vorherigen Interaktionen, einen erkennbaren User-Agent wie Mozilla/5.0, und die Fähigkeit, Akamais Sensor-Script auszuführen — ein JavaScript, das Canvas-Rendering, WebGL-Hashes, installierte Fonts und dutzende weitere Signale inventarisiert, um echte Browser von Automatisierung zu unterscheiden.

Eine native App beim ersten API-Request hat keines dieser Signale. Kein _abck-Cookie. Kein Verhaltens-Fingerprint. Kein JavaScript-Context. Und ein User-Agent, der sowas wie Dio/5.0 sagt — Darts HTTP-Client — statt Mozilla/5.0. Akamai bewertet jeden Request mit einem Bot Score von 0 (Mensch) bis 100 (Bot). Ein Standard-HTTP-Client ohne Sensor-Daten landet nahe 100 — maximale Bot-Konfidenz.

Das Ergebnis: 403 Forbidden. Aber nicht überall gleichzeitig. Bot Manager erlaubt es, Transactional Endpoints einzeln zu konfigurieren — Login, Checkout und Account-Seiten können mit strengeren Schwellenwerten geschützt werden als Produktlisten oder Suchendpunkte. In der Praxis: Produktbilder laden, aber der Login schlägt fehl. Oder der Warenkorb funktioniert, aber der Checkout nicht. Nicht konsistent reproduzierbar, weil der Bot Score dynamisch ist — derselbe Request kann je nach IP-Reputation, TLS-Fingerprint und Tageszeit unterschiedlich bewertet werden.

Das BMP-SDK: Beweisen, dass du kein Bot bist

Akamai bietet ein Bot Manager Premier (BMP) SDK für Flutter an - ein natives Plugin, das auf dem Gerät Verhaltens-Sensordaten sammelt. Touch-Events, Gerätebewegung, Bildschirm-Interaktionen - das SDK baut einen Fingerprint auf, den Akamais Edge-Server auswerten können, um menschliche User von Bots zu unterscheiden.

Das SDK wird als Platform-Plugin eingebunden, das native Libraries kapselt (ein AAR für Android, ein xcframework für iOS). Die Integration beginnt in der pubspec.yaml:

dependencies:
  bmp_flutter_sdk:
    path: packages/bmp_flutter_sdk

Initialisierung beim App-Start. Du übergibst die Base-URL der geschützten Ressource und aktivierst optional die Challenge-Action-Funktion:

void _initializeAkamaiSdk(ShopConfig config) {
  AkamaiBMP.configureSDK(baseUrl: config.baseUrl);
  AkamaiBMP.configureChallengeAction(baseUrl: config.baseUrl);
}

Nach der Initialisierung sammelt das SDK im Hintergrund Verhaltensdaten. Wenn du einen geschützten API-Call machen willst, rufst du die Sensordaten ab und schickst sie als HTTP-Header mit:

final sensorData = await AkamaiBMP.getSensorData();
headers['X-acf-sensor-data'] = sensorData;

Akamais Edge-Server prüft diesen Header, wertet die Sensordaten aus und entscheidet, ob der Request menschlich aussieht. Wenn ja, wird er an den Origin weitergeleitet. Wenn nein, antwortet der Server mit 428 (Challenge) oder 403 (Block).

Das SDK erledigt den schweren Teil - native Sensordaten-Erfassung über beide Plattformen. Aber die Orchestrierung - welche Requests Sensordaten brauchen, wie Challenge-Responses behandelt werden, wie fehlgeschlagene Requests wiederholt werden - das ist dein Job.

Die Interceptor-Kette

Die eigentliche Architekturarbeit ist die Dio-Interceptor-Kette - dasselbe Muster, das ich auch für Token-Refresh und Silent Logout verwende. Vier Interceptoren, jeder mit einer einzigen Verantwortung, in Reihenfolge auf jedem Request ausgeführt:

1. Sensordaten-Anreicherung

Der erste Interceptor prüft, ob der ausgehende Request eine Akamai-geschützte URL ansteuert. Wenn ja, holt er Sensordaten vom BMP-SDK und injiziert sie als X-acf-sensor-data-Header:

class AkamaiSensorDataEnrichmentInterceptor extends Interceptor {
  final List<AkamaiProtectedUrlRule> akamaiProtectedUrlRules;

  
  Future<void> onRequest(
    RequestOptions options,
    RequestInterceptorHandler handler,
  ) async {
    if (!akamaiProtectedUrlRules.matchUri(options.uri)) {
      handler.next(options);
      return;
    }

    final sensorData = await AkamaiBMP.getSensorData() ?? '';
    if (sensorData.isNotEmpty) {
      options.headers['X-acf-sensor-data'] = sensorData;
    }

    handler.next(options);
  }
}

2. Challenge Action (HTTP 428)

Wenn Akamai unsicher ist, ob der Request von einem Menschen kommt, antwortet es mit HTTP 428 (Precondition Required) und einem Akamai-BM-Challenge-Context-Header. Der Interceptor fängt das ab, zeigt dem User über das SDK einen nativen Challenge-Dialog und wiederholt bei Erfolg den Request:

class AkamaiChallengeActionInterceptor extends Interceptor {
  final Dio _dio;
  final List<AkamaiProtectedUrlRule> _akamaiProtectedUrlRules;

  
  Future<void> onError(
    DioException err,
    ErrorInterceptorHandler handler,
  ) async {
    final response = err.response;
    if (response == null ||
        response.statusCode != 428 ||
        !_akamaiProtectedUrlRules.matchUri(response.requestOptions.uri)) {
      handler.next(err);
      return;
    }

    final challengeContext =
        response.headers.value('Akamai-BM-Challenge-Context');

    if (challengeContext != null) {
      final ccaResponse = await AkamaiBMP.showChallengeAction(
        context: challengeContext,
        title: 'Verifizierung erforderlich',
        message: 'Bitte warten Sie, während wir Ihre Anfrage prüfen.',
        cancelButtonTitle: 'Abbrechen',
      );

      final status = ccaResponse?['status']?.toString();
      if (status == '1') {
        // Challenge bestanden - mit frischen Sensordaten wiederholen
        final sensorData = await AkamaiBMP.getSensorData() ?? '';
        final retryOptions = err.requestOptions.copyWith(
          headers: {
            ...err.requestOptions.headers,
            'X-acf-sensor-data': sensorData,
          },
        );
        final retryResponse = await _dio.fetch<dynamic>(retryOptions);
        return handler.resolve(retryResponse);
      }
    }

    handler.next(err);
  }
}

Der Challenge-Dialog ist nativ - das SDK rendert ihn. Der User sieht einen kurzen Verifizierungsbildschirm, und bei Erfolg wird der Request transparent wiederholt.

3. Bot Protection (HTTP 403)

Wenn Akamai überzeugt ist, dass der Request von einem Bot kommt, antwortet es mit HTTP 403 und einer reference_id im Response-Body. Anders als bei der 428-Challenge gibt es hier keine programmatische Lösung. Der Interceptor zeigt einen Support-Dialog mit der Referenz-ID:

class BotProtectionInterceptor extends Interceptor {
  final List<AkamaiProtectedUrlRule> akamaiProtectedUrlRules;

  
  void onError(DioException error, ErrorInterceptorHandler handler) {
    final referenceId = switch (error.response?.data) {
      final Map<String, dynamic> data
          when data.containsKey('reference_id') =>
        data['reference_id'] as String?,
      _ => null,
    };

    if (error.response?.statusCode == 403 &&
        referenceId != null &&
        akamaiProtectedUrlRules.matchUri(error.requestOptions.uri)) {
      // Bot-Erkennungs-Dialog mit Referenz-ID und Support-Kontakt anzeigen
      _showBotDetectionDialog(referenceId);
    }

    handler.next(error);
  }
}

Die Unterscheidung zwischen 428 und 403 ist entscheidend. Eine 428 ist eine Frage: “Bist du ein Mensch? Beweis es.” Eine 403 mit Referenz-ID ist ein Urteil: “Wir blockieren dich.” Verschiedene Antworten, verschiedene UX-Flows.

4. Session-Cookie-Monitoring

Ein vierter Interceptor überwacht das Session-Cookie der Anwendung bei authentifizierten Requests und loggt ins Crash-Reporting, wenn es fehlt. Das ist nicht Akamai-spezifisch - es fängt Fälle ab, in denen der Session-Zustand korrupt wurde, unabhängig von der Ursache.

URL-basierte Filterung

Nicht jeder Request braucht Akamai-Schutz. Produktlisten, Bild-URLs, statischer Content - die brauchen keine Sensordaten. Nur High-Value-Endpoints wie Authentifizierung und Checkout rechtfertigen den Overhead.

Die Filterung nutzt pfadbasierte Regeln mit drei Match-Typen:

class AkamaiProtectedUrlRule {
  final RuleType type; // pathEquals, pathContains, pathRegex
  final String rule;

  bool matches(Uri uri) {
    switch (type) {
      case RuleType.pathEquals:
        return uri.path == rule;
      case RuleType.pathContains:
        return uri.path.contains(rule);
      case RuleType.pathRegex:
        return RegExp(rule).hasMatch(uri.path);
    }
  }
}

Die geschützten Endpoints in diesem Projekt:

  • /api/accounts/authenticate
  • /api/accounts/registration
  • /api/accounts/changeemail
  • /api/accounts/forgotpassword
  • /api/accounts/resetpassword
  • /api/checkout/init
  • /api/checkout/validate
  • /api/checkout/order

Diese Regeln sind als Fallback-Defaults definiert, können aber über Firebase Remote Config überschrieben werden. Wenn das Sicherheitsteam anpasst, welche Endpoints geschützt sind, greift die Änderung ohne App-Release.

Warum ist das wichtig? Zwei Gründe. Erstens hat getSensorData() Kosten - es ist ein asynchroner Aufruf, der Latenz hinzufügt. Ihn bei jedem Request auf jeden Endpoint aufzurufen ist Verschwendung. Zweitens sagt die SDK-Dokumentation explizit: “Don’t call the getSensorData method for non-protected URLs.” Du sammelst Verhaltensdaten, und sie unnötig zu versenden ist sowohl ein Performance- als auch ein Datenschutzproblem.

Testen und Debug-Tooling

Akamais Bot-Erkennung kann man nicht lokal testen. Die Auswertung passiert auf Akamais Edge-Servern, nicht auf deinem Rechner. Aber du kannst die Interceptor-Logik testen und die SDK-Integration verifizieren.

Das BMP-SDK enthält eingebaute Integrations-Checks. Die App macht diese auf einer Debug-Seite zugänglich:

// Integrations-Diagnose ausführen
AkamaiBMP.runIntegrationChecks();
AkamaiBMP.runIntegrationChecksWithCCAEnabled();

Diese verifizieren, dass das SDK korrekt initialisiert wurde, die Sensordaten-Erfassung funktioniert, Gerätebewegungssensoren erreichbar sind und die Challenge-Action-Funktion konfiguriert ist. Das SDK loggt Ergebnisse in die Konsole mit einem klaren Pass/Fail für jeden Check.

Für die Interceptor-Kette testen Mock-Interceptoren in CI die Retry-Logik und URL-Filterung unabhängig von Akamais Edge-Servern:

test('reichert geschützte URL mit Sensordaten-Header an', () async {
  final interceptor = AkamaiSensorDataEnrichmentInterceptor(
    akamaiProtectedUrlRules: [
      AkamaiProtectedUrlRule(
        type: RuleType.pathContains,
        rule: '/api/checkout/order',
      ),
    ],
  );

  final options = RequestOptions(path: '/api/checkout/order');
  final handler = MockRequestInterceptorHandler();
  await interceptor.onRequest(options, handler);

  expect(options.headers['X-acf-sensor-data'], isNotNull);
});

Eine Staging-Umgebung mit aktiviertem Akamai bleibt der einzige Weg, den vollständigen Flow end-to-end zu verifizieren. Lokale Entwicklung nutzt Mock-Interceptoren, aber jede Änderung am Networking-Layer wird vor dem Merge gegen Staging getestet.

Was ich gelernt habe

Ein paar Dinge, die aus der SDK-Dokumentation nicht offensichtlich sind:

Die Challenge-Action-Response hat drei Zustände, nicht zwei. Status 1 bedeutet Erfolg, 0 bedeutet der User hat abgebrochen, und -1 bedeutet die Challenge ist fehlgeschlagen. Handle alle drei explizit - Abbruch und Fehler brauchen unterschiedliche Fehlermeldungen.

Sensordaten sollten für Retries frisch sein. Nach einer erfolgreichen Challenge-Action nicht die Sensordaten vom fehlgeschlagenen Request wiederverwenden. Ruf getSensorData() erneut auf für frische Verhaltensdaten. Der Edge-Server erwartet Sensordaten, die den aktuellen Session-Zustand widerspiegeln.

Das SDK braucht Initialisierung vor dem ersten API-Call. Ruf configureSDK() früh im App-Lifecycle auf - vor dem ersten geschützten API-Request. Wenn das SDK beim ersten Request noch nicht genug Verhaltensdaten gesammelt hat, ist die Sensor-Payload dünn, und Akamai wird eher challengen.

URL-Regel-Änderungen brauchen keinen App-Release. Die geschützten URL-Regeln über Remote Config konfigurierbar zu machen war eine der besseren Architekturentscheidungen. Als das Sicherheitsteam mitten im Sprint neue geschützte Endpoints hinzufügte, haben wir die Regeln ohne Release-Zyklus aktualisiert.

Fazit

Akamais BMP-SDK erledigt den schwierigen Teil - native Verhaltens-Sensordaten-Erfassung über iOS und Android. Die Herausforderung liegt in allem drumherum: die Interceptor-Kette bauen, das Zwei-Stufen-Antwortsystem handhaben, URL-basierte Filterung konfigurieren und das Debug-Tooling aufbauen, um zu verifizieren, dass alles funktioniert.

Die Interceptor-Kette - Sensordaten-Anreicherung, Challenge-Action-Behandlung, Bot-Protection, Session-Monitoring - ist kompakt. Jeder Interceptor hat eine einzige Verantwortung, und das URL-Regelsystem stellt sicher, dass sie nur bei Endpoints feuern, die Schutz brauchen.

Drei Erkenntnisse aus dem Projekt:

Plane die Akamai-Integration von Anfang an ein. Wenn du weißt, dass dein Backend hinter Akamai sitzt, starte mit der SDK-Integration und der Interceptor-Kette, nicht erst wenn die 403-Fehler kommen.

Halte die URL-Regeln aktualisierbar. Remote Config für die geschützten Endpoints ist keine Optimierung - es ist eine operative Notwendigkeit, wenn das Sicherheitsteam Regeln unabhängig vom App-Release-Zyklus anpassen muss.

Die SDK-Integration selbst dauert Tage. Die Interceptor-Architektur, URL-Filterung, Remote Config, Debug-Tooling und das Testen gegen Staging - da geht die Zeit hin.

Ich habe diese Integration end-to-end in einer produktiven E-Commerce-App gebaut. Wenn dein Team vor einer ähnlichen Akamai-Integration steht, lass uns sprechen.

Häufige Fragen

Was ist Akamai Bot Manager und warum betrifft er mobile Apps?

Akamai Bot Manager ist ein Bot-Erkennungs- und Mitigations-Service, der zwischen Clients und Origin-Servern sitzt. Er wertet eingehende Requests anhand von Verhaltensanalyse und Device-Fingerprinting aus. Mobile Apps benötigen das BMP-SDK, um Sensordaten über den X-acf-sensor-data-HTTP-Header bereitzustellen, die Akamais Edge-Server auswerten, um legitimen App-Traffic von Bots zu unterscheiden.

Gibt es ein offizielles Akamai SDK für Flutter?

Ja. Akamai bietet ein Bot Manager Premier (BMP) SDK für Flutter, iOS und Android an. Das Flutter-SDK (bmp_flutter_sdk) kapselt native Platform-Libraries und bietet Methoden für Initialisierung (configureSDK), Sensordaten-Erfassung (getSensorData) und Challenge-Behandlung (showChallengeAction). Es wird als lokales Flutter-Plugin-Paket integriert.

Was ist der Unterschied zwischen einer 428- und einer 403-Antwort von Akamai?

Eine 428 (Precondition Required) bedeutet, dass Akamai zusätzliche Verifizierung will. Die Response enthält einen Akamai-BM-Challenge-Context-Header, und die App kann über das SDK einen Challenge-Dialog zeigen. Bei Bestehen kann der Request mit frischen Sensordaten wiederholt werden. Eine 403 (Forbidden) mit einer reference_id bedeutet, dass Akamai den Request als Bot eingestuft hat - das ist terminal und kann nicht programmatisch gelöst werden.

Funktioniert Akamai Image Manager mit Flutters Bild-Caching?

Ja. Image-Manager-URLs sind deterministisch - dieselben Parameter erzeugen dasselbe optimierte Bild. Flutters Image-Cache (über cached_network_image oder ähnliche Pakete) funktioniert normal. Das CDN cached zusätzlich jede Bild-Variante am Edge, sodass die Kombination aus Client-seitigem und Edge-Caching gute Performance liefert.

Kann ich Akamai Bot Protection lokal testen?

Nicht direkt. Die Bot-Erkennung läuft auf Akamais Edge-Netzwerk. Das BMP-SDK enthält Integrations-Checks (runIntegrationChecks()), die die SDK-Initialisierung und Sensordaten-Erfassung auf dem Gerät verifizieren. Für CI mocke die Interceptor-Kette, um URL-Filterung und Retry-Logik ohne Akamais Edge-Server zu testen. Eine Staging-Umgebung mit aktiviertem Akamai ist nötig für die End-to-End-Verifizierung.

KH
Khalit Hartmann Freelance Mobile & Full-Stack Developer