Zum Inhalt springen

Datenschutz-Folgenabschätzung – QR Viewer

Die jeweils aktuelle Fassung liegt im Repository: github.com/thorsten-l/qr_viewer/blob/main/DPIA_de.md

App QR Viewer 2.2.0 (Build 14), iOS/iPadOS und Android
Codestand main, Audit auf Commit b25767c („release 2.1.2“); Maßnahmen zu F2 und F6 in 2.2.0
Verantwortlicher / Verfasser Thorsten Ludewig, t.ludewig@gmail.com
Datum 14. Oktober 2026
Grundlage Art. 35 DSGVO, § 25 TDDDG
Status Bewertung abgeschlossen; F2 und F6 in 2.2.0 umgesetzt, übrige Maßnahmen offen (Abschnitt 8)

Dieses Dokument verbindet ein technisches Sicherheitsaudit der App mit einer Datenschutz-Folgenabschätzung (DSFA). Es ist keine Rechtsberatung.


1. Zusammenfassung

QR Viewer ist ein Scanner für QR-Codes und Barcodes. Er zeigt den Inhalt zuerst an und öffnet Links oder andere Aktionen erst nach Bestätigung. Die App hat kein Benutzerkonto, keine eigenen Server, keine Werbung und keine Analyse. Der App-Code selbst baut keine Netzwerkverbindungen auf. Alle Erkennung und Auswertung läuft auf dem Gerät.

Ist eine DSFA Pflicht? Eher nicht. Der Entwickler erhält keine personenbezogenen Daten. Es gibt keine umfangreiche Verarbeitung und kein Profiling. Keiner der Fälle aus Art. 35 Abs. 3 DSGVO oder der DSK-Liste trifft zu. Diese Abschätzung ist freiwillig und dokumentiert, warum das Risiko gering ist.

Ergebnis: Das Risiko für die Betroffenen ist gering. Zwei Punkte brauchen Aufmerksamkeit:

  1. Unter Android sendet Google ML Kit technische Nutzungsdaten an Google (Befund F1). Das steht in der Datenschutzerklärung, nach § 25 TDDDG ist aber fraglich, ob das ohne Einwilligung reicht.
  2. Bis 2.1.2 lag der Scan-Verlauf unverschlüsselt vor und war Teil der Betriebssystem-Sicherungen (Befund F2). Gescannte Codes können WLAN-Passwörter, Matter-Einrichtungscodes oder Ticketdaten mit Name und Geburtsdatum enthalten. In 2.2.0 umgesetzt: Der Verlauf ist mit AES-256-CBC + HMAC-SHA256 verschlüsselt, der Schlüssel bleibt auf dem Gerät, die Android-Sicherung ist aus.

Ein hohes Restrisiko bleibt nicht. Eine vorherige Konsultation der Aufsichtsbehörde nach Art. 36 DSGVO ist nicht nötig.


2. Umfang und Vorgehen

Geprüft:

Nicht geprüft:

Risikoskala: Eintrittswahrscheinlichkeit × Schwere, jeweils gering / mittel / hoch, angelehnt an das Standard-Datenschutzmodell (SDM).


3. Beschreibung der Verarbeitung

3.1 Zweck

Die App liest den Inhalt optischer Codes und zeigt ihn verständlich an. Beispiele sind Links, Kontakte, WLAN-Zugänge, GiroCode-Überweisungen, 2FA-Schlüssel, VDV-Tickets, Codes der Deutschen Post und Matter-Einrichtungscodes. Weil nichts automatisch geöffnet wird, schützt sie vor schädlichen Codes („Quishing“).

3.2 Betroffene und Datenkategorien

Betroffene Daten Quelle
Nutzer:in Kamerabild (nur live, nicht gespeichert) Kamera
Nutzer:in Scan-Verlauf (letzte 25 Inhalte mit Zeit, Format, Typ) Scans
Nutzer:in Einstellungen: Scan-Art, Zoomstufe App
Dritte in Codes Namen, Telefonnummern, E-Mail- und Postadressen (vCard/MECARD), Termine Code-Inhalt
Ticketinhaber:in Name (Klartext oder maskiert), Geburtsdatum, Ticketnummer, Gültigkeit VDV-Ticket (Deutschlandticket)
Nutzer:in / Dritte WLAN-Passwörter, 2FA-Geheimnisse, Matter-Einrichtungs-PIN, IBAN/Name (GiroCode) Code-Inhalt
Nutzer:in (Android) Gerätemodell, OS-Version, Paketname und -version, ML-Kit-Leistungsdaten ML-Kit-SDK

