Identität ausführbarer Agent-Dateien nach dem Austausch eines symbolischen Links
Teste unter macOS die Identität ausführbarer Agent-Dateien gegen den Austausch symbolischer Links, binde Genehmigungen an laufenden Code und halte Pfad-Aliase aus Vertrauensentscheidungen heraus.

Ein Dateiname ist ein Verweis, keine Identität. Das klingt kleinlich, bis ein Agent eine Genehmigung erhält, während er als ~/bin/agent läuft, jemand diesen Pfad auf ein anderes Programm umbiegt und das Gateway den nächsten Aufrufer als vertrauenswürdig einstuft, weil das Etikett noch vertraut aussieht.
Symbolische Links machen den Fehler leicht reproduzierbar, sind aber nicht die eigentliche Ursache. Jede veränderliche Indirektion kann ihn erzeugen: ein Shell-Wrapper, ein PATH-Eintrag, eine kopierte Binärdatei, ein Entwicklungscheckout oder ein Launcher, der bei jeder Anfrage einen Pfad auflöst. Ein Gateway, das einen Pfad genehmigt, genehmigt ein Objekt, das ein unprivilegierter Benutzer oft ersetzen kann.
Unter macOS ist der laufende Prozess mit seiner Codeidentität die nützliche Einheit. Apple Code Signing Services können Code beschreiben und validieren, der zu einem Prozess gehört. Ein Pfad darf zur Diagnose im Datensatz auftauchen, aber nicht die Autorisierungsentscheidung tragen.
Ein symbolischer Link ist ein Namensdienst, nicht das Programm
Ein symbolischer Link speichert eine Zeichenkette, die der Kernel auflöst, wenn ein Programm sie öffnet oder ausführt. Wenn diese Zeichenkette ersetzt wird, findet ein späterer exec-Aufruf etwas anderes. Das Programmbild eines bereits gestarteten Prozesses wird dadurch nicht verändert.
Dieses Detail vermittelt trügerische Sicherheit. Man testet den Austausch eines Links, sieht, dass der ursprüngliche Prozess weiterläuft, und schließt daraus, dass der Angriff harmlos ist. Der Test hat nur normales Prozessverhalten gezeigt. Er hat nicht die entscheidende Entscheidung geprüft: Erkennt das Gateway einen späteren Prozess über denselben Alias als den Prozess, den es zuvor genehmigt hat?
Nehmen wir einen Coding-Agenten, der über diesen Pfad gestartet wird:
~/bin/build-agent -> ~/work/approved-agent
Das Gateway erhält die erste Anfrage, sieht ~/bin/build-agent und bittet den Betreiber um Erlaubnis. Danach ändert ein Angreifer den Link:
~/bin/build-agent -> ~/Downloads/replacement-agent
Wenn der genehmigte Prozess weiterhin Anfragen stellt, kann das Gateway diese Sitzung bis zum Ende des Prozesses korrekt fortsetzen. Das ist nicht der Fehler. Der Fehler entsteht, wenn ein anderer Prozess über denselben Namen startet und das Gateway sagt: «~/bin/build-agent habe ich bereits genehmigt.»
Der zweite Prozess ist ein neues Sicherheitsobjekt. Er braucht eine neue Prüfung und, sofern er nicht einer bewusst definierten Update-Regel entspricht, eine neue Genehmigung.
Derselbe Fehler tritt auch ohne symbolische Links auf. Ein Gateway, das codesign auf den von einem Client gelieferten Pfad anwendet, kann eine Datei prüfen, während es eine Anfrage von einem anderen Prozess akzeptiert. Der Client kann die Prüfung durch eine Änderung des Pfads danach überholen oder das Gateway einfach auf einen stabilen Alias verweisen, der auf wechselnde Ziele zeigt. Ein gut aussehender Pfad auf einer Genehmigungskarte behebt dieses Design nicht.
Apple behandelt Code-Anforderungen als Identitätsbedingungen und nicht als Dateinamen. Laut Apple-Dokumentation sind die Kriterien einer Designated Requirement ausschlaggebend dafür, ob Code als derselbe Code wie zuvor erkannt wird. Wenn der Entwickler keine eigene Anforderung festlegt, wird sie normalerweise aus der Signaturautorität und dem eingebetteten Bezeichner abgeleitet. Das ist die richtige Richtung, mit einer wichtigen Einschränkung: Eine Code-Anforderung beschreibt die Codeidentität, nicht eine laufende Prozesssitzung.
Der laufende Prozess ist das Objekt, das die Genehmigung erhalten hat
Ein Gateway sollte seine Autorisierungsentscheidung anhand einer vom Betriebssystem erhaltenen Referenz auf einen laufenden Prozess treffen. Die Entscheidung sollte anschließend an den Prozesslauf gebunden bleiben, nicht an einen vom Client behaupteten Pfad, einen Namen der ausführbaren Datei oder eine wiederverwendbare Umgebungsvariable.
Unter macOS hat eine gute Prüfung zwei Aufgaben:
- Signaturinformationen für den tatsächlichen aufrufenden Prozess beschaffen.
- Diesen Prozess validieren, bevor die Identitätsinformationen als Autorisierungsnachweis verwendet werden.
Das sind getrennte Aufgaben. SecCodeCopyDesignatedRequirement kann eine Designated Requirement für signierten Code zurückgeben. Apple weist jedoch ausdrücklich darauf hin, dass der Aufruf die Signatur nicht validiert. Nach der Signierung veränderter oder fehlerhaft signierter Code kann weiterhin unvollständige oder irreführende Informationen liefern. Ein Gateway muss deshalb zusätzlich eine Gültigkeitsprüfung durchführen.
Der Prozessdatensatz sollte genügend Nachweise enthalten, um die Entscheidung später erklären zu können:
- Prozess-ID oder besser eine vom Betriebssystem ausgestellte Prozessberechtigung, die gegen die Wiederverwendung von PIDs geschützt ist
- zum Prüfzeitpunkt beobachteter Pfad der ausführbaren Datei, nur als Kontext
- Signaturbezeichner und Team-Bezeichner, sofern vorhanden
- Signaturautorität und Zertifikatskette, soweit zutreffend
- Designated Requirement
- cdhash oder die Menge der unterstützten cdhash-Werte
- Ergebnis und Zeitpunkt der Signaturvalidierung
Verwechsle diese Liste nicht mit einer Richtliniensprache. Das Gateway braucht eine enge Antwort: Welcher laufende Prozess stellt die Anfrage, und hat ein Mensch diesen Lauf genehmigt? Einige Identitätsdaten reichen dafür aus. Eine Sammlung von Pfadregeln nicht.
Der schwierige Teil ist der Umgang mit Aktualisierungen. Eine Designated Requirement bleibt über legitime Versionen hinweg oft stabil. Deshalb verwendet macOS sie für Kontinuität, wenn ein Benutzer einer Anwendung den Zugriff auf einen geschützten Dienst erlaubt. Apple Technical Note TN3127 nennt das vertraute Beispiel einer App-Aktualisierung, die wieder auf das Mikrofon zugreift: macOS vergleicht die neue Version mit der gespeicherten Designated Requirement.
Für eine dauerhafte Betriebssystemberechtigung ist dieses Verhalten sinnvoll. Wenn eine frühere menschliche Genehmigung jedoch stillschweigend für einen neuen autonomen Agent-Lauf wiederverwendet wird, ist es zu weit gefasst. Ein Gateway kann die Signaturautorität anzeigen, damit ein Betreiber das Programm erkennt, und trotzdem erneut fragen, wenn ein neuer Prozess startet. Der Signierer belegt die Herkunft. Die Prozessgrenze bestimmt die Lebensdauer der Einwilligung.
Statische Pfadprüfungen lassen eine nicht wegzuerklärende Race Condition offen
Eine statische Prüfung beantwortet eine statische Frage: «Welche Signatur hat diese Datei an diesem Pfad gerade?» Allein kann sie nicht beantworten: «Welcher Code hat diese Anfrage gestellt?»
Diese Lücke bleibt bestehen, selbst wenn die statische Prüfung technisch korrekt ist. Angenommen, ein Gateway erhält eine Anfrage mit dem Pfad /Users/dev/bin/agent. Es führt Folgendes aus:
codesign --verify --strict --verbose=2 /Users/dev/bin/agent
codesign -d -r- /Users/dev/bin/agent
Beide Befehle können eine gültige Signatur und eine Designated Requirement melden. Danach speichert das Gateway den Pfad als genehmigte Identität. Zwischen der Prüfung und einer späteren Anfrage kann ein Angreifer agent auf eine andere Datei umbiegen. Bei der nächsten Anfrage kann das Gateway die Befehle erneut ausführen und Informationen über die Ersatzdatei erhalten. Keiner der beiden Befehle beweist eine Verbindung zu dem Prozess, der die Anfrage gestellt hat.
Es gibt eine zweite Race Condition, die Teams übersehen. Ein Helfer kann einen Pfad prüfen, bevor er einen Agenten startet, und später eine Verbindung von einem Kindprozess erhalten. Die Pfadprüfung beschreibt die übergeordnete Datei zum Startzeitpunkt. Die Verbindung beschreibt einen Prozess zum Zeitpunkt der Anfrage. Wenn der Helfer diese beiden Ereignisse nicht mithilfe einer Betriebssystemberechtigung verbindet, hat er eine Annahme geschaffen und sie Herkunft genannt.
Apples APIs für Codesignaturen stellen deshalb getrennte Informationskategorien bereit. kSecCSSigningInformation fordert Zertifikats- und CMS-Daten an, kSecCSRequirementInformation fordert Anforderungen an und kSecCSDynamicInformation fordert dynamische Gültigkeitsinformationen für laufenden Code an. Die API macht daraus noch kein vollständiges Gateway-Design, aber sie zeigt den Unterschied deutlich: Die statische Signaturprüfung und der Zustand des laufenden Codes sind verschiedene Eingaben.
Ein Dateiname gehört weiterhin in die Genehmigungsanzeige. Betreiber müssen sehen können, ob eine Anfrage aus einem Checkout in ~/work/demo oder aus einem installierten Tool in /Applications stammt. Behandle das als Kontext der Benutzeroberfläche. Der Autorisierungsdatensatz muss an den vom Betriebssystem identifizierten Aufrufer gebunden bleiben.
Den Austausch reproduzieren, ohne einen echten Agenten anzufassen
Mit zwei kleinen Binärdateien in einem temporären Verzeichnis lässt sich das Pfadproblem demonstrieren. Dafür brauchst du weder ein produktives Token noch einen SSH-Schlüssel oder ein verändertes Anwendungsbundle.
Erstelle einen Arbeitsbereich und kompiliere zwei Programme, die unterschiedliche Marker ausgeben. Der Code bleibt absichtlich schlicht, weil das zu testende Verhalten der Austausch und nicht die Programmlogik ist.
work="$(mktemp -d /tmp/agent-identity.XXXXXX)"
cd "$work"
cat > approved.c <<'EOF'
#include <cstdio.h>
#include <unistd.h>
int main(void) {
printf("approved process pid=%d\n", getpid());
fflush(stdout);
sleep(60);
return 0;
}
EOF
cat > replacement.c <<'EOF'
#include <cstdio.h>
#include <unistd.h>
int main(void) {
printf("replacement process pid=%d\n", getpid());
fflush(stdout);
sleep(60);
return 0;
}
EOF
clang approved.c -o approved-agent
clang replacement.c -o replacement-agent
codesign --force --sign - --identifier com.example.approved approved-agent
codesign --force --sign - --identifier com.example.replacement replacement-agent
ln -s "$work/approved-agent" agent
Eine Ad-hoc-Signatur reicht für einen lokalen Mechaniktest aus, enthält aber keine Zertifikatskette. Apple dokumentiert, dass Ad-hoc-signierter Code keine Zertifikate und leere CMS-Daten besitzt. Verwende eine Ad-hoc-Signatur nicht, um einen Vertriebssignierer zu simulieren oder zu entscheiden, was dein produktives Gateway akzeptiert.
Halte fest, worauf der Alias zeigt, prüfe seine Signatur und starte den ersten Prozess:
printf 'alias before: %s\n' "$(readlink agent)"
codesign -d -r- agent 2>&1 | sed -n '1,8p'
./agent &
first_pid=$!
printf 'first pid: %s\n' "$first_pid"
ps -p "$first_pid" -o pid=,comm=,args=
Die Ausgabe sollte ungefähr so aussehen:
alias before: /tmp/agent-identity.xxxxxx/approved-agent
Executable=/tmp/agent-identity.xxxxxx/agent
designated => identifier "com.example.approved"
approved process pid=48291
first pid: 48291
48291 ... ./agent
Ersetze nun den Link, während der erste Prozess schläft:
rm agent
ln -s "$work/replacement-agent" agent
printf 'alias after: %s\n' "$(readlink agent)"
codesign -d -r- agent 2>&1 | sed -n '1,8p'
ps -p "$first_pid" -o pid=,comm=,args=
Bei der Prüfung von agent solltest du nun com.example.replacement sehen, während first_pid weiterläuft. Starte den Alias ein zweites Mal:
./agent &
second_pid=$!
printf 'second pid: %s\n' "$second_pid"
wait "$first_pid" "$second_pid"
Der zweite Prozess gibt replacement process aus. Die beiden PIDs haben unterschiedliche Programmbilder ausgeführt, obwohl beide als ./agent gestartet wurden.
Dieses Ergebnis sollte deinen Gateway-Testplan ändern. Ein Test, der nur fragt, ob die alte PID weiterlief, hat fast nichts bewiesen. Der sinnvolle Test fragt, ob das Gateway die zweite PID als neuen Aufrufer behandelt und deren beobachtete Identität anzeigt, bevor sie eine genehmigte Aktion verwenden kann.
Ein sinnvoller Genehmigungstest hat drei getrennte Läufe
Gib dich nicht mit einem erfolgreichen Genehmigungstest und einem einzigen Symlink-Befehl zufrieden. Du brauchst drei Läufe, weil jeder eine andere Eigenschaft nachweist.
Starte zuerst das genehmigte Ziel über den Alias und stelle eine Aktionsanfrage. Das Gateway sollte einen Sitzungsdatensatz anlegen und eine Genehmigung anzeigen, die den tatsächlichen Aufrufer so beschreibt, dass ein Betreiber ihn beurteilen kann. Halte Sitzungs-ID, PID, beobachteten Pfad und die Fakten zur Codesignatur fest.
Ändere zweitens den Alias, während der erste Prozess weiterläuft. Lass den ersten Prozess eine weitere Anfrage stellen. Wenn dein Sitzungsmodell einen Prozesslauf bis zu dessen Ende genehmigt, kann das Gateway diese Anfrage zulassen. Das Programmbild hat sich nicht geändert. Bezeichne dieses erwartete Ergebnis nicht fälschlich als Schwachstelle.
Starte drittens einen neuen Prozess über den ersetzten Alias und stelle dieselbe Anfrage. Das Gateway darf die Genehmigung des ersten Prozesses nicht übernehmen, nur weil ausführbarer Dateiname, Befehlszeile, Arbeitsverzeichnis oder angeforderte Aktion übereinstimmen. Es sollte eine eigene Sitzung anlegen und den normalen Autorisierungsweg verlangen.
Verwende während des Tests eine Ergebnistabelle:
| Lauf | Alias-Ziel beim Start | Erwartetes Ergebnis |
|---|---|---|
| Erster Prozess | approved-agent | Neue Genehmigung, danach für diesen Lauf erlaubt |
| Erster Prozess nach dem Austausch | replacement-agent auf der Festplatte, altes Bild bleibt im Speicher | Verhalten der bestehenden Sitzung bis zum Ende |
| Zweiter Prozess | replacement-agent | Neue Genehmigung oder Ablehnung, niemals übernommene Genehmigung |
Ein weiterer Fall ist prüfenswert. Setze den Alias wieder auf die ursprüngliche Binärdatei und starte einen dritten Prozess. Ein Gateway sollte auch dann eine neue Sitzung anlegen. Dieselbe Codeidentität bedeutet nicht denselben Prozess. Wenn dein Produkt absichtlich eine dauerhafte Vertrauensbeziehung für einen signierten Herausgeber anbietet, muss das eine separate, ausdrücklich getroffene Betreiberentscheidung sein. Verstecke sie nicht in einer Funktion für prozessbezogene Genehmigungen.
Sallyports sitzungsbezogene Autorisierung ist standardmäßig aktiviert. Die Genehmigungskarte zeigt zuerst die Codesignaturautorität des Prozesses und nicht einen veränderlichen Dateinamen. Das gibt dem Betreiber bei der Anfrage eines neuen Agent-Prozesses einen belastbareren Anhaltspunkt.
Signierer, Designated Requirement und cdhash beantworten verschiedene Fragen
Teams fassen oft drei verschiedene Konzepte in der Aussage «von derselben App signiert» zusammen. Diese Abkürzung führt entweder zu ständigen Genehmigungsanfragen oder zu Berechtigungen, die zu lange gelten.
Eine Signaturautorität beantwortet die Frage, wer den Code signiert hat. Bei verteilter Software kann dazu eine Zertifikatskette und ein Team-Bezeichner gehören. Sie hilft dem Betreiber, einen bekannten Anbieter von einer zufälligen ausführbaren Datei zu unterscheiden. Einen exakten Build bezeichnet sie nicht.
Eine Designated Requirement beantwortet die Frage, ob macOS Code über Aktualisierungen hinweg als dieselbe Identität betrachtet. Apple sagt, dass jeder signierte Code eine Designated Requirement besitzt, entweder ausdrücklich festgelegt oder erzeugt. Die Standardanforderung umfasst normalerweise Signaturautorität und eingebetteten Bezeichner. Das macht sie für Kontinuität geeignet, kann aber auch spätere Versionen akzeptieren, die du selbst noch nicht geprüft hast.
Ein cdhash identifiziert ein bestimmtes signiertes CodeDirectory. Für Autorisierungszwecke ist er beinahe ein Fingerabdruck des Builds. Als Auditnachweis ist er sehr gut geeignet, weil er zwei Versionen mit demselben Signierer und Bezeichner unterscheiden kann. Als dauerhafte Genehmigungsregel für Entwicklerwerkzeuge ist er meist ungeeignet, da sich sein Wert bei normalen Aktualisierungen ändert.
Verwende die Nachweise passend zur Entscheidung:
- Verwende die Berechtigung des laufenden Prozesses, um eine Sitzung an einen Aufrufer zu binden.
- Zeige Signaturautorität und Bezeichner in der Genehmigungsoberfläche, damit der Betreiber die Quelle erkennen kann.
- Speichere Designated Requirement und cdhash, damit spätere Untersuchungen Herausgeberkontinuität und exakten Build unterscheiden können.
- Frage bei einem neuen Agent-Prozess erneut, selbst wenn Signierer und Designated Requirement übereinstimmen.
Der letzte Punkt ist bewusst strenger als macOS-Berechtigungen. Ein Agent-Gateway kann HTTP-Anfragen oder SSH-Befehle mit Zugangsdaten ausführen, die nie in den Agent-Prozess gelangen. Das ist eine Aktionsgrenze und keine einmalige Mikrofonabfrage. Eine frühere Bestätigung für einen unabhängigen späteren Prozess wiederzuverwenden, schwächt die menschliche Kontrolle, die das Gateway ursprünglich rechtfertigte.
Aus einem Datei-Wächter keine Autorisierung machen
Eine naheliegende Reaktion besteht darin, den Agent-Pfad zu überwachen und die Berechtigung zu widerrufen, wenn sich die Datei ändert. Das wirkt einfach: ursprüngliche Inode speichern, Dateisystemereignisse abonnieren und die Genehmigung nach einem Schreib- oder Umbenennungsvorgang ungültig machen.
Das ist die falsche Grundlage.
Dateisystemereignisse sind nützliche Telemetrie, aber kein Beweis für die Identität des Aufrufers. Pfade können mehrere Namen haben. Eine Binärdatei kann kopiert werden. Ein Prozess kann aus einer gelöschten Datei gestartet werden. Ereignisse können verzögert oder zusammengefasst zugestellt werden. Ein Angreifer muss keinen spektakulären Wettlauf gewinnen, wenn dein Design bereits den Pfad statt des Prozesses autorisiert.
Auch ein Vergleich von Inodes repariert das Modell nicht. Er kann einen Austausch in einem bestimmten Verzeichnis erkennen, sagt aber nichts Brauchbares über einen Prozess aus, der von einem anderen Hardlink oder einer kopierten Datei gestartet wurde. Außerdem führt er bei normalen Entwicklungsabläufen, in denen Werkzeuge ständig neu bauen, umbenennen und ersetzen, zu brüchigem Verhalten.
Behandle Dateibeobachtungen als Anlass, nützlichen Auditkontext hinzuzufügen. Wenn der aktuelle Pfad auf ein anderes Ziel zeigt als zum Genehmigungszeitpunkt, protokolliere diese Tatsache. Wenn dein Gateway einen neuen aufrufenden Prozess sieht, prüfe diesen Aufrufer und wende den normalen Autorisierungsweg an. Die Prozessgrenze übernimmt die Sicherheitsentscheidung, ohne dass der Wächter wie ein Referenzmonitor vertrauenswürdig sein muss.
Diese Regel verhindert auch einen subtileren Fehler: einen Wrapper zu genehmigen, weil seine Signatur vertraut aussieht, und dabei zu ignorieren, was er startet. Ein signierter Wrapper kann ein unsigniertes Kind ausführen, ein lokales Skript laden oder anhand seiner Umgebung ein Ziel auswählen. Das Gateway muss den Prozess identifizieren, der tatsächlich die Verbindung herstellt und die privilegierte Aktion anfordert. Ist der Wrapper der Aufrufer, genehmigst du ihn. Ist sein Kind der Aufrufer, prüfst du das Kind.
Genehmigung an eine Betriebssystemberechtigung binden und bei Unklarheit ablehnen
Eine praktische Implementierung braucht ein vom Betriebssystem bereitgestelltes Handle für den Anforderer. Unter macOS bedeutet das häufig, über Code Signing Services ein Codeobjekt für den aufrufenden Prozess zu erhalten. Dafür werden Prozessattribute aus dem vertrauenswürdigen Verbindungskontext verwendet und nicht Werte, die aus den Eingaben des Agenten übernommen wurden.
Die sichere Reihenfolge sieht so aus:
- Verbindung annehmen und die Betriebssystemidentität des Aufrufers aus dem Verbindungsmechanismus beziehen.
- Diese Identität einem laufenden Codeobjekt zuordnen.
- Die Gültigkeit des Codes prüfen, bevor Identitätsdaten für die Autorisierung gelesen werden.
- Signaturautorität, Bezeichner, Designated Requirement und cdhash aus diesem laufenden Codeobjekt lesen.
- Einen Sitzungsdatensatz an die Aufruferberechtigung binden und eine Genehmigung verlangen, wenn keine genehmigte Sitzung existiert.
- Vor jeder Aktion erneut prüfen, ob die Aufruferberechtigung noch auf denselben laufenden Prozess verweist, und die Sitzung beim Ende des Prozesses oder nach einem Widerruf durch den Betreiber löschen.
Die Einzelheiten des ersten Schritts hängen vom Transport ab. Ein lokaler Unix-Socket, eine XPC-Verbindung und eine Pipe zwischen Eltern- und Kindprozess stellen unterschiedliche Berechtigungen bereit. Der gefährliche Rückfall ist immer derselbe: eine PID, einen Pfad, eine Bundle-ID oder eine Zusammenfassung der Signatur zu akzeptieren, die der Agent in seiner Anfrage selbst mitsendet. Der Agent kontrolliert diese Nutzdaten. Sie sind kein Beleg für irgendetwas.
Die Wiederverwendung von PIDs verdient besondere Aufmerksamkeit. Eine reine PID ist nur so lange eindeutig, wie der Prozess existiert. Nach seinem Ende kann das Betriebssystem dieselbe Nummer einem anderen Prozess zuweisen. Speichere eine umfassendere Berechtigung, wenn die API eine solche anbietet. Wenn dein Transport keine dauerhafte Bindung an den Aufrufer bereitstellen kann, beschränke die Sitzung auf die Lebensdauer der Verbindung und autorisiere nach einer neuen Verbindung erneut. Bei einem unklaren Aufrufer sicher abzulehnen ist weniger bequem, als ihn zu akzeptieren. Genau dort entstehen jedoch Pfad-Austauschfehler.
Halte Genehmigungsaufforderungen verständlich. Wenn das Gateway eine Ad-hoc-Signatur sieht, soll es das sagen. Wenn keine gültige Signatur vorhanden ist, soll es das ebenfalls sagen. Hat das Programm einen vertrauten Anzeigenamen, aber eine neue Signaturautorität, darf diese nicht hinter einem aufklappbaren Detailbereich verborgen werden. Die erste Zeile sollte dem Betreiber mitteilen, wer den Prozess signiert hat und welche Aktion er ausführen möchte.
Die Auditspur muss die Entscheidung bewahren, nicht nur die Anfrage
Ein Protokolleintrag mit POST /deploy und dem Ergebnis «erfolgreich» kann einen Vorfall mit einem symbolischen Link nicht erklären. Er zeigt, was geschehen ist, aber nicht, warum das Gateway diesen Aufrufer handeln ließ.
Speichere für jede genehmigte Sitzung eine Momentaufnahme der zum Genehmigungszeitpunkt beobachteten Identitätsnachweise. Speichere für jede Aktion den Sitzungsbezug und das Ergebnis. Der Aktionsdatensatz muss die Zertifikatsdaten nicht wiederholt kopieren, aber er muss auf genau den Genehmigungsdatensatz zurückführen, der diese Daten enthält.
Ein kompakter Datensatz kann so aussehen:
{
"session": "6F2A...",
"caller": {
"process": "OS-issued caller credential",
"path_observed": "/private/tmp/demo/agent",
"signing_identifier": "com.example.approved",
"designated_requirement": "identifier com.example.approved",
"cdhash": "<observed digest>",
"validity": "valid"
},
"approval": "granted",
"action": "HTTP POST /deploy",
"result": "success"
}
Der Pfad bleibt nützlich. Er kann zeigen, dass ein Prozess aus einem temporären Verzeichnis oder einem Shell-Alias gestartet wurde. Er darf jedoch nicht genügen, um eine spätere Anfrage dieser Sitzung zuzuordnen.
Sallyport bewahrt ein Sitzungsjournal für Agent-Läufe und ein Aktivitätsjournal für einzelne Aufrufe auf. Beide werden aus einem einzigen verschlüsselten, hashverketteten Auditprotokoll erzeugt. Der Offline-Befehl sp audit verify prüft die Kette, ohne den Tresorschlüssel zu benötigen. Dadurch lässt sich ein Pfad-Austausch leichter überprüfen, weil das Genehmigungsereignis und die spätere Aktion getrennte Fakten bleiben und nicht in einer vagen Erfolgsmeldung verschwimmen.
Führe den Test mit dem symbolischen Link durch, bevor du eine Genehmigungsregel formulierst, die du später nicht erklären kannst. Wenn ein neu gestarteter Ersatzprozess die Genehmigung des ersten Prozesses verwenden kann, behandle den Namen der ausführbaren Datei nicht länger als bloßes Komfortfeld. Er ist in die Vertrauensentscheidung gelangt.
FAQ
Macht eine Codesignatur einen Pfad zu einer ausführbaren Datei vertrauenswürdig?
Eine signierte ausführbare Datei kann weiterhin über einen symbolischen Link, einen Hardlink, einen kopierten Pfad oder ein Startskript erreicht werden. Der Name zeigt nur, wo ein Prozess gefunden wurde. Er beweist weder, welcher Code läuft, noch wer ihn signiert hat.
Kann das Ersetzen eines symbolischen Links einen bereits laufenden Prozess ändern?
Nein. Ein laufender Prozess führt weiterhin das von exec geladene Programmbild aus, während das Ersetzen eines symbolischen Links die spätere Pfadauflösung beeinflusst. Das Sicherheitsproblem entsteht, wenn ein Gateway den veränderlichen Pfad erneut auflöst und dieses Ergebnis als Beleg für den bereits genehmigten Prozess behandelt.
Wie sollte eine macOS-App einen Agent-Prozess identifizieren?
Verwende den laufenden Prozess als Prüfobjekt, nicht den vom Client gelieferten Pfad. Sammle unter macOS die Signaturinformationen des Prozesses über Code Signing Services und validiere sie, bevor du eine Sitzung genehmigst.
Was ist eine Designated Requirement unter macOS?
Eine Designated Requirement beschreibt eine Gruppe von Code, die macOS über legitime Aktualisierungen hinweg als dieselbe Identität von Herausgeber und Anwendung betrachtet. Sie identifiziert nicht einen einzelnen Build eindeutig. Verwende sie daher für Kontinuität, nicht als einzigen Nachweis dessen, was ausgeführt wurde.
Sollte ich einen Agenten per cdhash genehmigen?
Ein cdhash identifiziert ein bestimmtes signiertes CodeDirectory und ist ein nützlicher Nachweis für einen konkreten Build. Er ist strenger als ein Signierer oder eine Designated Requirement. Wenn du ihn jedoch dauerhaft festschreibst, schlagen normale Aktualisierungen fehl, bis jemand den neuen Build ausdrücklich genehmigt.
Soll eine Agent-Genehmigung einen Neustart überleben?
Nein. Eine Genehmigung sollte zu einem Prozesslauf gehören, nicht zu einem Dateinamen und nicht zu einer dauerhaften Entwickleridentität. Ein neuer Prozess sollte ein neues Genehmigungsereignis erzeugen, auch wenn er aus derselben signierten Anwendung stammt.
Warum ist eine pfadbasierte Genehmigung für KI-Agenten gefährlich?
Das gefährliche Muster besteht darin, einen Helfer einmal zu genehmigen und danach jeden Prozess zu akzeptieren, der über diesen Pfad gestartet wird. Angreifer profitieren davon, weil sie nach der ersten Entscheidung einen symbolischen Link, einen Wrapper oder eine Binärdatei austauschen können, ohne den vertrauten Befehlsnamen zu ändern.
Was sollte ein Auditprotokoll für eine Agent-Aktion festhalten?
Ein Prüfprotokoll sollte die Prozess-ID oder das Audit-Token, den beobachteten Pfad als Kontext, Signaturautorität, Bezeichner, Designated Requirement, cdhash, das Validierungsergebnis und den Beginn der Sitzung enthalten. Der Pfad hilft bei der Diagnose, darf aber nicht der Vertrauensanker sein.
Was soll passieren, wenn die Ersatzdatei unsigniert oder anders signiert ist?
Eine unsignierte Ersatzdatei sollte abgelehnt werden, wenn deine Genehmigungsregel eine gültige Signatur verlangt. Eine von einer anderen Stelle signierte Ersatzdatei braucht eine neue Genehmigung. Ein legitimes Update unter einer Identität, die du bewusst zulässt, sollte deiner festgelegten Update-Regel folgen.
Ist es sicher, einen symbolischen Link auf meinem Arbeits-Mac auszutauschen?
Führe den Austausch in einem temporären Verzeichnis mit selbst kompilierten Binärdateien durch und verweise den Alias auf diese Dateien. Ersetze keine Dateien in einem Anwendungsbundle, das du nicht selbst erstellt hast, deaktiviere keine Plattformsicherungen und teste niemals mit produktiven Zugangsdaten.