Security model and trust boundaries of the data service
graph TD
C["Client (Access through the driver, Excel, custom program)"] -->|"HTTPS: sign-in, request"| P["Reverse proxy (optional: IIS or another)"]
P -->|"only from TrustedProxies: X-Forwarded-For, -Proto"| G["Data service: sign-in, policy, rules per object and method"]
C -->|"HTTPS, direct"| G
G -->|"reads; changes only through administration"| S[("Administration store (file, sealed secrets)")]
K["Master key (environment or file, kept separately)"] -->|"unseals"| G
G -->|"SQL under the alias's login, the person's login, or a shared login"| D[("SQL Server")]Figure: Trust boundaries run between the client and the service (the network), between a proxy and the service (whose client address counts), between the service and the administration store (file and key kept apart), and between the service and the database (which login runs the SQL).
For applications, the data service is the only path to the database. It decides who is calling, what that caller can reach, and which login SQL Server uses to run the statement. This page summarizes what needs protecting, which measure protects it at which boundary, what the operator has to provide, and which risks remain. The linked pages cover the details; this page shows how they fit together.
Key features
- Two questions, answered separately: who is calling (sign-in) and whose identity the statement runs under (pass-through per alias); see Sign-in and identity pass-through.
- What a caller can't read doesn't exist for that caller: rules per alias, object, and method; hidden objects respond the same way as unknown ones; see Rights: rules and scope.
- SQL is built from names that the service looked up in its catalog and from bound values, never from caller-supplied text—with two explicit exceptions (below).
- Secrets in the administration store are sealed or kept only as hashes, and the master key is stored separately; see Administration store and master key.
Core concepts
Assets
| Asset | Where it lives | Protection |
|---|---|---|
| Business data in SQL Server | the database | the service's rules, plus the permissions of the login that SQL Server runs under |
| Connection strings of the data sources (the alias's login) | administration store | sealed with the master key; the administration API never returns them |
| Master key | environment variable or file (env:, file:) | never stored in the store file; anyone who has it can unseal the file |
| Personal keys | with the key holder | the store keeps only the SHA-256 hash, an ID, and the last four characters |
| Service keys | configuration | as a reference (env:, file:) or, explicitly, in plain text (plain:) |
| Second-factor secrets | administration store | sealed |
| Second-factor sessions | with the client; in the store only as a hash | expire; valid only together with their first factor |
| Log, audit, change log | service log, store | contain no keys, passwords, connection strings, or values |
| License key of the geolocation database | administration store | sealed; the administration API never returns it |
| Sign-in log (address, approximate location, and person per sign-in) | administration store | individual events only with the sign-in-events right; limited retention (default 90 days, hourly counts without person 400 days); coordinates rounded to about 10 km; locating happens on the server, no address leaves it. See Check sign-in patterns |
| Load log (shapes of requests without values; requests per day and person) | administration store | callers' values are never recorded; figures per person and the person of slow requests only with the load-persons right, retention 7 days by default; the file for the manufacturer (export-load) contains no persons, addresses, or values. See Investigate load |
Trust boundaries and measures
| Boundary | What the service enforces | What the operator has to provide |
|---|---|---|
| Client → service | Sign-in on every request; a sign-in policy that requires a second factor by method, scope, and network; a limit on failed attempts (429). Administration, self-service, the second-factor exchange, and SQL Server sign-in require a protected connection (HTTPS, loopback, or a trusted proxy that sends X-Forwarded-Proto: https). State-changing requests that a browser sends on behalf of another website (Sec-Fetch-Site, otherwise Origin) are refused with 403 | HTTPS with a certificate the clients trust. Bind unencrypted HTTP to loopback only (the installation package's default: HTTP on port 8434, bound to 127.0.0.1) |
| Proxy → service | Client address, scheme, and host from X-Forwarded-For, -Proto, and -Host are accepted only from proxies listed in TrustedProxies, evaluated from the nearest hop; otherwise the connecting peer counts | If rules distinguish by network, make the service reachable only through the listed proxies |
| Service → database | Names only after a catalog lookup, with ordinal comparison and brackets with ] doubled; values as parameters. Pass-through of the person with EXECUTE AS LOGIN, followed by a revert; the DenyImpersonate block list. SQL Server messages without hidden names or values | Grant the alias's login only the permissions that the released objects need. That login is the upper limit for everything that runs under Service |
| Service → administration store | Changes only through the administration API (admin right; the default rule requires a second factor); every change recorded in the change log; validation before a change takes effect | Store file accessible only to the service account and administrators (the default); back up the master key separately; one instance per store |
The three ways caller-supplied text reaches the database
- Custom statements with the
sqlright. The service runs the text as is and doesn't evaluate it. The only limit is the login it runs under—underService, the alias's login. A caller withsqlcan therefore reach everything that login can reach, including objects outside the caller's rules. This right is meant for trusted programs. - Checked statements without
sql. The service parses the text, allows only a closed list of statement forms, checks every object against the catalog and the rules per method, and runs a newly generated version; see Aliases, the catalog, and the central rule. Security here depends on how complete that check is; the permissions of the login still limit it as well. - Unchecked statements under the caller's own login, without
sql. If the request runs under a login other than the alias's—a SQL Server login through HTTP Basic, impersonation of the person (Persons: Impersonate), or a database identity of kindLoginorOwn—the service runs the text as is, provided the alias accepts custom statements (AllowPassThrough) and a rule of the caller that isn't read-only names the alias. The limit is that login's permissions in SQL Server, not the rule's object lists; see The one exception.
Residual risks
| Residual risk | Condition | Mitigation |
|---|---|---|
| Keys over unencrypted HTTP. The service also accepts service keys and personal keys over an unprotected connection; only administration, self-service, the second factor, and SQL Server sign-in require a protected one | HTTP is reachable beyond loopback | Bind HTTP to 127.0.0.1 only (the installation package's default); the OData ODBC driver sends a personal key only over https or locally anyway |
| Unchecked statements bypass the per-object rules | a caller with sql, or a caller with write access under their own login on an alias with AllowPassThrough | Grant sql only to trusted programs; give the alias's login and the people's logins only the permissions they need; set AllowPassThrough only where unchecked statements are required; use checked statements instead |
| A gap in the list of checked statement forms | a construct that the check misses | Execution stays limited by the login's permissions; the list is closed, and anything unknown is refused |
| The change log isn't tamper-proof | write access to the store file | File permissions; tamper-proof evidence belongs in a system outside the operator's control |
Failed-attempt counters, request limits, and stored responses for Idempotency-Key are kept in memory | restarting the service resets them | none; after a restart, every limit starts over |
Row filters based on SESSION_CONTEXT are vouched for only by the service | statements run under the alias's login; anyone with the same login could set the value themselves | a separate login per person and Persons: Impersonate; see Row-level restriction |
A SQL Server sign-in from a refused origin reveals whether a password is correct (401 wrong, 403 right) | the sign-in policy refuses SQL Server sign-ins from outside | The failed-attempt limit (five per login and alias per minute); better not to expose SQL Server sign-in to the outside at all |
The second-factor exchange and enrollment are evaluated only against rules with scope All | a refusal only for Data or Admin | Create network-based refusals with scope All |
| A restored store reopens access that was blocked after the backup was made | restoring an older backup | Repeat the blocks afterward; see Back up, restore, and move the administration store |
Without X-Forwarded-For, every request counts as coming from the proxy | the proxy doesn't send the header | After setup, check the audit log; see Run the service behind IIS or a proxy |
A stored response for an Idempotency-Key is replayed without a new permission check | a retry within ten minutes of the first response, even after a block | Generate the Idempotency-Key as a random value; see HTTP: native API (reference) |
This page describes the protective measures of the service. It doesn't replace a security assessment of the overall system the service runs in.