@@ -3182,40 +3182,43 @@ REVOKE CREATE ON SCHEMA public FROM PUBLIC;
31823182 query that database would take protective action at the beginning of each
31833183 session. Specifically, they would begin each session by
31843184 setting <varname>search_path</varname> to the empty string or otherwise
3185- removingnon-superuser- writableschemas
3185+ removingschemas that are writableby non-superusers
31863186 from <varname>search_path</varname>. There are a few usage patterns
31873187 easily supported by the default configuration:
31883188 <itemizedlist>
31893189 <listitem>
3190- <!-- "DROP SCHEMA public" is inferior to this REVOKE, because pg_dump
3191- doesn't preserve that DROP.
3192-
3193- A database owner can attack the database's users via "CREATE SCHEMA
3190+ <para>
3191+ Constrain ordinary users to user-private schemas.
3192+ To implement this pattern, first ensure that no schemas have
3193+ public <literal>CREATE</literal> privileges. Then, for every user
3194+ needing to create non-temporary objects, create a schema with the
3195+ same name as that user, for example
3196+ <literal>CREATE SCHEMA alice AUTHORIZATION alice</literal>.
3197+ (Recall that the default search path starts
3198+ with <literal>$user</literal>, which resolves to the user
3199+ name. Therefore, if each user has a separate schema, they access
3200+ their own schemas by default.) This pattern is a secure schema
3201+ usage pattern unless an untrusted user is the database owner or
3202+ holds the <literal>CREATEROLE</literal> privilege, in which case no
3203+ secure schema usage pattern exists.
3204+ </para>
3205+ <!-- A database owner can attack the database's users via "CREATE SCHEMA
31943206 trojan; ALTER DATABASE $mydb SET search_path = trojan, public;". A
31953207 CREATEROLE user can issue "GRANT $dbowner TO $me" and then use the
31963208 database owner attack. -->
3209+
31973210 <para>
3198- Constrain ordinary users to user-private schemas. To implement this,
3199- first issue <literal>REVOKE CREATE ON SCHEMA public FROM
3200- PUBLIC</literal>. Then, for every user needing to create non-temporary
3201- objects, create a schema with the same name as that user. Recall that
3202- the default search path starts with <literal>$user</literal>, which
3203- resolves to the user name. Therefore, if each user has a separate
3204- schema, they access their own schemas by default. After adopting this
3205- pattern in a database where untrusted users had already logged in,
3206- consider auditing the public schema for objects named like objects in
3207- schema <literal>pg_catalog</literal>. This pattern is a secure schema
3208- usage pattern unless an untrusted user is the database owner or holds
3209- the <literal>CREATEROLE</literal> privilege, in which case no secure
3210- schema usage pattern exists.
3211- </para>
3212- <para>
3213- If the database originated in an upgrade
3214- from <productname>PostgreSQL</productname> 14 or earlier,
3215- the <literal>REVOKE</literal> is essential. Otherwise, the default
3216- configuration follows this pattern; ordinary users can create only
3217- temporary objects until a privileged user furnishes a schema.
3211+ In <productname>PostgreSQL</productname> 15 and later, the default
3212+ configuration supports this usage pattern. In prior versions, or
3213+ when using a database that has been upgraded from a prior version,
3214+ you will need to remove the public <literal>CREATE</literal>
3215+ privilege from the <literal>public</literal> schema (issue
3216+ <literal>REVOKE CREATE ON SCHEMA public FROM PUBLIC</literal>).
3217+ Then consider auditing the <literal>public</literal> schema for
3218+ objects named like objects in schema <literal>pg_catalog</literal>.
32183219 </para>
3220+ <!-- "DROP SCHEMA public" is inferior to this REVOKE, because pg_dump
3221+ doesn't preserve that DROP. -->
32193222 </listitem>
32203223
32213224 <listitem>