LoginSignup
2
1

PostgreSQL 大きな整数を使用することによる脆弱性

Last updated at Posted at 2024-03-30

大きな整数を使用することによる脆弱性

次の記事の内容を抜粋した記事です。
bigintを超える整数を使用すると、クエリの速度が著しく落ちて、攻撃手段に使用できる場合があるというものです。

発生条件

次の 4 つの質問の回答がYesの場合、脆弱な可能性があります

  • PostgreSQL を使用していますか?
  • bigint範囲外の整数をサポートするプログラミング言語を使用していますか(ほとんどの動的型付けプログラミング言語はサポート)?
  • ユーザー入力から得られた整数値を、範囲内にあるかどうかを検証せずに受け入れてますか?
  • 引用符、明示的なキャスト、またはバインドされた変数を使用せずに、クエリ内で文字通り整数値を使用していますか?

※ PostgreSQLが条件に入っているのは、次の仕様によるものです。

小数点も指数も含まない数値定数は、その値が型integer(32 ビット) に適合する場合、最初はinteger型であると推定されます。それ以外の場合、その値が型bigint(64 ビット)に適合する場合はbigint型であるとみなされます。それ以外の場合は、numeric型とみなされます。

準備

データベース作成

postgres@masami-L ~> createdb -U postgres sample
postgres@masami-L ~> psql -U postgres -d sample

テーブル作成

sample=# CREATE TABLE a AS SELECT * FROM generate_series(1,1000000) AS a(id);
CREATE INDEX ON a(id);
SELECT 1000000
CREATE INDEX

事象

bigint の最大値 9223372036854775807 で 検索

sample=# EXPLAIN ANALYZE SELECT id FROM a WHERE id = 9223372036854775807;
                                                   QUERY PLAN
-----------------------------------------------------------------------------------------------------------------
 Index Only Scan using a_id_idx on a  (cost=0.42..4.44 rows=1 width=4) (actual time=0.111..0.112 rows=0 loops=1)
   Index Cond: (id = '9223372036854775807'::bigint)
   Heap Fetches: 0
 Planning Time: 0.672 ms
 Execution Time: 0.150 ms
(5 rows)

インデックススキャンが使用されます

bigint を超える値で検索します

sample=# EXPLAIN ANALYZE SELECT id FROM a WHERE id = 9223372036854775808;
                                                    QUERY PLAN
-------------------------------------------------------------------------------------------------------------------
 Gather  (cost=1000.00..12175.00 rows=5000 width=4) (actual time=102.700..106.299 rows=0 loops=1)
   Workers Planned: 2
   Workers Launched: 2
   ->  Parallel Seq Scan on a  (cost=0.00..10675.00 rows=2083 width=4) (actual time=97.138..97.138 rows=0 loops=3)
         Filter: ((id)::numeric = '9223372036854775808'::numeric)
         Rows Removed by Filter: 333333
 Planning Time: 0.469 ms
 Execution Time: 106.355 ms
(8 rows)

シーケンシャルスキャンに代わり、動作が 60 倍以上遅くなりました。
numeric で検索しているため、インデックスが効かないようです。

対策

基本的にはクライアントで対策が本筋になります。

  • バインド変数を使用する
  • パラメータチェックする

ActiveRecord等いくつかのデータベースライブラリは、ブログ主の報告をもって、
対策したようですが、自前でチェックしたほうがいいでしょう

その他回避策

何らかの理由でクライアント側で対策が取れない場合、 回避策も提案されています

  • 予期していない型になるパラメータはエラーにする
sample=# EXPLAIN ANALYZE SELECT id FROM a WHERE id = 9223372036854775808::bigint;
ERROR:  bigint out of range
  • numeric のインデックスを張る方法
sample=# CREATE INDEX ON a((id::numeric));
CREATE INDEX
sample=# EXPLAIN ANALYZE SELECT id FROM a WHERE id = 9223372036854775808;
                                                      QUERY PLAN
----------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on a  (cost=95.17..4805.55 rows=5000 width=4) (actual time=0.108..0.109 rows=0 loops=1)
   Recheck Cond: ((id)::numeric = '9223372036854775808'::numeric)
   ->  Bitmap Index Scan on a_id_idx1  (cost=0.00..93.92 rows=5000 width=0) (actual time=0.104..0.105 rows=0 loops=1)
         Index Cond: ((id)::numeric = '9223372036854775808'::numeric)
 Planning Time: 0.562 ms
 Execution Time: 0.147 ms
(6 rows)

ちなみにブログ参照先の Reddit にもあるように整数以外でも当然インデックススキャンはされません。

sample=# EXPLAIN ANALYZE SELECT id FROM a WHERE id = 0.11;
                                                    QUERY PLAN
-------------------------------------------------------------------------------------------------------------------
 Gather  (cost=1000.00..12175.00 rows=5000 width=4) (actual time=97.910..101.180 rows=0 loops=1)
   Workers Planned: 2
   Workers Launched: 2
   ->  Parallel Seq Scan on a  (cost=0.00..10675.00 rows=2083 width=4) (actual time=92.100..92.101 rows=0 loops=3)
         Filter: ((id)::numeric = 0.11)
         Rows Removed by Filter: 333333
 Planning Time: 0.320 ms
 Execution Time: 101.214 ms
(8 rows)
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1