Do some copy-editing on the docs for row-level security.

Clarifications, markup improvements, corrections of misleading or
outright wrong statements.
This commit is contained in:
Tom Lane 2016-01-03 20:04:11 -05:00
parent 939d10cd87
commit c1611db01f
4 changed files with 234 additions and 193 deletions

View File

@ -1512,7 +1512,7 @@ REVOKE ALL ON accounts FROM PUBLIC;
<title>Row Security Policies</title> <title>Row Security Policies</title>
<indexterm zone="ddl-rowsecurity"> <indexterm zone="ddl-rowsecurity">
<primary>row security</primary> <primary>row-level security</primary>
</indexterm> </indexterm>
<indexterm zone="ddl-rowsecurity"> <indexterm zone="ddl-rowsecurity">
@ -1520,54 +1520,68 @@ REVOKE ALL ON accounts FROM PUBLIC;
</indexterm> </indexterm>
<para> <para>
In addition to the <xref linkend="ddl-priv"> system available through In addition to the SQL-standard <link linkend="ddl-priv">privilege
<xref linkend="sql-grant">, tables can have row security policies system</link> available through <xref linkend="sql-grant">,
which limit the rows returned for normal queries and rows which can tables can have <firstterm>row security policies</> that restrict,
be added through data modification commands. By default, tables do on a per-user basis, which rows can be returned by normal queries
not have any policies and all rows are visible and able to be added, or inserted, updated, or deleted by data modification commands.
subject to the regular <xref linkend="ddl-priv"> system. This is This feature is also known as <firstterm>Row-Level Security</>.
also known as Row Level Security. By default, tables do not have any policies, so that if a user has
access privileges to a table according to the SQL privilege system,
all rows within it are equally available for querying or updating.
</para> </para>
<para> <para>
When row security is enabled on a table with When row security is enabled on a table (with
<xref linkend="sql-altertable">, all normal access to the table <link linkend="sql-altertable">ALTER TABLE ... ENABLE ROW LEVEL
(excluding the owner) for selecting rows or adding rows must be through SECURITY</>), all normal access to the table for selecting rows or
a policy. If no policy exists for the table, a default-deny policy is modifying rows must be allowed by a row security policy. (However, the
used and no rows are visible or can be added. Privileges which operate table's owner is typically not subject to row security policies.) If no
at the whole table level such as <literal>TRUNCATE</>, and policy exists for the table, a default-deny policy is used, meaning that
<literal>REFERENCES</> are not subject to row security. no rows are visible or can be modified. Operations that apply to the
whole table, such as <command>TRUNCATE</> and <literal>REFERENCES</>,
are not subject to row security.
</para> </para>
<para> <para>
Row security policies can be specific to commands, or to roles, or to Row security policies can be specific to commands, or to roles, or to
both. The commands available are <literal>ALL</literal>, both. A policy can be specified to apply to <literal>ALL</literal>
<literal>SELECT</>, <literal>INSERT</>, <literal>UPDATE</>, and commands, or to <literal>SELECT</>, <literal>INSERT</>, <literal>UPDATE</>,
<literal>DELETE</>. Multiple roles can be assigned to a given policy and or <literal>DELETE</>. Multiple roles can be assigned to a given
normal role membership and inheritance rules apply. Table owners, policy, and normal role membership and inheritance rules apply.
superusers, and roles with the <literal>BYPASSRLS</> attribute bypass the
row security system when querying a table. Applications that expect to
bypass all row security through those mechanisms should
set <xref linkend="guc-row-security"> to <literal>off</>.
</para> </para>
<para> <para>
To specify which rows are visible and what rows can be added to the To specify which rows are visible or modifiable according to a policy,
table with row level security, an expression is required which returns an expression is required that returns a Boolean result. This
a Boolean result. This expression will be evaluated for each row prior expression will be evaluated for each row prior to any conditions or
to other conditionals or functions which are part of the query. The functions coming from the user's query. (The only exceptions to this
one exception to this rule are <literal>leakproof</literal> functions, rule are <literal>leakproof</literal> functions, which are guaranteed to
which are guaranteed to not leak information. Two expressions may be not leak information; the optimizer may choose to apply such functions
specified to provide independent control over the rows which are ahead of the row-security check.) Rows for which the expression does
visible and the rows which are allowed to be added. The expression not return <literal>true</> will not be processed. Separate expressions
is run as part of the query and with the privileges of the user may be specified to provide independent control over the rows which are
running the query, however, security definer functions can be used in visible and the rows which are allowed to be modified. Policy
the expression. expressions are run as part of the query and with the privileges of the
user running the query, although security-definer functions can be used
to access data not available to the calling user.
</para>
<para>
Superusers and roles with the <literal>BYPASSRLS</> attribute always
bypass the row security system when accessing a table. Table owners
normally bypass row security as well, though a table owner can choose to
be subject to row security with <link linkend="sql-altertable">ALTER
TABLE ... FORCE ROW LEVEL SECURITY</>. Even in a table with that option
selected, the table owner will bypass row security if the
<xref linkend="guc-row-security"> configuration parameter is set
to <literal>off</>; this setting is typically used for purposes such as
backup and restore.
</para> </para>
<para> <para>
Enabling and disabling row security, as well as adding policies to a Enabling and disabling row security, as well as adding policies to a
table, is always the privilege of the owner only. table, is always the privilege of the table owner only.
</para> </para>
<para> <para>
@ -1587,46 +1601,40 @@ REVOKE ALL ON accounts FROM PUBLIC;
<para> <para>
When multiple policies apply to a given query, they are combined using When multiple policies apply to a given query, they are combined using
<literal>OR</literal>, similar to how a given role has the privileges <literal>OR</literal>, so that a row is accessible if any policy allows
of all roles which they are a member of. it. This is similar to the rule that a given role has the privileges
of all roles that they are a member of.
</para> </para>
<para> <para>
Referential integrity checks, such as unique or primary key constraints Referential integrity checks, such as unique or primary key constraints
and foreign key references, will bypass row security to ensure that and foreign key references, always bypass row security to ensure that
data integrity is maintained. Care must be taken when developing data integrity is maintained. Care must be taken when developing
schemas and row level policies to avoid a "covert channel" leak of schemas and row level policies to avoid <quote>covert channel</> leaks of
information through these referential integrity checks. information through such referential integrity checks.
</para> </para>
<para> <para>
To enable row security for a table, As a simple example, here is how to create a policy on
the <command>ALTER TABLE</command> is used. For example, to enable the <literal>account</> relation to allow only members of
row level security for the table accounts, use: the <literal>managers</> role to access rows, and only rows of their
accounts:
</para> </para>
<programlisting> <programlisting>
-- Create the table first
CREATE TABLE accounts (manager text, company text, contact_email text); CREATE TABLE accounts (manager text, company text, contact_email text);
ALTER TABLE accounts ENABLE ROW LEVEL SECURITY; ALTER TABLE accounts ENABLE ROW LEVEL SECURITY;
</programlisting>
<para>
To create a policy on the account relation to allow the managers role
to view the rows of their accounts, the <command>CREATE POLICY</command>
command can be used:
</para>
<programlisting>
CREATE POLICY account_managers ON accounts TO managers CREATE POLICY account_managers ON accounts TO managers
USING (manager = current_user); USING (manager = current_user);
</programlisting> </programlisting>
<para> <para>
If no role is specified, or the special <quote>user</quote> name If no role is specified, or the special user name
<literal>PUBLIC</literal> is used, then the policy applies to all <literal>PUBLIC</literal> is used, then the policy applies to all
users on the system. To allow all users to view their own row in users on the system. To allow all users to access their own row in
a user table, a simple policy can be used: a <literal>users</> table, a simple policy can be used:
</para> </para>
<programlisting> <programlisting>
@ -1635,10 +1643,10 @@ CREATE POLICY user_policy ON users
</programlisting> </programlisting>
<para> <para>
To use a different policy for rows which are being added to the To use a different policy for rows that are being added to the table
table from those rows which are visible, the WITH CHECK clause compared to those rows that are visible, the <literal>WITH CHECK</>
can be used. This would allow all users to view all rows in the clause can be used. This policy would allow all users to view all rows
users table, but only modify their own: in the <literal>users</> table, but only modify their own:
</para> </para>
<programlisting> <programlisting>
@ -1648,16 +1656,17 @@ CREATE POLICY user_policy ON users
</programlisting> </programlisting>
<para> <para>
Row security can be disabled with the <command>ALTER TABLE</command> Row security can also be disabled with the <command>ALTER TABLE</>
also. Note that disabling row security does not remove the command. Disabling row security does not remove any policies that are
policies which are defined on the table, they are simply ignored defined on the table; they are simply ignored. Then all rows in the
and all rows are visible and able to be added, subject to the table are visible and modifiable, subject to the standard SQL privileges
normal privileges system. system.
</para> </para>
<para> <para>
Below is a larger example of how this feature can be used in Below is a larger example of how this feature can be used in production
production environments, based on a Unix password file. environments. The table <literal>passwd</> emulates a Unix password
file:
</para> </para>
<programlisting> <programlisting>
@ -1748,7 +1757,7 @@ postgres=&gt; select username,real_name,home_phone,extra_info,home_dir,shell fro
postgres=&gt; update passwd set username = 'joe'; postgres=&gt; update passwd set username = 'joe';
ERROR: permission denied for relation passwd ERROR: permission denied for relation passwd
-- Allowed to change her own real_name, but no others -- Alice is allowed to change her own real_name, but no others
postgres=&gt; update passwd set real_name = 'Alice Doe'; postgres=&gt; update passwd set real_name = 'Alice Doe';
UPDATE 1 UPDATE 1
postgres=&gt; update passwd set real_name = 'John Doe' where username = 'admin'; postgres=&gt; update passwd set real_name = 'John Doe' where username = 'admin';
@ -1759,11 +1768,16 @@ postgres=&gt; delete from passwd;
ERROR: permission denied for relation passwd ERROR: permission denied for relation passwd
postgres=&gt; insert into passwd (username) values ('xxx'); postgres=&gt; insert into passwd (username) values ('xxx');
ERROR: permission denied for relation passwd ERROR: permission denied for relation passwd
-- Alice can change her own password -- Alice can change her own password; RLS silently prevents updating other rows
postgres=&gt; update passwd set pwhash = 'abc'; postgres=&gt; update passwd set pwhash = 'abc';
UPDATE 1 UPDATE 1
</programlisting> </programlisting>
<para>
For additional details see <xref linkend="sql-createpolicy">
and <xref linkend="sql-altertable">.
</para>
</sect1> </sect1>
<sect1 id="ddl-schemas"> <sect1 id="ddl-schemas">

