Skip to content

Commit 08395e5

Browse files
committed
Document search_path security with untrusted dbowner or CREATEROLE.
Commit 5770172 wrote, incorrectly, that certain schema usage patterns are secure against CREATEROLE users and database owners. When an untrusted user is the database owner or holds CREATEROLE privilege, a query is secure only if its session started with SELECT pg_catalog.set_config('search_path', '', false) or equivalent. Back-patch to 9.4 (all supported versions). Discussion: https://postgr.es/m/20191013013512.GC4131753@rfd.leadboat.com
1 parent 44381b1 commit 08395e5

File tree

1 file changed

+40
-40
lines changed

1 file changed

+40
-40
lines changed

doc/src/sgml/ddl.sgml

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1907,67 +1907,67 @@ REVOKE CREATE ON SCHEMA public FROM PUBLIC;
19071907
<title>Usage Patterns</title>
19081908

19091909
<para>
1910-
Schemas can be used to organize your data in many ways. There are a few
1911-
usage patterns easily supported by the default configuration, only one of
1912-
which suffices when database users mistrust other database users:
1910+
Schemas can be used to organize your data in many ways.
1911+
A <firstterm>secure schema usage pattern</firstterm> prevents untrusted
1912+
users from changing the behavior of other users' queries. When a database
1913+
does not use a secure schema usage pattern, users wishing to securely
1914+
query that database would take protective action at the beginning of each
1915+
session. Specifically, they would begin each session by
1916+
setting <varname>search_path</varname> to the empty string or otherwise
1917+
removing non-superuser-writable schemas
1918+
from <varname>search_path</varname>. There are a few usage patterns
1919+
easily supported by the default configuration:
19131920
<itemizedlist>
19141921
<listitem>
19151922
<!-- "DROP SCHEMA public" is inferior to this REVOKE, because pg_dump
1916-
doesn't preserve that DROP. -->
1923+
doesn't preserve that DROP.
1924+
1925+
A database owner can attack the database's users via "CREATE SCHEMA
1926+
trojan; ALTER DATABASE $mydb SET search_path = trojan, public;". A
1927+
CREATEROLE user can issue "GRANT $dbowner TO $me" and then use the
1928+
database owner attack. -->
19171929
<para>
19181930
Constrain ordinary users to user-private schemas. To implement this,
19191931
issue <literal>REVOKE CREATE ON SCHEMA public FROM PUBLIC</literal>,
1920-
and create a schema for each user with the same name as that user. If
1921-
affected users had logged in before this, consider auditing the public
1932+
and create a schema for each user with the same name as that user.
1933+
Recall that the default search path starts
1934+
with <literal>$user</literal>, which resolves to the user name.
1935+
Therefore, if each user has a separate schema, they access their own
1936+
schemas by default. After adopting this pattern in a database where
1937+
untrusted users had already logged in, consider auditing the public
19221938
schema for objects named like objects in
1923-
schema <literal>pg_catalog</literal>. Recall that the default search
1924-
path starts with <literal>$user</literal>, which resolves to the user
1925-
name. Therefore, if each user has a separate schema, they access their
1926-
own schemas by default.
1939+
schema <literal>pg_catalog</literal>. This pattern is a secure schema
1940+
usage pattern unless an untrusted user is the database owner or holds
1941+
the <literal>CREATEROLE</literal> privilege, in which case no secure
1942+
schema usage pattern exists.
19271943
</para>
1928-
</listitem>
1929-
1930-
<listitem>
19311944
<para>
1932-
Remove the public schema from each user's default search path
1933-
using <literal>ALTER ROLE <replaceable>user</replaceable> SET
1934-
search_path = "$user"</literal>. Everyone retains the ability to
1935-
create objects in the public schema, but only qualified names will
1936-
choose those objects. While qualified table references are fine, calls
1937-
to functions in the public schema <link linkend="typeconv-func">will be
1938-
unsafe or unreliable</link>. Also, a user holding
1939-
the <literal>CREATEROLE</literal> privilege can undo this setting and
1940-
issue arbitrary queries under the identity of users relying on the
1941-
setting. If you create functions or extensions in the public schema or
1942-
grant <literal>CREATEROLE</literal> to users not warranting this
1943-
almost-superuser ability, use the first pattern instead.
19441945
</para>
19451946
</listitem>
19461947

19471948
<listitem>
19481949
<para>
1949-
Remove the public schema from <varname>search_path</varname> in
1950-
<link linkend="config-setting-configuration-file"><filename>postgresql.conf</filename></link>.
1951-
The ensuing user experience matches the previous pattern. In addition
1952-
to that pattern's implications for functions
1953-
and <literal>CREATEROLE</literal>, this trusts database owners
1954-
like <literal>CREATEROLE</literal>. If you create functions or
1955-
extensions in the public schema or assign
1956-
the <literal>CREATEROLE</literal>
1957-
privilege, <literal>CREATEDB</literal> privilege or individual database
1958-
ownership to users not warranting almost-superuser access, use the
1959-
first pattern instead.
1950+
Remove the public schema from the default search path, by modifying
1951+
<link linkend="config-setting-configuration-file"><filename>postgresql.conf</filename></link>
1952+
or by issuing <literal>ALTER ROLE ALL SET search_path =
1953+
"$user"</literal>. Everyone retains the ability to create objects in
1954+
the public schema, but only qualified names will choose those objects.
1955+
While qualified table references are fine, calls to functions in the
1956+
public schema <link linkend="typeconv-func">will be unsafe or
1957+
unreliable</link>. If you create functions or extensions in the public
1958+
schema, use the first pattern instead. Otherwise, like the first
1959+
pattern, this is secure unless an untrusted user is the database owner
1960+
or holds the <literal>CREATEROLE</literal> privilege.
19601961
</para>
19611962
</listitem>
19621963

19631964
<listitem>
19641965
<para>
19651966
Keep the default. All users access the public schema implicitly. This
19661967
simulates the situation where schemas are not available at all, giving
1967-
a smooth transition from the non-schema-aware world. However, any user
1968-
can issue arbitrary queries under the identity of any user not electing
1969-
to protect itself individually. This pattern is acceptable only when
1970-
the database has a single user or a few mutually-trusting users.
1968+
a smooth transition from the non-schema-aware world. However, this is
1969+
never a secure pattern. It is acceptable only when the database has a
1970+
single user or a few mutually-trusting users.
19711971
</para>
19721972
</listitem>
19731973
</itemizedlist>

0 commit comments

Comments
 (0)