@@ -3211,40 +3211,43 @@ REVOKE CREATE ON SCHEMA public FROM PUBLIC;
32113211 query that database would take protective action at the beginning of each
32123212 session. Specifically, they would begin each session by
32133213 setting <varname>search_path</varname> to the empty string or otherwise
3214- removing non-superuser- writable schemas
3214+ removing schemas that are writable by non-superusers
32153215 from <varname>search_path</varname>. There are a few usage patterns
32163216 easily supported by the default configuration:
32173217 <itemizedlist>
32183218 <listitem>
3219- <!-- "DROP SCHEMA public" is inferior to this REVOKE, because pg_dump
3220- doesn't preserve that DROP.
3221-
3222- A database owner can attack the database's users via "CREATE SCHEMA
3219+ <para>
3220+ Constrain ordinary users to user-private schemas.
3221+ To implement this pattern, first ensure that no schemas have
3222+ public <literal>CREATE</literal> privileges. Then, for every user
3223+ needing to create non-temporary objects, create a schema with the
3224+ same name as that user, for example
3225+ <literal>CREATE SCHEMA alice AUTHORIZATION alice</literal>.
3226+ (Recall that the default search path starts
3227+ with <literal>$user</literal>, which resolves to the user
3228+ name. Therefore, if each user has a separate schema, they access
3229+ their own schemas by default.) This pattern is a secure schema
3230+ usage pattern unless an untrusted user is the database owner or
3231+ holds the <literal>CREATEROLE</literal> privilege, in which case no
3232+ secure schema usage pattern exists.
3233+ </para>
3234+ <!-- A database owner can attack the database's users via "CREATE SCHEMA
32233235 trojan; ALTER DATABASE $mydb SET search_path = trojan, public;". A
32243236 CREATEROLE user can issue "GRANT $dbowner TO $me" and then use the
32253237 database owner attack. -->
3238+
32263239 <para>
3227- Constrain ordinary users to user-private schemas. To implement this,
3228- first issue <literal>REVOKE CREATE ON SCHEMA public FROM
3229- PUBLIC</literal>. Then, for every user needing to create non-temporary
3230- objects, create a schema with the same name as that user. Recall that
3231- the default search path starts with <literal>$user</literal>, which
3232- resolves to the user name. Therefore, if each user has a separate
3233- schema, they access their own schemas by default. After adopting this
3234- pattern in a database where untrusted users had already logged in,
3235- consider auditing the public schema for objects named like objects in
3236- schema <literal>pg_catalog</literal>. This pattern is a secure schema
3237- usage pattern unless an untrusted user is the database owner or holds
3238- the <literal>CREATEROLE</literal> privilege, in which case no secure
3239- schema usage pattern exists.
3240- </para>
3241- <para>
3242- If the database originated in an upgrade
3243- from <productname>PostgreSQL</productname> 14 or earlier,
3244- the <literal>REVOKE</literal> is essential. Otherwise, the default
3245- configuration follows this pattern; ordinary users can create only
3246- temporary objects until a privileged user furnishes a schema.
3240+ In <productname>PostgreSQL</productname> 15 and later, the default
3241+ configuration supports this usage pattern. In prior versions, or
3242+ when using a database that has been upgraded from a prior version,
3243+ you will need to remove the public <literal>CREATE</literal>
3244+ privilege from the <literal>public</literal> schema (issue
3245+ <literal>REVOKE CREATE ON SCHEMA public FROM PUBLIC</literal>).
3246+ Then consider auditing the <literal>public</literal> schema for
3247+ objects named like objects in schema <literal>pg_catalog</literal>.
32473248 </para>
3249+ <!-- "DROP SCHEMA public" is inferior to this REVOKE, because pg_dump
3250+ doesn't preserve that DROP. -->
32483251 </listitem>
32493252
32503253 <listitem>
0 commit comments