View File

@ -16,13 +16,14 @@ PostgreSQL documentation
<refnamediv> <refnamediv>
<refname>ALTER POLICY</refname> <refname>ALTER POLICY</refname>
<refpurpose>change the definition of a policy</refpurpose> <refpurpose>change the definition of a row level security policy</refpurpose>
</refnamediv> </refnamediv>
<refsynopsisdiv> <refsynopsisdiv>
<synopsis> <synopsis>
ALTER POLICY <replaceable class="parameter">name</replaceable> ON <replaceable class="parameter">table_name</replaceable> RENAME TO <replaceable class="PARAMETER">new_name</replaceable>
ALTER POLICY <replaceable class="parameter">name</replaceable> ON <replaceable class="parameter">table_name</replaceable> ALTER POLICY <replaceable class="parameter">name</replaceable> ON <replaceable class="parameter">table_name</replaceable>
[ RENAME TO <replaceable class="PARAMETER">new_name</replaceable> ]
[ TO { <replaceable class="parameter">role_name</replaceable> | PUBLIC | CURRENT_USER | SESSION_USER } [, ...] ] [ TO { <replaceable class="parameter">role_name</replaceable> | PUBLIC | CURRENT_USER | SESSION_USER } [, ...] ]
[ USING ( <replaceable class="parameter">using_expression</replaceable> ) ] [ USING ( <replaceable class="parameter">using_expression</replaceable> ) ]
[ WITH CHECK ( <replaceable class="parameter">check_expression</replaceable> ) ] [ WITH CHECK ( <replaceable class="parameter">check_expression</replaceable> ) ]
@ -33,14 +34,22 @@ ALTER POLICY <replaceable class="parameter">name</replaceable> ON <replaceable c
<title>Description</title> <title>Description</title>
<para> <para>
<command>ALTER POLICY</command> changes the <replaceable class="parameter"> <command>ALTER POLICY</command> changes the definition of an existing
definition</replaceable> of an existing policy. row-level security policy.
</para> </para>
<para> <para>
To use <command>ALTER POLICY</command>, you must own the table that To use <command>ALTER POLICY</command>, you must own the table that
the policy applies to. the policy applies to.
</para> </para>
<para>
In the second form of <command>ALTER POLICY</command>, the role list,
<replaceable class="parameter">using_expression</replaceable>, and
<replaceable class="parameter">check_expression</replaceable> are replaced
independently if specified. When one of those clauses is omitted, the
corresponding part of the policy is unchanged.
</para>
</refsect1> </refsect1>
<refsect1> <refsect1>
@ -79,9 +88,9 @@ ALTER POLICY <replaceable class="parameter">name</replaceable> ON <replaceable c
<term><replaceable class="parameter">role_name</replaceable></term> <term><replaceable class="parameter">role_name</replaceable></term>
<listitem> <listitem>
<para> <para>
The role to which the policy applies. Multiple roles can be specified at one time. The role(s) to which the policy applies. Multiple roles can be
To apply the policy to all roles, use <literal>PUBLIC</literal>, which is also specified at one time. To apply the policy to all roles,
the default. use <literal>PUBLIC</literal>.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>

