Dateizugriff einer macOS-App nach dem Neustart prüfen

Security ·ca. 5 Min. Lesezeit

Dateizugriff einer macOS-App nach dem Neustart prüfen

Eine Dateilesefunktion, die auf einem entfernten Mac im Testverzeichnis problemlos funktioniert, kann bei Nutzern mit „Zugriff verweigert“ scheitern. Häufig liegt die Testdatei zufällig im Container der App. Oder es wurde nur geprüft, ob sie sich direkt nach der Auswahl öffnen lässt – nicht aber nach einem Neustart der App. Für die Abnahme braucht es deshalb eine Datei außerhalb des Containers, die der Nutzer selbst auswählt. Die Prüfung muss auch das erneute Öffnen nach einem Neustart umfassen.

Zuerst die Testgrenzen festlegen

Die App Sandbox beschränkt den Zugriff auf Dateien außerhalb des App-Containers. Wenn ein Nutzer über den systemeigenen Dateiauswahldialog Zugriff gewährt, bedeutet das nicht, dass die App die Datei dauerhaft über ihren ursprünglichen Pfad lesen kann. Soll sich die App die Datei merken, muss sie ein Lesezeichen mit Sicherheitsbereich speichern. Beim nächsten Start muss sie dieses Lesezeichen auflösen und den Zugriff für die Dauer des tatsächlichen Lese- oder Schreibvorgangs aktivieren.

Legen Sie eine gewöhnliche Textdatei mit eindeutig erkennbarem Inhalt außerhalb des App-Containers ab. Wählen Sie kein Verzeichnis, das durch zusätzliche Datenschutzberechtigungen des Systems geschützt ist: Sonst vermischen sich bei diesem Test zwei verschiedene Berechtigungsmechanismen. Halten Sie außerdem eine Datei innerhalb des Containers als Vergleichsfall bereit. Dass diese lesbar ist, belegt nur, dass die grundlegende Dateiverarbeitung funktioniert – nicht den Zugriff auf externe Dateien.

Das Abnahmekriterium lautet nicht „Nach dem Schließen des Auswahldialogs tritt kein Fehler auf“, sondern: „Die App kann die ausgewählte Datei nach einem Neustart weiterhin im Rahmen der erteilten Berechtigung lesen und bietet einen Weg zur Behebung, wenn die Berechtigung nicht mehr nutzbar ist.“

Berechtigungen der ausgelieferten App prüfen

Prüfen Sie zuerst die tatsächlich ausgelieferte .app, nicht nur die im Projekt bearbeitete Berechtigungsdatei. Weichen Build-Konfiguration oder Signierung ab, können die Deklarationen im fertigen Produkt anders aussehen. Ersetzen Sie APP im folgenden Beispiel durch den tatsächlichen Pfad des aktuellen Builds:

APP="$PWD/build/Reader.app"
codesign --verify --strict --verbose=2 "$APP"
codesign -d --entitlements :- "$APP"

Prüfen Sie, ob die Sandbox-Berechtigung aktiviert ist. Bei einem schreibgeschützten Import muss die Leseberechtigung für vom Nutzer ausgewählte Dateien vorhanden sein. Eine Lese- und Schreibberechtigung kommt erst infrage, wenn die Originaldatei tatsächlich geändert werden muss. Soll der Zugriff über App-Neustarts hinweg bestehen bleiben, prüfen Sie außerdem die Deklaration für appbezogene Lesezeichen. Erweitern Sie die Zugriffsrechte nicht auf unbeteiligte Verzeichnisse, nur damit der Test besteht.

Die Signaturprüfung zeigt lediglich, welche Berechtigungen deklariert sind. Sie zeigt nicht, ob der Nutzer eine Datei ausgewählt hat oder ob sich ein Lesezeichen wiederherstellen lässt. Beides muss in der laufenden App geprüft werden.

Lesezeichen speichern und Zugriff paarweise verwalten

Sobald NSOpenPanel die vom Nutzer ausgewählte URL zurückgibt, erstellen Sie ein Lesezeichen mit Sicherheitsbereich und speichern die erhaltenen Data im persistenten Speicher der App. Speichern Sie nicht nur url.path: Der Pfad hält den Speicherort fest, enthält aber nicht die Informationen, die zum erneuten Erlangen des Zugriffs nötig sind.

Fassen Sie beim Lesen das Auflösen, Aktivieren und Beenden des Zugriffs in einer Funktion zusammen, damit auch bei Fehlern aufgeräumt wird:

enum FileAccessError: Error {
    case staleBookmark
    case accessDenied
}

func readSelectedFile(bookmark: Data) throws -> Data {
    var stale = false
    let url = try URL(
        resolvingBookmarkData: bookmark,
        options: .withSecurityScope,
        relativeTo: nil,
        bookmarkDataIsStale: &stale
    )
    guard !stale else { throw FileAccessError.staleBookmark }
    guard url.startAccessingSecurityScopedResource() else {
        throw FileAccessError.accessDenied
    }
    defer { url.stopAccessingSecurityScopedResource() }
    return try Data(contentsOf: url)
}

