8000 Warn that views can be safely used to hide columns, but not rows. · danielcode/postgres@04daad2 · GitHub
[go: up one dir, main page]

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 04daad2

Browse files
committed
Warn that views can be safely used to hide columns, but not rows.
1 parent d6d7926 commit 04daad2

File tree

2 files changed

+51
-11
lines changed

2 files changed

+51
-11
lines changed

doc/src/sgml/ref/create_view.sgml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,12 @@ CREATE VIEW vista AS SELECT text 'Hello World' AS hello;
144144

145145
<para>
146146
Access to tables referenced in the view is determined by permissions of
147-
the view owner. However, functions called in the view are treated the
148-
same as if they had been called directly from the query using the view.
149-
Therefore the user of a view must have permissions to call all functions
150-
used by the view.
147+
the view owner. In some cases, this can be used to provide secure but
148+
restricted access to the underlying tables. However, not all views are
149+
secure against tampering; see <xref linkend="rules-privileges"> for
150+
details. Functions called in the view are treated the same as if they had
151+
been called directly from the query using the view. Therefore the user of
152+
a view must have permissions to call all functions used by the view.
151153
</para>
152154

153155
<para>

doc/src/sgml/rules.sgml

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1725,18 +1725,18 @@ SELECT * FROM shoelace;
17251725
<programlisting>
17261726
CREATE TABLE phone_data (person text, phone text, private boolean);
17271727
CREATE VIEW phone_number AS
1728-
SELECT person, phone FROM phone_data WHERE NOT private;
1728+
SELECT person, CASE WHEN NOT private THEN phone END AS phone
1729+
FROM phone_data;
17291730
GRANT SELECT ON phone_number TO secretary;
17301731
</programlisting>
1731-
1732+
17321733
Nobody except him (and the database superusers) can access the
17331734
<literal>phone_data</> table. But because of the <command>GRANT</>,
17341735
the secretary can run a <command>SELECT</command> on the
17351736
<literal>phone_number</> view. The rule system will rewrite the
17361737
<command>SELECT</command> from <literal>phone_number</> into a
1737-
<command>SELECT</command> from <literal>phone_data</> and add the
1738-
qualification that only entries where <literal>private</> is false
1739-
are wanted. Since the user is the owner of
1738+
<command>SELECT</command> from <literal>phone_data</>.
1739+
Since the user is the owner of
17401740
<literal>phone_number</> and therefore the owner of the rule, the
17411741
read access to <literal>phone_data</> is now checked against his
17421742
privileges and the query is permitted. The check for accessing
@@ -1770,15 +1770,53 @@ GRANT SELECT ON phone_number TO secretary;
17701770
</para>
17711771

17721772
<para>
1773-
This mechanism also works for update rules. In the examples of
1773+
Note that while views can be used to hide the contents of certain
1774+
columns using the technique shown above, they cannot be used to reliably
1775+
conceal the data in unseen rows. For example, the following view is
1776+
insecure:
1777+
<programlisting>
1778+
CREATE VIEW phone_number AS
1779+
SELECT person, phone FROM phone_data WHERE phone NOT LIKE '412%';
1780+
</programlisting>
1781+
This view might seem secure, since the rule system will rewrite any
1782+
<command>SELECT</command> from <literal>phone_number</> into a
1783+
<command>SELECT</command> from <literal>phone_data</> and add the
1784+
qualification that only entries where <literal>phone</> does not begin
1785+
with 412 are wanted. But if the user can create his or her own functions,
1786+
it is not difficult to convince the planner to execute the user-defined
1787+
function prior to the <function>NOT LIKE</function> expression.
1788+
<programlisting>
1789+
CREATE FUNCTION tricky(text, text) RETURNS bool AS $$
1790+
BEGIN
1791+
RAISE NOTICE '% => %', $1, $2;
1792+
RETURN true;
1793+
END
1794+
$$ LANGUAGE plpgsql COST 0.0000000000000000000001;
1795+
SELECT * FROM phone_number WHERE tricky(person, phone);
1796+
</programlisting>
1797+
Every person and phone number in the <literal>phone_data</> table will be
1798+
printed as a <literal>NOTICE</literal>, because the planner will choose to
1799+
execute the inexpensive <function>tricky</function> function before the
1800+
more expensive <function>NOT LIKE</function>. Even if the user is
1801+
prevented from defining new functions, built-in functions can be used in
1802+
similar attacks. (For example, casting functions include their inputs in
1803+
the error messages they produce.)
1804+
</para>
1805+
1806+
<para>
1807+
Similar considerations apply to update rules. In the examples of
17741808
the previous section, the owner of the tables in the example
17751809
database could grant the privileges <literal>SELECT</>,
17761810
<literal>INSERT</>, <literal>UPDATE</>, and <literal>DELETE</> on
17771811
the <literal>shoelace</> view to someone else, but only
17781812
<literal>SELECT</> on <literal>shoelace_log</>. The rule action to
17791813
write log entries will still be executed successfully, and that
17801814
other user could see the log entries. But he cannot create fake
1781-
entries, nor could he manipulate or remove existing ones.
1815+
entries, nor could he manipulate or remove existing ones. In this
1816+
case, there is no possibility of subverting the rules by convincing
1817+
the planner to alter the order of operations, because the only rule
1818+
which references <literal>shoelace_log</> is an unqualified
1819+
<literal>INSERT</>. This might not be true in more complex scenarios.
17821820
</para>
17831821
</sect1>
17841822

0 commit comments

Comments
 (0)
0