View File

@ -16,7 +16,7 @@ PostgreSQL documentation
<refnamediv> <refnamediv>
<refname>CREATE POLICY</refname> <refname>CREATE POLICY</refname>
<refpurpose>define a new policy for a table</refpurpose> <refpurpose>define a new row level security policy for a table</refpurpose>
</refnamediv> </refnamediv>
<refsynopsisdiv> <refsynopsisdiv>
@ -33,40 +33,34 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
<title>Description</title> <title>Description</title>
<para> <para>
The <command>CREATE POLICY</command> command defines a new policy for a The <command>CREATE POLICY</command> command defines a new row-level
table. Note that row-level security must also be enabled on the table using security policy for a table. Note that row-level security must be
<command>ALTER TABLE</command> in order for created policies to be applied. enabled on the table (using <command>ALTER TABLE ... ENABLE ROW LEVEL
SECURITY</command>) in order for created policies to be applied.
</para> </para>
<para> <para>
A policy grants the permission to select, insert, update, or delete rows A policy grants the permission to select, insert, update, or delete rows
that match the relevant policy expression. Existing table rows are that match the relevant policy expression. Existing table rows are
checked against the expression specified via <literal>USING</literal>, while new rows that checked against the expression specified in <literal>USING</literal>,
would be created via <literal>INSERT</literal> or <literal>UPDATE</literal> are checked against the expression while new rows that would be created via <literal>INSERT</literal>
specified via <literal>WITH CHECK</literal>. When a <literal>USING</literal> expression returns true for a given or <literal>UPDATE</literal> are checked against the expression specified
row then that row is visible to the user, while if a false or null is in <literal>WITH CHECK</literal>. When a <literal>USING</literal>
returned then the row is not visible. When a <literal>WITH CHECK</literal> expression expression returns true for a given row then that row is visible to the
returns true for a row then that row is added, while if a false or null is user, while if false or null is returned then the row is not visible.
returned then an error occurs. When a <literal>WITH CHECK</literal> expression returns true for a row
</para> then that row is inserted or updated, while if false or null is returned
then an error occurs.
<para>
Generally, the system will enforce filter conditions imposed using
security policies prior to qualifications that appear in the query itself,
in order to prevent the inadvertent exposure of the protected data to
user-defined functions which might not be trustworthy. However,
functions and operators marked by the system (or the system
administrator) as <literal>LEAKPROOF</literal> may be evaluated before policy
expressions, as they are assumed to be trustworthy.
</para> </para>
<para> <para>
For <command>INSERT</command> and <command>UPDATE</command> statements, For <command>INSERT</command> and <command>UPDATE</command> statements,
<literal>WITH CHECK</literal> expressions are enforced after <literal>WITH CHECK</literal> expressions are enforced after
<literal>BEFORE</literal> triggers are fired, and before any data modifications are made. <literal>BEFORE</literal> triggers are fired, and before any actual data
Thus a <literal>BEFORE ROW</literal> trigger may modify the data to be inserted, affecting modifications are made. Thus a <literal>BEFORE ROW</literal> trigger may
the result of the security policy check. <literal>WITH CHECK</literal> expressions are modify the data to be inserted, affecting the result of the security
enforced before any other constraints. policy check. <literal>WITH CHECK</literal> expressions are enforced
before any other constraints.
</para> </para>
<para> <para>
@ -79,18 +73,25 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
Policies can be applied for specific commands or for specific roles. The Policies can be applied for specific commands or for specific roles. The
default for newly created policies is that they apply for all commands and default for newly created policies is that they apply for all commands and
roles, unless otherwise specified. If multiple policies apply to a given roles, unless otherwise specified. If multiple policies apply to a given
statement, they will be combined using <quote>or</quote> (although <literal>ON CONFLICT DO statement, they will be combined using OR (although <literal>ON CONFLICT DO
UPDATE</> and <literal>INSERT</> policies are not combined in this way, but UPDATE</> and <literal>INSERT</> policies are not combined in this way, but
rather enforced as noted at each stage of <literal>ON CONFLICT</> execution). rather enforced as noted at each stage of <literal>ON CONFLICT</> execution).
</para> </para>
<para> <para>
Further, for commands that can have both <literal>USING</literal> For commands that can have both <literal>USING</literal>
and <literal>WITH CHECK</literal> policies (<literal>ALL</literal> and <literal>WITH CHECK</literal> policies (<literal>ALL</literal>
and <literal>UPDATE</literal>), if no <literal>WITH CHECK</literal> policy and <literal>UPDATE</literal>), if no <literal>WITH CHECK</literal>
is defined, then the <literal>USING</literal> policy will be used for both policy is defined, then the <literal>USING</literal> policy will be used
what rows are visible (normal <literal>USING</literal> case) and which rows both for which rows are visible (normal <literal>USING</literal> case)
will be allowed to be added (<literal>WITH CHECK</literal> case). and for which rows will be allowed to be added (<literal>WITH
CHECK</literal> case).
</para>
<para>
If row-level security is enabled for a table, but no applicable policies
exist, a <quote>default deny</> policy is assumed, so that no rows will
be visible or updatable.
</para> </para>
</refsect1> </refsect1>
@ -136,7 +137,7 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
<term><replaceable class="parameter">role_name</replaceable></term> <term><replaceable class="parameter">role_name</replaceable></term>
<listitem> <listitem>
<para> <para>
The roles to which the policy is to be applied. The default is The role(s) to which the policy is to be applied. The default is
<literal>PUBLIC</literal>, which will apply the policy to all roles. <literal>PUBLIC</literal>, which will apply the policy to all roles.
</para> </para>
</listitem> </listitem>
@ -149,10 +150,13 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
Any <acronym>SQL</acronym> conditional expression (returning Any <acronym>SQL</acronym> conditional expression (returning
<type>boolean</type>). The conditional expression cannot contain <type>boolean</type>). The conditional expression cannot contain
any aggregate or window functions. This expression will be added any aggregate or window functions. This expression will be added
to queries that refer to the table if row level security is enabled to queries that refer to the table if row level security is enabled.
and rows for which the expression returns true will be visible. Any Rows for which the expression returns true will be visible. Any
rows for which the expression returns false or null will not be rows for which the expression returns false or null will not be
visible to the user. visible to the user (in a <command>SELECT</>), and will not be
available for modification (in an <command>UPDATE</>
or <command>DELETE</>). Such rows are silently suppressed; no error
is reported.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -163,12 +167,15 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
<para> <para>
Any <acronym>SQL</acronym> conditional expression (returning Any <acronym>SQL</acronym> conditional expression (returning
<type>boolean</type>). The conditional expression cannot contain <type>boolean</type>). The conditional expression cannot contain
any aggregate or window functions. This expression will be used with any aggregate or window functions. This expression will be used in
<command>INSERT</command> and <command>UPDATE</command> queries against <command>INSERT</command> and <command>UPDATE</command> queries against
the table if row level security is enabled and only rows where the the table if row level security is enabled. Only rows for which the
expression evaluates to true will be allowed. An error will be thrown expression evaluates to true will be allowed. An error will be thrown
if the expression evaluates to false or null for any of the records if the expression evaluates to false or null for any of the records
inserted or any of the records that result from the update. inserted or any of the records that result from the update. Note that
the <replaceable class="parameter">check_expression</replaceable> is
evaluated against the proposed new contents of the row, not the
original contents.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -176,7 +183,7 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
</variablelist> </variablelist>
<refsect2> <refsect2>
<title>Per-Command policies</title> <title>Per-Command Policies</title>
<variablelist> <variablelist>
@ -189,25 +196,25 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
<literal>ALL</literal> policy exists and more specific policies <literal>ALL</literal> policy exists and more specific policies
exist, then both the <literal>ALL</literal> policy and the more exist, then both the <literal>ALL</literal> policy and the more
specific policy (or policies) will be combined using specific policy (or policies) will be combined using
<quote>or</quote>, as usual for overlapping policies. OR, as usual for overlapping policies.
Additionally, <literal>ALL</literal> policies will be applied to Additionally, <literal>ALL</literal> policies will be applied to
both the selection side of a query and the modification side, using both the selection side of a query and the modification side, using
the <literal>USING</literal> policy for both if only a <literal>USING</literal> policy has been defined. the <literal>USING</literal> expression for both cases if only
a <literal>USING</literal> expression has been defined.
</para> </para>
<para> <para>
As an example, if an <literal>UPDATE</literal> is issued, then the As an example, if an <literal>UPDATE</literal> is issued, then the
<literal>ALL</literal> policy will be applicable to both what the <literal>ALL</literal> policy will be applicable both to what the
<literal>UPDATE</literal> will be able to select out as rows to be <literal>UPDATE</literal> will be able to select as rows to be
updated (with the <literal>USING</literal> expression being applied), and it will be updated (applying the <literal>USING</literal> expression),
applied to rows that result from the <literal>UPDATE</literal> and to the resulting updated rows, to check if they are permitted
statement, to check if they are permitted to be added to the table to be added to the table (applying the <literal>WITH CHECK</literal>
(using the <literal>WITH CHECK</literal> expression, if defined, and the <literal>USING</literal> expression expression, if defined, and the <literal>USING</literal> expression
otherwise). If an <command>INSERT</command> or <command>UPDATE</command> command attempts to add rows to otherwise). If an <command>INSERT</command>
the table that do not pass the <literal>ALL</literal> <literal>WITH CHECK</literal> or <command>UPDATE</command> command attempts to add rows to the
expression, the entire command will be aborted. Note that if only a table that do not pass the <literal>ALL</literal>
<literal>USING</literal> clause is specified then that clause will be policy's <literal>WITH CHECK</literal> expression, the entire
used for both <literal>USING</literal> and command will be aborted.
<literal>WITH CHECK</literal> cases.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -221,13 +228,12 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
<literal>SELECT</literal> permissions are required on the relation the <literal>SELECT</literal> permissions are required on the relation the
policy is defined for. The result is that only those records from the policy is defined for. The result is that only those records from the
relation that pass the <literal>SELECT</literal> policy will be relation that pass the <literal>SELECT</literal> policy will be
returned during a <literal>SELECT</literal> query, even if other returned during a <literal>SELECT</literal> query, and that queries
records exist in the relation and that queries which require that require <literal>SELECT</literal> permissions, such as
<literal>SELECT</literal> permissions, such as
<literal>UPDATE</literal>, will also only see those records <literal>UPDATE</literal>, will also only see those records
which are allowed by the <literal>SELECT</literal> policy. that are allowed by the <literal>SELECT</literal> policy.
The <literal>SELECT</literal> policy only accepts the A <literal>SELECT</literal> policy cannot have a <literal>WITH
<literal>USING</literal> expression as it only applies in cases where CHECK</literal> expression, as it only applies in cases where
records are being retrieved from the relation. records are being retrieved from the relation.
</para> </para>
</listitem> </listitem>
@ -240,16 +246,16 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
Using <literal>INSERT</literal> for a policy means that it will apply Using <literal>INSERT</literal> for a policy means that it will apply
to <literal>INSERT</literal> commands. Rows being inserted that do to <literal>INSERT</literal> commands. Rows being inserted that do
not pass this policy will result in a policy violation error, and the not pass this policy will result in a policy violation error, and the
entire <literal>INSERT</literal> command will be aborted. The entire <literal>INSERT</literal> command will be aborted.
<literal>INSERT</literal> policy only accepts the An <literal>INSERT</literal> policy cannot have
<literal>WITH CHECK</literal> expression as it only applies in cases a <literal>USING</literal> expression, as it only applies in cases
where records are being added to the relation. where records are being added to the relation.
</para> </para>
<para> <para>
Note that <literal>INSERT</literal> with <literal>ON CONFLICT DO Note that <literal>INSERT</literal> with <literal>ON CONFLICT DO
UPDATE</literal> requires that any <literal>INSERT</literal> policy UPDATE</literal> checks <literal>INSERT</literal> policies'
<literal>WITH CHECK</literal> expression passes for any rows appended <literal>WITH CHECK</literal> expressions only for rows appended
to the relation by the <literal>INSERT</literal> path only. to the relation by the <literal>INSERT</literal> path.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -261,19 +267,15 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
Using <literal>UPDATE</literal> for a policy means that it will apply Using <literal>UPDATE</literal> for a policy means that it will apply
to <literal>UPDATE</literal> commands (or auxiliary <literal>ON to <literal>UPDATE</literal> commands (or auxiliary <literal>ON
CONFLICT DO UPDATE</literal> clauses of <literal>INSERT</literal> CONFLICT DO UPDATE</literal> clauses of <literal>INSERT</literal>
commands). As <literal>UPDATE</literal> involves pulling an existing commands). Since <literal>UPDATE</literal> involves pulling an
record and then making changes to some portion (but possibly not all) existing record and then making changes to some portion (but
of the record, the <literal>UPDATE</literal> policy accepts both a possibly not all) of the record, <literal>UPDATE</literal>
<literal>USING</literal> expression and a <literal>WITH CHECK</literal> policies accept both a <literal>USING</literal> expression and
expression. a <literal>WITH CHECK</literal> expression.
</para> The <literal>USING</literal> expression determines which records
the <literal>UPDATE</literal> command will see to operate against,
<para> while the <literal>WITH CHECK</literal> expression defines which
The <literal>USING</literal> expression will be used to modified rows are allowed to be stored back into the relation.
determine which records the <literal>UPDATE</literal> command will see
to operate against, while the <literal>WITH CHECK</literal> expression
defines what rows are allowed to be added back into the relation
(similar to the <literal>INSERT</literal> policy).
</para> </para>
<para> <para>
@ -285,15 +287,15 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
overlapping <literal>SELECT</literal> related policies found) with the overlapping <literal>SELECT</literal> related policies found) with the
<literal>USING</literal> clause of the <literal>UPDATE</literal> policy <literal>USING</literal> clause of the <literal>UPDATE</literal> policy
using AND. Therefore, in order for a user to be able to using AND. Therefore, in order for a user to be able to
<literal>UPDATE</literal> a specific set of rows using a <literal>UPDATE</literal> specific rows, the user must have access
<literal>WHERE</literal> clause, the user must have access to the to the row(s) through a <literal>SELECT</literal>
row(s) through a <literal>SELECT</literal> or <literal>ALL</literal> or <literal>ALL</literal> policy and the row(s) must pass
policy and the row(s) must be pass the <literal>UPDATE USING</literal> the <literal>UPDATE</literal> policy's <literal>USING</>
expression. expression.
</para> </para>
<para> <para>
Any rows whose resulting values do not pass the Any rows whose updated values do not pass the
<literal>WITH CHECK</literal> expression will cause an error, and the <literal>WITH CHECK</literal> expression will cause an error, and the
entire command will be aborted. If only a <literal>USING</literal> entire command will be aborted. If only a <literal>USING</literal>
clause is specified, then that clause will be used for both clause is specified, then that clause will be used for both
@ -307,9 +309,10 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
<literal>WITH CHECK</literal> expression. This <literal>WITH CHECK</literal> expression. This
<literal>UPDATE</literal> policy must always pass when the <literal>UPDATE</literal> policy must always pass when the
<literal>UPDATE</literal> path is taken. Any existing row that <literal>UPDATE</literal> path is taken. Any existing row that
necessitates that the <literal>UPDATE</literal> path be taken must pass necessitates that the <literal>UPDATE</literal> path be taken must
the (<literal>UPDATE</literal> or <literal>ALL</literal>) <literal>USING</literal> qualifications (combined pass the (<literal>UPDATE</literal> or <literal>ALL</literal>)
using <quote>or</quote>), which are always enforced as <literal>WITH CHECK</literal> <literal>USING</literal> qualifications (combined using OR), which
are always enforced as <literal>WITH CHECK</literal>
options in this context. (The <literal>UPDATE</literal> path will options in this context. (The <literal>UPDATE</literal> path will
<emphasis>never</> be silently avoided; an error will be thrown <emphasis>never</> be silently avoided; an error will be thrown
instead.) Finally, the final row appended to the relation must pass instead.) Finally, the final row appended to the relation must pass
@ -327,8 +330,9 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
to <literal>DELETE</literal> commands. Only rows that pass this to <literal>DELETE</literal> commands. Only rows that pass this
policy will be seen by a <literal>DELETE</literal> command. There can policy will be seen by a <literal>DELETE</literal> command. There can
be rows that are visible through a <literal>SELECT</literal> that are be rows that are visible through a <literal>SELECT</literal> that are
not seen by a <literal>DELETE</literal>, if they do not pass the not available for deletion, if they do not pass the
<literal>USING</literal> expression for the <literal>DELETE</literal>. <literal>USING</literal> expression for
the <literal>DELETE</literal> policy.
</para> </para>
<para> <para>
@ -340,17 +344,18 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
overlapping <literal>SELECT</literal> related policies found) with the overlapping <literal>SELECT</literal> related policies found) with the
<literal>USING</literal> clause of the <literal>DELETE</literal> policy <literal>USING</literal> clause of the <literal>DELETE</literal> policy
using AND. Therefore, in order for a user to be able to using AND. Therefore, in order for a user to be able to
<literal>DELETE</literal> a specific set of rows using a <literal>DELETE</literal> specific rows, the user must have access
<literal>WHERE</literal> clause, the user must have access to the to the row(s) through a <literal>SELECT</literal>
row(s) through a <literal>SELECT</literal> or <literal>ALL</literal> or <literal>ALL</literal> policy and the row(s) must pass
policy and the row(s) must be pass the <literal>DELETE USING</literal> the <literal>DELETE</literal> policy's <literal>USING</>
expression. expression.
</para> </para>
<para> <para>
The <literal>DELETE</literal> policy only accepts the A <literal>DELETE</literal> policy cannot have a <literal>WITH
<literal>USING</literal> expression as it only applies in cases where CHECK</literal> expression, as it only applies in cases where
records are being extracted from the relation for deletion. records are being deleted from the relation, so that there is no
new row to check.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -367,11 +372,11 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
</para> </para>
<para> <para>
Note that while policies will be applied for explicit queries against tables While policies will be applied for explicit queries against tables
in the system, they are not applied when the system is performing internal in the database, they are not applied when the system is performing internal
referential integrity checks or validating constraints. This means there are referential integrity checks or validating constraints. This means there are
indirect ways to determine that a given value exists. An example of this is indirect ways to determine that a given value exists. An example of this is
attempting to insert a duplicate value into a column which is the primary key attempting to insert a duplicate value into a column that is a primary key
or has a unique constraint. If the insert fails then the user can infer that or has a unique constraint. If the insert fails then the user can infer that
the value already exists. (This example assumes that the user is permitted by the value already exists. (This example assumes that the user is permitted by
policy to insert records which they are not allowed to see.) Another example policy to insert records which they are not allowed to see.) Another example
@ -379,33 +384,46 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
otherwise hidden table. Existence can be determined by the user inserting otherwise hidden table. Existence can be determined by the user inserting
values into the referencing table, where success would indicate that the values into the referencing table, where success would indicate that the
value exists in the referenced table. These issues can be addressed by value exists in the referenced table. These issues can be addressed by
carefully crafting policies that prevent users from being able to insert, carefully crafting policies to prevent users from being able to insert,
delete, or update records at all which might possibly indicate a value they delete, or update records at all which might possibly indicate a value they
are not otherwise able to see, or by using generated values (e.g., surrogate are not otherwise able to see, or by using generated values (e.g., surrogate
keys) instead. keys) instead of keys with external meanings.
</para> </para>
<para> <para>
Regarding how policy expressions interact with the user: as the expressions Generally, the system will enforce filter conditions imposed using
security policies prior to qualifications that appear in user queries,
in order to prevent inadvertent exposure of the protected data to
user-defined functions which might not be trustworthy. However,
functions and operators marked by the system (or the system
administrator) as <literal>LEAKPROOF</literal> may be evaluated before
policy expressions, as they are assumed to be trustworthy.
</para>
<para>
Since policy expressions
are added to the user's query directly, they will be run with the rights of are added to the user's query directly, they will be run with the rights of
the user running the overall query. Therefore, users who are using a given the user running the overall query. Therefore, users who are using a given
policy must be able to access any tables or functions referenced in the policy must be able to access any tables or functions referenced in the
expression or they will simply receive a permission denied error when expression or they will simply receive a permission denied error when
attempting to query the table that has row-level security enabled. This does not change how views attempting to query the table that has row-level security enabled.
This does not change how views
work, however. As with normal queries and views, permission checks and work, however. As with normal queries and views, permission checks and
policies for the tables which are referenced by a view will use the view policies for the tables which are referenced by a view will use the view
owner's rights and any policies which apply to the view owner. owner's rights and any policies which apply to the view owner.
</para> </para>
<para> <para>
When reducing the set of rows which a user has access to, through When reducing the set of rows which users have access to, through
modifications to relations referenced by Row-Level Security Policies or modifications to row-level security policies or security-barrier views,
Security Barrier Views, be aware that users with a currently open transaction be aware that users with a currently open transaction may be able to see
may be able to see updates to the rows that they are no longer allowed updates to rows that they are theoretically no longer allowed access to,
access. Therefore, the best practice to avoid any possible leak of as the new policies may not be absorbed into existing query plans
immediately. Therefore, the best practice to avoid any possible leak of
information when altering conditions that determine the visibility of information when altering conditions that determine the visibility of
specific rows is to ensure that affected users do not have any open specific rows is to ensure that affected users do not have any open
transactions, perhaps by ensuring they have no concurrent sessions running. transactions, perhaps by ensuring they have no concurrent sessions
running.
</para> </para>
</refsect1> </refsect1>
@ -425,6 +443,7 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable
<simplelist type="inline"> <simplelist type="inline">
<member><xref linkend="sql-alterpolicy"></member> <member><xref linkend="sql-alterpolicy"></member>
<member><xref linkend="sql-droppolicy"></member> <member><xref linkend="sql-droppolicy"></member>
<member><xref linkend="sql-altertable"></member>
</simplelist> </simplelist>
</refsect1> </refsect1>

