CVE-2018-1058 は PostgreSQL 10.3 等で文書化された脆弱性で、マニュアルの 5.8.6. Usage Patterns などに対策のための記述が追加されました。
詳しい内容は Wiki の A Guide to CVE-2018-1058: Protect Your Search Path に記述されており (日本語だとOSSデータベース取り取り時報 第32回が良いです)、面白い挙動だと思ったので実際の動きを確認してみました。
再現手順
1. Windows 10 に PostgreSQL 10.3 をインストール
ロケールを C にして適当にインストールしました。
2. C:\Program Files\PostgreSQL\10\bin を PATH に追加
3. postgres さんでログイン
PS> psql -Upostgres
4. alice ちゃんのアカウントをつくる
postgres=# CREATE USER alice WITH PASSWORD 'Shino'; -- シノ大好き!
インストーラーが作るデータベース・クラスタは initdb -A md5
となっているため、パスワード認証必須みたいです。
5. テーブル a をつくる
postgres=# CREATE TABLE a (full_name varchar(255));
6. 適当に insert する
postgres=# INSERT INTO a VALUES ('humpty dumpty');
7. upper 関数を使って確認
postgres=# SELECT upper(full_name) FROM a;
upper
---------------
HUMPTY DUMPTY
(1 行)
これがあるべき結果!
8. alice ちゃんでログイン
PS> psql -Ualice postgres
9. いたずらで罠関数版の upper を作る
postgres=> CREATE FUNCTION upper(varchar) RETURNS text AS $$
postgres$> -- 日本の文字大好き! 全角にしよう!
postgres$> SELECT translate($1, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
postgres$> $$ LANGUAGE SQL IMMUTABLE;
10. postgres さんでさっきと同じクエリを実行
postgres=# SELECT upper(full_name) FROM a;
upper
---------------------------
HUMPTY DUMPTY
(1 行)
さっきと違って全角になってる!! 罠関数を踏んでしまった!
普通の upper は引数が text 型なので varchar 型とは暗黙の型変換が行われますが、alice ちゃんの upper は引数が元から varchar 型なので、より良く一致するのですね。
11. postgres さんで問題を解決
postgres=# -- 容疑者探し
postgres=# \df+ public.*
関数一覧
スキーマ | 名前 | 結果のデータ型 | 引数のデータ型 | 型 | 関数の変動性分類 | 並列実行 | 所有者 | セキュリティ | アクセス権限 | 手続き言語 | ソースコード | 説明
----------+-------+----------------+-------------------+------+------------------+----------+--------+--------------+--------------+------------+-----------------------------------------------------------------------------------------------------------------+------
public | upper | text | character varying | 通常 | IMMUTABLE | 危険 | alice | 起動ロール | | sql | +|
| | | | | | | | | | | -- 日本の文字大好き! 全角にしよう! +|
| | | | | | | | | | | SELECT translate($1, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');+|
| | | | | | | | | | | |
(1 行)
postgres=# DROP FUNCTION public.upper; -- アリスちゃんのいたずらの後始末
DROP FUNCTION
postgres=# REVOKE CREATE ON SCHEMA public FROM PUBLIC; -- 明示的に許可していないユーザーは public に CREATE できなくしよう
REVOKE
この対策が取れない場合、search_path を '"$user", public'
ではなく "$user"
とする方法があります。
12. alice ちゃんでいたずらできないのを確認
postgres=> CREATE FUNCTION upper(varchar) RETURNS text AS $$
postgres$> SELECT translate($1, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
postgres$> $$ LANGUAGE SQL IMMUTABLE;
ERROR: permission denied for schema public
13. alice ちゃん用の遊び場を作成
postgres=# CREATE SCHEMA AUTHORIZATION alice;
14. alice ちゃんが自室で遊べることを確認
postgres=> CREATE FUNCTION upper(varchar) RETURNS text AS $$
postgres$> SELECT translate($1, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
postgres$> $$ LANGUAGE SQL IMMUTABLE;
CREATE FUNCTION
postgres=> CREATE TABLE b (first varchar(256), last text);
CREATE TABLE
postgres=> INSERT INTO b VALUES ('humpty', 'dumpty');
INSERT 0 1
postgres=> SELECT upper(first), upper(last) FROM b;
upper | upper
--------------+--------
HUMPTY | DUMPTY
(1 行)
あとがき
デフォルトの権限を見直さず alice ちゃんに不要な権限を与えちゃったのがいけなかったですね。とはいえデフォルト値の initdb -A trust
とか、public に一般ユーザが CREATE できるとかは好ましいとは思えず、最初から安全にしてくれても良いのに、と思いました。11 に期待できるでしょうか。
私は 10.3 の提供開始当初、アップデートしさえすれば安全になると思い込んでいました。Windows Server の Meltdown 脆弱性パッチでも同じ勘違いをしていました。リリースノート等はきちんと読むべきですね。
私に商用環境の構築経験はないため、もしかすると上記では不十分な点もあるかもしれません。業務でご参考になさる場合には、私と同じ轍を踏まないよう、公式文書も合わせてご確認ください。
ここまでご覧いただきありがとうございました。