Besondere Kategorien nach Art. 9 DSGVO werden nicht gezielt verarbeitet. Ein Code kann solche Daten zufällig enthalten, etwa einen Text über die Gesundheit. Die App zeigt ihn dann wie jeden anderen Text an.

3.3 Speicherorte

Daten Ort Schutz Löschung
Verlauf (scan_history_v2) SharedPreferences (Android-XML in der App-Sandbox) / NSUserDefaults (iOS) Sandbox des Betriebssystems, Geräteverschlüsselung; AES-256-CBC + HMAC-SHA256 seit 2.2.0 Einzeln, „Verlauf löschen“, Deinstallation; max. 25 Einträge
Verlaufsschlüssel (32 Byte, zufällig) iOS-Schlüsselbund (AfterFirstUnlockThisDeviceOnly, nicht synchronisiert) / Android Keystore Wo vorhanden hardwaregestützt; nie in Sicherungen Deinstallation
2FA-Schlüssel werden nicht gespeichert – –
Scan-Art, Zoom SharedPreferences / NSUserDefaults Sandbox Deinstallation
Kamerabild Nur im Arbeitsspeicher – Sofort
Exportdateien (CSV/JSON), vCard/iCalendar Temporäre Datei von share_plus im App-Cache, danach die Ziel-App Sandbox; in der Ziel-App gelten deren Regeln Das Betriebssystem leert den Cache

3.4 Datenflüsse und Empfänger

# Fluss Auslöser Empfänger
D1 Kamerabild → Codeerkennung Scannen Auf dem Gerät: Apple Vision (iOS) bzw. ML Kit (Android)
D2 ML-Kit-Telemetrie Automatisch, nur Android Google (Firelog/CCT über com.google.android.datatransport)
D3 Link öffnen Nutzer:in bestätigt den Dialog Browser bzw. die App für das Schema, danach die Website
D4 E-Mail, Anruf, SMS, Karte, Authenticator Nutzer:in bestätigt Die passende System-App
D5 „Online nachschlagen“ Nutzer:in bestätigt DuckDuckGo (GTIN) / Open Library (ISBN)
D6 „Sendung verfolgen“ Nutzer:in bestätigt Deutsche Post (deutschepost.de, Sendungsnummer in der URL)
D7 Kopieren, Teilen, Kontakt, Termin, Verlaufsexport Nutzer:in tippt Zwischenablage / im Teilen-Menü gewählte App
D8 Support, Anleitungen Nutzer:in tippt GitHub
D9 Sicherung Betriebssystem iOS: iCloud-/Gerätesicherung, Verlauf nur als Geheimtext. Android: keine seit 2.2.0 (allowBackup="false")

3.5 Berechtigungen

Plattform Berechtigung Herkunft Zweck
iOS Kamera (NSCameraUsageDescription) App Scannen
Android CAMERA mobile_scanner Scannen
Android INTERNET, ACCESS_NETWORK_STATE ML Kit / datatransport (nicht vom App-Code genutzt) Telemetrie D2
Android DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION AndroidX Intern

Die App fragt nicht nach Standort, Kontakten, Kalender, Speicher, Mikrofon oder Bluetooth. Kontakte und Termine gehen als .vcf bzw. .ics über das Teilen-Menü weiter. Dafür braucht es keine Kontakt- oder Kalenderberechtigung.


4. Rechtliche Einordnung


5. Notwendigkeit und Verhältnismäßigkeit

Grundsatz Bewertung
Zweckbindung Daten dienen nur der Anzeige und Aktionen, die du selbst auslöst.
Datenminimierung Das Kamerabild wird nicht gespeichert. Der Verlauf ist auf 25 Einträge begrenzt. 2FA-Schlüssel werden nicht gespeichert. Tracking-Parameter werden aus Links entfernt. Es gibt keine unnötigen Berechtigungen. Aber: WLAN-Passwörter und Matter-PINs landen im Verlauf.
Speicherbegrenzung Höchstens 25 Einträge; einzeln oder alle löschbar.
Transparenz Datenschutzerklärung auf Deutsch/Englisch; Info-Knopf in jeder Datenkarte; der Bestätigungsdialog zeigt das vollständige Ziel.
Integrität / Vertraulichkeit Sandbox des Betriebssystems; kein Netzwerkcode in der App; kein WebView; die Parser prüfen Längen. Siehe F2–F5.
Betroffenenrechte Beim Entwickler liegen keine Daten. Du verwaltest alles lokal selbst.