View File

@ -16,7 +16,7 @@ PostgreSQL documentation
<refnamediv> <refnamediv>
<refname>DROP POLICY</refname> <refname>DROP POLICY</refname>
<refpurpose>remove a policy from a table</refpurpose> <refpurpose>remove a row level security policy from a table</refpurpose>
</refnamediv> </refnamediv>
<refsynopsisdiv> <refsynopsisdiv>
@ -32,10 +32,9 @@ DROP POLICY [ IF EXISTS ] <replaceable class="parameter">name</replaceable> ON <
<command>DROP POLICY</command> removes the specified policy from the table. <command>DROP POLICY</command> removes the specified policy from the table.
Note that if the last policy is removed for a table and the table still has Note that if the last policy is removed for a table and the table still has
row level security enabled via <command>ALTER TABLE</command>, then the row level security enabled via <command>ALTER TABLE</command>, then the
default-deny policy will be used. <command>ALTER TABLE</command> can be used default-deny policy will be used. <literal>ALTER TABLE ... DISABLE ROW
to disable row level security for a table using LEVEL SECURITY</literal> can be used to disable row level security for a
<literal>DISABLE ROW SECURITY</literal>, whether policies for the table table, whether policies for the table exist or not.
exist or not.
</para> </para>
</refsect1> </refsect1>