5

Web アプリケーションでは、レコード ID をランダム化します。その理由は、DB に既にいくつのエントリが存在するかを非表示にしたいためであり、リストにないものがあるためです。ID が単純な増分番号である場合、リストにないものの ID を推測するのは簡単です。

私が見たところ、これを行うには3つの方法があります。

単純な乱数

アルゴリズム:

  1. 挿入時に乱数を作成します。
  2. ID がすでに使用されているかどうかを確認します。はいの場合は 1 に進みます。
  3. この ID を使用します。

プロ

  • 簡単
  • ID の任意のサイズまたはタイプ (32 ビット、64 ビット、可変長、文字列) で動作します

コントラ

  • 競合状態の可能性があるため、トランザクションが必要です (アルゴリズムはアトミックではありません)。

UUID

プロ

  • 衝突の可能性は非常に低いため、無視できます

コントラ

  • URL コメント ( "#{id}--#{page_title}) としてページ タイトルを含む素敵な短い URL が必要な場合、UUID を使用すると、このコメントが右端まで移動します。
  • 主キーとしてのUUIDは、結合のパフォーマンスが低下すると思いますか?

暗号化された ID

アルゴリズム:

  1. nextval(atomic!)を使用してシーケンスから数値を読み取る
  2. 秘密鍵と、ID に使用されるサイズで動作する暗号化アルゴリズムを使用して ID を暗号化します。

プロ

  • 競合状態なし (トランザクションは不要)

コントラ

  • ID 列のサイズは決して変更できません
  • 誰かが鍵を解読/推測できれば、すべてが無駄だった

タイムスタンプ

@emboss の提案

プロ

  • 簡単
  • IDが不足することはありません

コントラ

  • 衝突が発生する可能性があります(ただし、実際に発生するかどうかをテストする必要があります)
  • 多分ある程度推測できる

ランダム パブリック ID/名前ベースのパブリック ID

@viktor tron の提案

レコードを検索するためにのみ使用される、URL で発生するすべてのものの 2 番目の ID。内部的には通常の ID が使用されます (結合など)。

プロ

  • 内部的にはすべて正常なままです
  • 適切なランダム アルゴリズム/命名スキームにより、URL の推測が (十分に) 不可能になるはずです。

コントラ

  • パブリック インターフェイスで ID を使用する多くの変更
  • ユーザーは、そのようなタイトルを含む URL を削減できると考えるかもしれませんが、この場合、URL は機能しなくなります。

3番目のオプションを使用すると思います。それとも、それに対するより多くの議論がありますか? さらに良い解決策はありますか?Ruby on Rails 3.x と PostgreSQL 9.x を使用しています。

編集:非公開は非公開を意味しません!YouTube の限定公開動画のようなものです。検索結果やアップローダーのプロフィールに表示されない通常の動画です。そのため、(考えられるすべての ID を試してみないと) 実際にそれらを見つけることはできませんが、URL を知っている人なら誰でもそれらにアクセスできます。もちろん、何かを非公開にし、リンクを他の誰かに送信するユーザーは、それが不明なままではない可能性があることに注意する必要があります (URL が渡され、リンクによって検索エンジンにたどり着く可能性があります)。

物事を非公開にする別のオプションもあります。これらは2つの異なるものです。(「非公開」の意味を誰もが知っていると仮定するのは間違いだと思います。)

4

6 に答える 6

12

:これは質問の最初のバージョンに回答します。これは、これが承認ロジックの代わりではないことが明らかではありませんでした。


これは間違った問題に対する間違った解決策です。

問題は、ユーザーが「リストにない」ものの ID を推測して使用できることだと思います。

実際の問題は、ユーザーが承認なしでアクセスできることです。

承認ロジックを導入し、ユーザーが正当にアクセスできる項目のみにアクセスを許可し、それ以外はすべて禁止します。

また

DB にあるエントリの数を非表示にします

これが理由なら、小さいことは恥ずかしいことではないと思います。とにかく、シーケンスを100000から開始するか、Nずつ増やすか、別の同様のトリックを使用できます:)

于 2012-05-28T14:24:44.493 に答える
3

まったく別の方法をお勧めします。単純にレコード ID をユーザーに表示しないことです。あなたはそれをする必要が無い。URL には別の識別形式を使用してください。

きれいな URL が必要だと言っているので、https://github.com/norman/friendly_idのようなスラッガー/パーマリンク gem を使用できます。

Friendly_id のデフォルトのスラッグ ジェネレーターは、スラッグ文字列の一意性をチェックする機能を提供し、必要に応じてそれを保証するためにシーケンスを追加します。

真剣に、IDはそのままにしておいてください:)

于 2012-05-28T14:17:22.113 に答える
2

