Rechte: Regeln und Reichweite
Was ein Aufrufer erreicht, legen Regeln fest: welche Aliasse, welche Arten von Objekten und welche Objekte, welche Methoden und ob nur lesend. Regeln erhalten Dienstschlüssel, Personen, Windows-Konten und -Gruppen sowie SQL-Anmeldungen. Diese Seite erklärt, wie Regeln zusammenwirken.
Wichtige Funktionen
- Zuschnitt je Aufrufer und je Alias.
- Mehrere Regeln für verschiedene Aliasse, jede als Ganzes beurteilt.
- Rechte je Tabelle, Sicht und Prozedur; eine Sicht ohne Rechte auf ihre Tabellen.
- Ein persönlicher Schlüssel schränkt die Rechte seiner Person ein, gewährt aber nie mehr.
Grundkonzepte
Zuschnitt je Aufrufer
Regeln stehen unter Gateway:Security:Clients: erlaubte Aliasse, Ressourcenarten, Verben und ein
Nur-Lese-Kennzeichen. Ein Aufrufer ohne passende Regel erreicht nichts. Ein Schlüssel ohne Regel
verhindert den Start, weil er zwar anmelden, aber nichts erreichen würde.
Zwei Aufrufer dürfen nicht denselben Schlüssel tragen; die Startprüfung weist eine solche Konfiguration ab. Die Zuordnung geschieht über den Schlüssel: Trügen zwei Aufrufer denselben, würde jede Anfrage dem zugerechnet, den die Konfiguration zuletzt nennt, und der andere wäre von außen nicht mehr erreichbar. Welcher das ist, hinge an der Reihenfolge der Einträge – das wäre kein Zuschnitt. Die Meldung nennt beide Aufrufer und nie den Schlüssel, auch nicht als Prüfsumme: Eine Startmeldung landet in einem Protokoll und oft danach in einem Vorgang.
Reichweite je Alias
Eine Regel darf aus mehreren Einträgen mit derselben Id bestehen, und jeder Eintrag nennt
seine eigenen Aliasse. Das ist für den häufigen Fall gedacht, dass eine Anwendung eine Datenbank nur
liest und in eine zweite schreiben muss:
"Clients": [
{ "Id": "fachanwendung", "Databases": [ "fachdaten" ],
"Resources": [ "views" ], "Verbs": [ "GET" ], "ReadOnly": true },
{ "Id": "fachanwendung", "Databases": [ "anmeldung" ],
"Resources": [ "views", "procedures" ], "Verbs": [ "GET", "POST" ], "ReadOnly": false }
]
Ohne diese Möglichkeit gälte die Reichweite eines Aufrufers für alle seine Aliasse gemeinsam. Eine Anwendung, die irgendwo schreiben muss, wäre damit überall schreibfähig, wo sie liest – und was das bedeutet, hängt davon ab, was in der anderen Datenbank steht. Den Katalog liest der Dienst aus der Datenbank, niemand pflegt ihn von Hand; erreichbar ist also alles, was dort existiert. In einer Datenbank mit vielen Prozeduren würde eine gemeinsame Reichweite sie alle aufrufbar machen.
Zwei Einträge mit derselben Id dürfen denselben Alias nicht nennen, und * steht nicht neben
einem zweiten Eintrag. Beides verhindert den Start mit einer Meldung, die die Id und den doppelten
Alias nennt. Sonst entschiede die Reihenfolge der Einträge, welche Reichweite gilt, und beide Einträge
sähen für sich genommen richtig aus. Weil so höchstens ein Eintrag einer Id auf eine Anfrage passen
kann, spielt die Reihenfolge keine Rolle. Verschiedene Regeln (verschiedene Id), etwa die Regeln
einer Person aus mehreren Windows-Gruppen, dürfen denselben Alias nennen; ihre Rechte addieren sich.
Ein Eintrag wird als Ganzes beurteilt. Den Alias aus dem einen und das Verb aus dem anderen zu
nehmen, würde zwei enge Erlaubnisse zu einer weiten addieren, die niemand aufgeschrieben hat. Im
Beispiel oben wird ein POST gegen fachdaten abgewiesen, obwohl derselbe Aufrufer POST gegen
anmeldung darf.
Ein einzelner Eintrag, der * neben einem konkreten Alias nennt, bleibt zulässig – innerhalb eines
Eintrags können sich die beiden nicht widersprechen.
Rechte je Objekt
Eine Regel kann die Objekte nennen, für die sie gilt (Objects), und einzelne davon ausnehmen
(ExceptObjects). Beide Listen haben die Form der Tabellenlisten eines Alias: *, schema.* oder
schema.name, die Namen so geschrieben, wie der Dienst sie führt (Sonderzeichen kodiert, siehe
Namen mit Sonderzeichen). Groß- und
Kleinschreibung zählt nicht.
"Clients": [
{ "Id": "lager-lesen", "Databases": [ "fachdaten" ],
"Resources": [ "views" ], "Objects": [ "dbo.viewLagerbestand" ],
"Verbs": [ "GET" ], "ReadOnly": true },
{ "Id": "lager-pflege", "Databases": [ "fachdaten" ],
"Resources": [ "tables" ], "Objects": [ "lager.*" ], "ExceptObjects": [ "lager.Preise" ],
"Verbs": [ "GET", "PATCH" ], "ReadOnly": false }
]
- Ohne Liste gilt die Regel für alle Objekte ihrer Arten. Die Arten unter
Resourcesgelten weiter: Ein Objekt unterObjectserreicht der Aufrufer nur, wenn seine Art erlaubt ist. - Ausnehmen gewinnt innerhalb der Regel. Zwischen den Regeln einer Person addieren sich die Rechte wie überall: Gewährt eine andere Regel das Objekt, bleibt es erreichbar.
- Eine Sicht braucht kein Recht auf ihre Tabellen. Geprüft wird nur das Objekt, das die Anfrage nennt. SQL Server liest die Tabellen hinter der Sicht über die Besitzkette, wie für jede Anmeldung, die nur die Sicht lesen darf. So geben Sie einen Teil einer Tabelle frei: Sicht anlegen, Sicht freigeben.
- Was ein Aufrufer nicht lesen darf, gibt es für ihn nicht. Dienstdokument,
$metadataund die Kataloglisten des Treibers zeigen nur erlaubte Objekte; eine Anfrage an ein anderes Objekt beantwortet der Dienst mit404wie bei einem Objekt, das es nicht gibt. Ein lesbares Objekt, das der Aufrufer so nicht ändern darf, beantwortet er mit403. - Nicht neben
sql. Eine eigene Anweisung erreicht alles, was die Anmeldung erreicht, unter der sie läuft – die des Alias oder, bei einer SQL-Anmeldung und unterImpersonate, die eigene der Person. Der Dienst liest den Text nicht und kann dort keine Objektliste durchsetzen; eine Regel mitsqlund einer Objektliste verhindert deshalb den Start bzw. das Speichern. Dasselbe gilt für Aufrufer, deren Anweisungen unter ihrer eigenen Anmeldung laufen (siehe Durchreichepfad): Dort begrenzt die Objektliste eine eigene Anweisung nicht. Geprüfte Anweisungen ohnesqlprüft der Dienst dagegen Objekt für Objekt gegen die Objektliste.
Zeilenweise Einschränkung
Die Regeln des Dienstes enden bei Alias, Ressourcenart, Objekt, Verb und Nur-Lese-Kennzeichen. Eine Regel je Zeile kennt der Dienst nicht, und er bekommt auch keine: Ob eine Person eine bestimmte Zeile sehen oder ändern darf, beantwortet die Datenbank – mit einer Sicht, die filtert, und mit Prozeduren, die prüfen. Zwei Berechtigungssysteme, die sich überschneiden, wären am Ende beide falsch.
Voraussetzung: Die Anweisung läuft als Person. Eine Sicht kann nur nach der Person filtern, wenn SQL Server die Person kennt. Das ist der Fall
- an einem Alias mit
Persons: Impersonate, für Aufrufer mit eigener Anmeldung in SQL Server (Windows-Konto oder eine bei der Person eingetragene SQL-Anmeldung): Der Dienst wechselt mitEXECUTE AS LOGIN.SUSER_SNAME()undUSER_NAME()nennen dann die Person,ORIGINAL_LOGIN()den Dienst;SUSER_SID()gibt die SID der Person zurück, in der Anweisung ebenso wie in Spaltenvorgaben und Triggern; siehe So geben Sie Personen an SQL Server weiter; - bei der Anmeldung mit einer SQL-Anmeldung per HTTP Basic: Die Anweisung läuft auf einer eigenen Verbindung mit dieser Anmeldung.
Die Falle ist die Voreinstellung. An einem Alias mit
Persons: Service– der Vorgabe – laufen alle Anweisungen unter der Anmeldung des Alias.SUSER_SNAME()undSUSER_SID()nennen dann das Konto des Dienstes, für jeden Aufrufer gleich. Eine Sicht, die darauf filtert, meldet keinen Fehler: Sie liefert je nach Filter nichts oder alles. Dasselbe gilt für Aufrufer mit einem Dienstschlüssel: Er wechselt nie die Identität, auch an einem Alias mitImpersonatenicht.
Was in welchem Fall ankommt:
| Aufrufer | Persons: Service (Vorgabe) | Persons: Impersonate |
|---|---|---|
| Windows-Konto mit eigener Anmeldung in SQL Server | Anmeldung des Alias, SESSION_CONTEXT leer | die eigene Anmeldung |
| Windows-Konto ohne eigene Anmeldung | Anmeldung des Alias, SESSION_CONTEXT leer | abgewiesen, 403 |
| Person mit eingetragener SQL-Anmeldung (persönlicher Schlüssel) | Anmeldung des Alias; Person in SESSION_CONTEXT | diese SQL-Anmeldung |
| Person ohne eigene Anmeldung (persönlicher Schlüssel) | Anmeldung des Alias; Person in SESSION_CONTEXT | Anmeldung des Alias; Person in SESSION_CONTEXT |
| SQL-Anmeldung per HTTP Basic | die eigene Anmeldung | die eigene Anmeldung |
| Dienstschlüssel | Anmeldung des Alias, ohne Person | Anmeldung des Alias, ohne Person |
| Identität aus der Verwaltung gewählt (Sammelanmeldung) | die Sammelanmeldung; Person in SESSION_CONTEXT | die Sammelanmeldung; Person in SESSION_CONTEXT |
SESSION_CONTEXT setzt der Dienst für Aufrufer mit persönlichem Schlüssel und für eine gewählte
Datenbank-Identität, an jedem Alias und vor jedem Wechsel, nur lesend: wkl.person (Name der Person),
wkl.key (Kennung des persönlichen Schlüssels oder NULL) und wkl.role (gewählte Identität oder
NULL). Der Verbindungspool setzt die Werte zurück, bevor die Verbindung an die nächste Anfrage geht.
Beispiel 1: Filter auf die Anmeldung der Person. Für einen Alias mit Persons: Impersonate.
Verglichen wird über SUSER_SID(), nicht über den Namen: Ein umbenanntes Windows-Konto behält in
SQL Server seinen alten Anmeldenamen, die SID bleibt (siehe
„Der Dienst kann diese Anmeldung in SQL Server nicht annehmen“ nach Umbenennen eines Kontos).
CREATE VIEW maske.auftrag_liste AS SELECT a.auftrag_id, a.betreff, a.bereich_id FROM dbo.auftrag AS a WHERE EXISTS (SELECT 1 FROM iam.konto_bereich AS kb WHERE kb.bereich_id = a.bereich_id AND kb.login_sid = SUSER_SID());
Beispiel 2: Filter auf die Person aus SESSION_CONTEXT. Für Aufrufer ohne eigene Anmeldung
(persönlicher Schlüssel an einem Alias mit Persons: Service). Der Wert ist der Name der Person in
der Verwaltung; eine Umbenennung dort ändert ihn.
CREATE VIEW maske.auftrag_liste_schluessel AS SELECT a.auftrag_id, a.betreff, a.bereich_id FROM dbo.auftrag AS a WHERE EXISTS (SELECT 1 FROM iam.konto_bereich AS kb WHERE kb.bereich_id = a.bereich_id AND kb.person_name = CAST(SESSION_CONTEXT(N'wkl.person') AS nvarchar(256)));
Daraus folgt eine Entscheidung: Entweder Sie verbinden beide Bedingungen in einer Sicht
(… = SUSER_SID() OR … = SESSION_CONTEXT(N'wkl.person')) und nehmen hin, dass der Dienst den Namen der
Person verbürgt, oder Sie stellen den Alias auf Persons: Impersonate, geben jeder Person eine
eigene Anmeldung und verwenden nur Beispiel 1. Dann weist der Dienst ein Windows-Konto ohne eigene
Anmeldung mit 403 ab. Ein persönlicher Schlüssel ohne eingetragene SQL-Anmeldung läuft dagegen auch
dort unter der Anmeldung des Alias – für ihn liefert SUSER_SID() das Konto des Dienstes, und ein
Filter nach Beispiel 1 zeigt ihm nichts oder alles. Tragen Sie bei solchen Aliassen jeder Person mit
Schlüssel eine SQL-Anmeldung ein, oder verbinden Sie beide Bedingungen.
Welche Wege die Identität wechseln. Alle sechs Datenwege öffnen ihre Verbindung über dieselbe
Sitzung: Lesen (auch $apply), Einzelsatz, Zählen, Prozeduraufruf, Schreiben in Tabellen und die
Durchreiche.
Der Katalog nicht. $metadata, Spalten, Schlüssel und die Liste der Objekte liest der Dienst unter
der Anmeldung des Alias, und welche Objekte ein Aufrufer sieht, entscheiden die Regeln des Dienstes.
Das hat zwei Folgen:
- Eine Sicht, die Zeilen filtert, zeigt in
$metadatatrotzdem alle ihre Spalten. - Den Schlüssel einer Sicht (aus den Browse-Metadaten von SQL Server) ermittelt der Dienst unter der Anmeldung des Alias, nicht unter der der Person.
Verwandte Themen
- „So legen Sie eine Regel an“ (Dokumentation der Verwaltungsanwendung)