Auch beim Erstellen des Lesezeichens muss die Option für den Sicherheitsbereich verwendet werden; die zurückgegebenen Daten müssen zuverlässig gespeichert werden. Das Beispiel bricht den Lesevorgang bei einem veralteten Lesezeichen ab. Die Produktoberfläche sollte dann eine erneute Dateiauswahl ermöglichen und nach Erteilung der neuen Berechtigung ein neues Lesezeichen erstellen. Der Rückgabewert von startAccessingSecurityScopedResource() muss geprüft werden. stopAccessingSecurityScopedResource() darf nicht erst beim Beenden der App aufgerufen werden.

Neustart-Regressionstest in einer grafischen Sitzung durchführen

Auf einem Cloud-Mac lässt sich die Signatur über die Kommandozeile prüfen. Für den interaktiven Test mit NSOpenPanel ist jedoch eine nutzbare grafische macOS-Sitzung erforderlich. Dass sich Befehle per SSH ausführen lassen, heißt nicht, dass auch der Dateiauswahldialog erscheint. Stellen Sie bei automatisierten Tests ebenfalls sicher, dass der Testprozess in einer Umgebung mit grafischer Sitzung läuft.

Führen Sie mit derselben Testdatei die folgenden Schritte aus und halten Sie jeweils das erwartete und das tatsächliche Ergebnis fest:

  1. Starten Sie die App erstmals und versuchen Sie, die externe Datei ohne Auswahldialog über einen gespeicherten Pfad zu lesen. Prüfen Sie, dass die App die vorgesehene Autorisierung nicht allein über den Pfad umgeht.
  2. Wählen Sie die Datei selbst im Dialog aus, lesen und prüfen Sie ihren Inhalt und speichern Sie das Lesezeichen.
  3. Beenden Sie die App vollständig und starten Sie dasselbe ausgelieferte Produkt erneut. Lösen Sie das Lesezeichen auf, lesen Sie die Datei erneut und prüfen Sie ihren Inhalt.
  4. Verschieben Sie die Testdatei und versuchen Sie es erneut. Erwartet werden eine verständliche Fehlermeldung und eine Möglichkeit zur erneuten Auswahl – nicht die falsche Diagnose eines Signaturfehlers für eine fehlende Datei.
  5. Testen Sie den Fehlerpfad mit beschädigten Lesezeichendaten. Die App muss den Lesevorgang abbrechen und um eine erneute Auswahl bitten, statt wiederholt Dialoge anzuzeigen oder unbegrenzt neue Versuche zu starten.

Der dritte Schritt wird besonders leicht übersehen: Wird nur innerhalb eines einzigen App-Prozesses gelesen, kann unbemerkt bleiben, dass das Lesezeichen nie dauerhaft gespeichert wurde. Wenn der Test auch das Zurückschreiben in die Datei umfasst, wiederholen Sie diese Schritte separat mit Lese- und Schreibberechtigung. Ein schreibgeschützter Test reicht dafür nicht aus.

Fehler anhand der Befunde eingrenzen

Scheitert der Zugriff unmittelbar nach der Auswahl, prüfen Sie zuerst, ob die von NSOpenPanel zurückgegebene URL korrekt verwendet wird und ob die deklarierten Berechtigungen zum benötigten Lese- oder Schreibzugriff passen. Funktioniert der Zugriff zunächst, aber nicht mehr nach einem Neustart, prüfen Sie vorrangig, ob das Lesezeichen tatsächlich dauerhaft gespeichert wurde und ob die neu gestartete App dieselbe Identität und Signaturkonfiguration hat. Treten Fehler nur in bestimmten Verzeichnissen auf, schließen Sie zunächst zusätzliche Datenschutzberechtigungen dieser Verzeichnisse als Ursache aus, statt die Sandbox-Berechtigungen pauschal auszuweiten.

Das Testprotokoll sollte mindestens die Version der ausgelieferten App, ihre endgültig deklarierten Berechtigungen, die Art des Testdateiverzeichnisses, die Ergebnisse vor und nach der Auswahl sowie nach dem Neustart und den Fehlertyp enthalten. Protokollieren Sie nur erforderliche Zustände und Fehler, nicht die Rohdaten des Lesezeichens oder den Dateiinhalt. Scheitert ein späterer Build, kann das Team so zwischen geänderten Berechtigungen, einem Problem im Lebenszyklus des Lesezeichens und einer fehlenden grafischen Sitzung unterscheiden – statt sich erneut auf „Auf meinem Rechner lässt sich die Datei öffnen“ zu verlassen.

Häufig gestellte Fragen

Warum muss die App nach der Dateiauswahl ein Lesezeichen speichern?

Soll die App nach einem Neustart erneut auf die ausgewählte Datei zugreifen, muss sie ein sicherheitsbezogenes Lesezeichen speichern, später auflösen und den Zugriff für die Dauer des Lesens aktivieren.

Lässt sich der gesamte Test über SSH ausführen?

Nein. Signatur und Berechtigungen lassen sich per Kommandozeile prüfen. Für Dateidialog und interaktive Zugriffstests benötigt der Testprozess eine nutzbare macOS-Grafiksitzung.

Binden Sie einen Cloud-Mac in Ihren Workflow ein

VPSPush bietet dedizierte physische Macs mit Fernzugriff. Wählen Sie Standort und Laufzeit und prüfen Sie im Bestellvorgang die Zugangsdaten und den Endpreis.

Cloud-Mac-Angebote ansehen und bestellen