「内部ID」参照とともに、いくつかの静的ソルトで衝突耐性のあるハッシュ関数を使用します。たとえば、SHA-256 は X の要素を H の要素に一意にマッピングし、衝突の可能性は低くなります。ただし、H の要素から X の要素を計算することは (数学的に) 非常に困難です。

Ruby では、次のようにします。

@hashed_id = Digest::SHA2.new << SHA_SALT << @foo.id

ところで、これは暗号化の形式ではありません。なぜなら、秘密鍵を知らなくても、同じ入力があれば誰でも同じハッシュを生成できるからです。また、一方向関数にすぎないため、「復号化」アルゴリズムもありません。

于 2012-05-28T14:33:01.410 に答える
1

セルジオはあなたの問題に完璧な答えを出したと思います。

あなたが達成しようとしているのは、あいまいさによるセキュリティの良い例です。リストにない特定のアイテムへのアクセスを適切に制限する代わりに、これらのアイテムを人々から隠そうとしています。しかし、これでも隠されたアイテムを推測する可能性は残りますが、アクセス制限により、想定されていないページを表示することができなくなります。そして、アクセス制限が明らかに勝者である理由があります。あるべきではないものを表示する可能性が 0 であるのに対し、成功する可能性はわずかです。たとえそれが無視できるものであっても、0 は常に 0 よりも大きい何らかの値よりも優先されます。

提案されたソリューションが機能しない理由をいくつか追加したかっただけです。

乱数

ここでa を使用しないと、SecureRandomすでに目的が無効になります。法線randを使用すると、乱数が予測可能になるため、非表示のページを「見つけよう」と決心した人は、成功する可能性が高くなります。しかし、安全な乱数を使用している場合でも、ある範囲の数値で均一に分散されたページを「広げている」だけです。最終的にアプリに到達するレコード/ページが多いほど、ランダムに推測するだけの攻撃者が最終的に成功する可能性が高くなります。

UUID

攻撃者がそれらがどのように構築されているかがわかれば、それらは簡単に推測できます。それらは決定論的スキームに従って構築されているため、ランダム性にはセキュリティがありません。

暗号化/ハッシュ

ここで暗号化を使用するのは間違っています。可逆であり、その必要がないという意味では間違っています。なぜなら、それは実際に防止しようとしているからです。認証された暗号化を使用していない限り、結果の暗号文は可鍛性があるため、攻撃者が使用されたキーを知らなくても、禁止されたページに侵入できる可能性が高くなります. 鍵を回復しようとする可能性のある多数の攻撃は言うまでもありません。したがって、より良い解決策は、適切にランダム化された安全なハッシュ関数を使用することです。静的ソルトの使用は、パスワードに十分でないのと同じ理由で十分ではありません: 辞書を事前計算する能力を最小限に抑えるには、ID ごとのソルトの方が適しています。事前計算は非常に簡単です。あらゆる種類のソルトを使用して ID の 1 ~ 100 のテーブルを計算することは、実際には有望な戦略です。

しかし、どんなに頑張っても、推測するだけでアクセスできる可能性は常にあります。Sergio が既に述べたことをまとめると、実際に必要なのは認証とアクセス制限の実装です。

データのサイズを隠したい場合は、代わりにタイムスタンプを使用してみませんか? いずれにせよ、データベース ID はそのままにして、URL に表示したいもの用の特別な「表示 ID」列を追加しますが、元の ID を主キーとして残します。

于 2012-05-28T15:35:17.900 に答える
1

恥知らずなプラグイン: https://github.com/dividedmind/pg_random_id

gem を入れて、readme に従ってマイグレーションを追加するだけで完了です。これはシーケンスのスクランブルに基づいているため、衝突が発生しないことが保証されています。ランダムな整数または文字列 ID を持つことができます。

于 2013-02-10T07:40:24.077 に答える
0

これは称賛に値する目標ですが、ID 列を自動インクリメント整数から変更するのはおそらく間違いです。突き詰めると、ID 列はデータベースでのみ使用する必要があります。これにより、データベースはリレーションを公開し、レコードを個別に見つけることができます。ID 列を使用して、私がビジネス ロジックと見なすものの一部を公開しようとしています。つまり、モデルに本質的にランダムな参照番号が必要です。そして、そのビジネス ロジックが変更されると、ID 列を変更したくなるでしょう。これにより、外部キーが失われ、おそらく大きな頭痛の種になるでしょう。

この目標を達成するには、「数値」などと呼ばれる新しい列を作成し、これらの戦略のいずれかを実装する必要があります。その後、新しい戦略に移行する必要がある場合は、移行がはるかに簡単になりModel.find(id)ますModel.find_by_number(number)

于 2012-05-28T15:04:53.070 に答える