6. Sicherheitsaudit – Befunde

Schweregrad: Hoch / Mittel / Gering / Info.

ID Schwere Befund Empfehlung
F1 Mittel ML-Kit-Telemetrie unter Android. mobile_scanner bindet com.google.mlkit:barcode-scanning ein. Das Release-Manifest enthält deshalb INTERNET sowie TransportBackendDiscovery mit CctBackendFactory. Google erhält Geräte- und Nutzungsdaten, ohne dass du etwas tust. Das steht in PRIVACY.md, es gibt aber keine Einwilligung (§ 25 TDDDG). (a) Rechtlich prüfen lassen. (b) Eine Erkennungsbibliothek ohne Telemetrie suchen (z. B. ZXing-basiert) für einen Android-Build „ohne Netzwerk“. (c) Mindestens: Prüfen, dass die Angaben in „Datensicherheit“ der Play Console dazu passen.
F2 Mittel → in 2.2.0 umgesetzt Verlauf unverschlüsselt und in Sicherungen. scan_history_v1 ist Klartext-JSON in SharedPreferences/NSUserDefaults. Android Auto Backup ist aktiv, weil android:allowBackup nicht gesetzt ist (Standard true). iOS nimmt UserDefaults in iCloud- und Gerätesicherungen auf. Der Verlauf kann WLAN-Passwörter, Matter-PINs, GiroCode-Daten (IBAN, Name) und VDV-Tickets (Name, Geburtsdatum) enthalten. (a) Den Verlauf von Sicherungen ausnehmen: Android allowBackup="false" oder dataExtractionRules/fullBackupContent ohne sharedpref; unter iOS den Verlauf in einer Datei mit isExcludedFromBackup speichern. (b) WLAN-Passwörter und Matter-Codes wie 2FA-Schlüssel nicht oder nur maskiert speichern. (c) Optional: Einstellung „Verlauf speichern“ an/aus.
F3 Gering Zwischenablage ohne Markierung „sensibel“. „Kopieren“ legt Passwörter und Geheimnisse im Klartext in die Zwischenablage. Android 13+ zeigt sie in der Vorschau und in den Zwischenablage-Verläufen von Tastaturen. iOS kann sie per Universal Clipboard synchronisieren. Unter Android für Passwort- und Geheimnis-Felder ClipDescription.EXTRA_IS_SENSITIVE setzen (Platform Channel). Unter iOS UIPasteboard mit localOnly und expirationDate nutzen.
F4 Gering App-Umschalter / Bildschirmfotos. Ergebnisse mit Geheimnissen sind in der Taskvorschau sichtbar. Weder FLAG_SECURE noch eine iOS-Abdeckung wird genutzt. Seit 2.2.0 zeigt „Code anzeigen“ den Inhalt als scanbare Grafik; wer in der Nähe ist, kann ihn mit einer Kamera abgreifen (z. B. WLAN-Passwort, 2FA-Schlüssel). Die Anzeige startest du bewusst. Optional: Die Vorschau verbergen, solange die Ergebnisseite ein Passwort oder Geheimnis zeigt.
F5 Gering Verlaufsexport im Klartext. CSV und JSON enthalten alle Einträge ohne Schutz. Wo sie danach liegen, hängt von der Ziel-App ab (Cloud, E-Mail). Den Export startest du bewusst. Im Exportdialog darauf hinweisen, dass sensible Inhalte enthalten sein können (z. B. WLAN-Passwörter).
F6 Info → in 2.2.0 behoben Datenschutzerklärung bei VDV-Tickets ungenau. PRIVACY.md spricht von einem „maskierten Namen“. Der Parser (decodeTravelerName) zeigt auch Klartextnamen (Vorname#Nachname), wenn das Ticket sie enthält. Formulierung anpassen: „Name (je nach Ticket im Klartext oder maskiert)“.
F7 Info Kein App-eigenes Privacy Manifest unter iOS. ios/Runner/PrivacyInfo.xcprivacy fehlt. Die Plugins (shared_preferences_foundation, mobile_scanner, url_launcher_ios, package_info_plus, share_plus, flutter_secure_storage) bringen eigene mit. Die Vorgaben des App Store sind damit erfüllt. Optional: Ein App-Manifest mit NSPrivacyTracking = false und ohne erhobene Datentypen ergänzen, der Vollständigkeit halber.
F8 Info Sperrliste statt Positivliste für URL-Schemata. linkUri sperrt file, content, data, javascript, vbscript, intent, about, blob und chrome. Andere Schemata mit // sowie fido, magnet, bitcoin, lightning und ethereum sind erlaubt, jeweils nach einer Bestätigung mit vollständigem Ziel. Vertretbar. Bei Bedarf auf eine Positivliste umstellen (http, https, market, itms-apps, …).
F9 Info Auswertung fremder Eingaben. Der BER-Parser prüft jede Länge und begrenzt das Längenfeld auf 3 Byte. Die VDV-Dekodierung steckt in try/catch, ebenso der Binär- und der Deutsche-Post-Parser. RSA (modPow) arbeitet nur auf Daten in QR-Größe (wenige KB); ein nennenswertes Risiko für Denial-of-Service gibt es deshalb nicht. Es gibt kein WebView, keinen dynamischen Code und keine Deep Links. Exportiert sind nur die Launcher-Activity und der ProfileInstallReceiver, der durch die Berechtigung DUMP geschützt ist. Kein Handlungsbedarf. Die Tests mit Grenzfällen beibehalten.
F10 Info Abhängigkeiten. Alle direkten Abhängigkeiten sind aktuell, außer cupertino_icons (1.0.9 → 2.0.0, nur Symbole). Einige transitive Pakete liegen ein Patch-Release zurück. Neu in 2.2.0: flutter_secure_storage (Schlüsselbund/Keystore), pointycastle und barcode_widget (reines Dart, ohne Netzwerk und ohne Berechtigungen). Ein Abgleich mit Schwachstellen-Datenbanken wurde nicht gemacht. Regelmäßig flutter pub upgrade ausführen. osv-scanner in die Release-Checkliste aufnehmen.

Vorhandene Schutzmaßnahmen (positiv)


7. Risiken für die Betroffenen

Wahrscheinlichkeit (W) und Schwere (S): gering / mittel / hoch.

Risiko Ursache W S Vor Maßnahmen Nach Maßnahmen (Abschnitt 8)
R1 Google erfährt von der App-Nutzung ML-Kit-Telemetrie (F1) hoch (Android) gering (keine Inhalte, keine Bilder) mittel gering (mit anderer Bibliothek) / unverändert (nur Offenlegung)
R2 Jemand liest Geheimnisse aus dem Verlauf Entsperrtes oder verlorenes Gerät, Backup-Konto kompromittiert (F2) gering mittel gering–mittel gering (seit 2.2.0 verschlüsselt; auf einem entsperrten Gerät zeigt die App den Verlauf weiterhin an)
R3 Geheimnisse gelangen über die Zwischenablage nach außen Zwischenablage-Verlauf, Tastatur-Apps, Universal Clipboard (F3) gering mittel gering gering
R4 Phishing / Schadsoftware über Codes Schädlicher Link im QR-Code mittel hoch gering (Bestätigung, vollständiges Ziel sichtbar, gesperrte Schemata) gering
R5 Nachschlagedienste erfahren Artikel- oder Sendungsnummern Du tippst „Online nachschlagen“ / „Sendung verfolgen“ mittel gering gering gering
R6 Mitlesen / Bildschirmfotos Taskvorschau (F4) gering gering gering gering
R7 Der Export landet an einem unsicheren Ort Export im Klartext (F5) gering mittel gering gering

8. Maßnahmenplan

Priorität Maßnahme Befund Status
1 Verlauf verschlüsseln (AES-256-CBC + HMAC, Schlüssel in Schlüsselbund/Keystore) und Android-Sicherung abschalten F2 erledigt (2.2.0)
2 WLAN-Passwörter und Matter-Einrichtungscodes nicht im Verlauf speichern (wie 2FA) oder maskieren F2 offen
3 „Datensicherheit“ in der Play Console mit der ML-Kit-Telemetrie abgleichen und bei Bedarf anpassen; § 25 TDDDG rechtlich prüfen F1 offen
4 Eine Android-Erkennungsbibliothek ohne Telemetrie prüfen F1 offen
5 PRIVACY.md bei VDV-Namen korrigieren F6 erledigt (2.2.0)
6 Sensible Inhalte in der Zwischenablage markieren F3 offen
7 Hinweis auf sensible Inhalte beim Verlaufsexport F5 offen
8 Optional: Taskvorschau verbergen, iOS-App-Privacy-Manifest ergänzen, Positivliste für Schemata F4, F7, F8 offen
9 osv-scanner / flutter pub outdated in die Release-Checkliste F10 offen

9. Ergebnis und Überprüfung

Rolle Name Datum
Verantwortlicher Thorsten Ludewig