web-dev-qa-db-ja.com

リバースエンジニアリングできない順次識別文字列(「請求書番号」の問題)

猫の写真を作成できるサイトを運営しているとしましょう。私はすべての猫の写真に一意の識別子を付け、http://catpictures.com/base62Identifierを使用してソーシャルメディアで共有できるようにします。

猫の写真に1、2、3などの連続した識別子を与えることもできますが、ユーザーが1日に作成する新しい猫の写真の数を(毎日HTTP 200を返す最大の識別子によって)簡単に見つけることができます。これにより、競合他社に月に1回製品を注文し、請求書番号を書き留めるという一般的な戦略がわかります。ウェブサイトのトラフィックの数値はビジネスの収益とよく相関しているので、この情報を秘密にしたいと思います。

私がしようと考えていること:

これはハッシュアルゴリズムの仕事のように聞こえますよね?問題は、ハッシュを観察することで、どのアルゴリズムがそれを作成したか(md5、crc32など)を判別するのが非常に簡単です。レインボーテーブルを持っている人は、そのアイデアを簡単に解決するでしょう。識別子[hash( "salt" +1)、hash( "salt" +2)、...]をソルトすることもできますが、その場合、ソルトに関連するセキュリティについて心配する必要があります。そして衝突チェック。

もう1つのアイデアは、ランダムな文字列を生成し、それをデータベース内の猫の画像の主キーとして使用することでした(または、猫の画像データの最初のnビットをハッシュすることもできました)。この方法では、衝突をチェックするだけで済みます。

一意の識別子のURLを介してトラフィック量を公開しないようにするための標準的なベストプラクティスの方法はありますか?

編集:データベースの主キーまたはインデックス可能な列としてのセキュリティと適合性の良い組み合わせであるソリューションを具体的に探しています。

52
Escher

この種の問題に対する標準的なアプローチは、各画像に対して ID(Universally Unique Identifier) を作成することです。これは通常、ランダムな128ビットの識別子であり、名前空間に対するブルートフォース攻撃を介して画像を列挙することが可能であるという特定の懸念なしに、各画像に割り当てることができます。

たとえば.NETでは、このような目的で [〜#〜] guid [〜#〜] 構造を使用できます。 Windows 2000以降ソース )、Guid.NewGuidはランダムな(バージョン4)UUIDを生成します。 (古いバージョンでは バージョン1 UUID が生成されましたが、これは生成された日付を示し、「請求書番号」の問題からユーザーを保護するために何もしていません。)

78
Rory McCune

単純に画像ハッシュを使用します。あなたが使ったハッシュを誰かが理解していることの何が問題になっていますか? 「URLのこの部分がsha1のように見える」と思った場合、ファイルをダウンロードするとthat sha1が含まれています。しかし、それでも私はあなたの"猫のセキュリティ"を破ることはできません。ハッシュを解読して画像を理解することができたとしても、単にダウンロードするのではなく、それを試みても意味がありません。

30
Ángel

画像データの暗号で保護されたハッシュを生成し、それを識別子として使用するだけです。

これには2つの副作用があります。

  • ハッシュ付きの画像を要求することで、サービスに画像がすでに存在するかどうかを知ることができます。
  • 重複した画像をアップロードすることはできません。

これらの影響はどちらも本質的に悪いものではありません。彼らも便利になるかもしれません。しかし、それらを避けたい場合は、安全な乱数ジェネレータからの疑似乱数で各画像ハッシュをソルトすることができます。

ちなみに、衝突は心配する必要はありません。 SHA256のようなハッシュ関数を使用すると、 ランダムな衝突が発生する可能性は天文学的に非常に小さいため、1つが見つかると不思議です

14
Philipp

標準的な方法は、暗号で保護された疑似乱数ジェネレータ(CSPRNG)を使用して、ランダムにURLを生成することです。

ハッシュなどは必要ありません-単純な古い乱数を使用してください。それらはGUIDである必要もありません(データベースが何らかの理由で単純な数値よりもGUIDをよりよく処理する場合を除きます)。おそらく、あなたのサイトは各URLでアクセス可能な画像をすでに記憶しているので、連続したURLではなくランダムなURLを処理するように変更するだけです。

128ビットの乱数は十分な長さにする必要があります。

新しい画像を処理するときは、URLの重複を必ず確認してください。

9
user253751

質問、コメント、その他の回答で読んだことから、すべてのものが写真ごとに一意の識別子を見つけることに変わり、これは推測できず、写真の数に関する情報も提供されず、データベースで簡単に処理できます。

次に、挿入のタイムスタンプ(1970年からのミリ秒数)を使用しないのはなぜですか。 2人が非常に同じミリ秒で猫の写真を挿入する可能性がある場合は、そのミリ秒の挿入数に対応する連番と連結できます。

そうすれば、誰かが最後の写真を積極的に検索することで見つけられる唯一のことは、誰かが写真を追加した最後の日であり、そのようなジャークに毎日のDOS攻撃のように見せることです。

その間、衝突やデータベースのサポートについて心配する必要はありません。

8
Aldian

代替ソリューション:

画像識別子にメタデータを追加します。例:

philipp_20151213_00002.jpg-ユーザーPhilippが2015年12月13日に投稿した2番目の画像。

私はそのメタデータをリークしますが、それはユーザーがそのリンクをクリックしたときにとにかく見ることができるデータだけです(私は推測します)。

これはオブザーバーに、サービスに投稿された画像の合計数を通知するのではなく、その日の特定のユーザーのアクティビティについてのみ通知します。これも隠したい場合は、連番の代わりに疑似乱数を使用できます。 1人のユーザーが1日に非常に大量の画像をアップロードした場合でも衝突が発生する可能性がありますが、実際には、ランダムな数がなくなるまで新しい乱数を生成するだけで処理できるほどまれです。

6
Philipp

これが1つの方法です。サーバー全体で8バイトのCSPRNGを保持します。次に、新しい画像ごとに、別の8バイトのCSPRNGを生成します。このCSPRNGをサーバー全体のCSPRNGでハッシュします(md5は問題ありません)。次に、XOR画像IDを含むハッシュの最後の8バイト(データベースで0から自動インクリメントされます)。クライアントは、画像の一意の8バイトCSPRNGのBase64エンコーディングを受け取ります。 8バイトXOR結果。これは公開イメージIDになります。

サーバーが公開イメージIDを受信すると、サーバー全体の8バイトのCSPRNGとともに、公開IDの最初の8バイトをハッシュします。次に、ハッシュの最後の8バイトを取得し、XORパブリックIDの最後の8バイトを使用します。結果は、データベースからインデックスを作成できるプライベート内部IDになります。

更新(説明):

まず、すべてのID計算に使用されるランダムなグローバルCSPRNGを事前定義します(8バイトまたは64ビット、18,446,744,073,709,551,616の可能な組み合わせ)。

serverCSPRNG = CSPRNG(8)

PrivateID(8バイト)から新しいパブリックID(16バイト)を作成するには、次のようにします。

newCSPRNG = CSPRNG(8)
hashEnding = last8Bytes(md5(newCSPRNG + serverCSPRNG))
publicID = newCSPRNG + XOR(hashEnding, privateID)

PublicIDからprivateIDを派生させる場合:

hashEnding = last8Bytes(md5(first8Bytes(publicID) + serverCSPRNG))
privateID = XOR(hashEnding, last8Bytes(publicID))

セキュリティを強化するために、ブルートフォース攻撃から完全に保護するために、publicIDの最後の8バイトでセカンダリグローバル(静的サーバーのみ)CSPRNGをXORすることができます(1つに固有のセキュリティモデルを実装しているため)。タイムパッド)。

1
Jonathan Gray

前述のように here :ハッシュ、UUIDなどには、これらのハッシュ/ uuidがPKであり、PKがクラスター化されているDBへのレコードの挿入は非常に高価である(定義が高価)という「欠点」があります。 。)それらは通常順次ではないので( NEWSEQUENTIALID のような特定の関数が使用されている場合を除きますが、そのページの「重要な」ブロックに注意してください:「プライバシーが懸念される場合は、この関数を使用しないでください。次に生成されるGUIDの値を推測できます... ")。

ここでの提案とは別に、Twitterの( 廃止snowflake のようなものを検討します。私は同様の.Netライブラリ( IdGen );を作成しました。 Readmeには、正確に機能する方法に関する情報が記載されています。利点は、生成されたIDが(ほとんど)シーケンシャルであり、スペースをあまり消費しない(64ビットv.s. 128ビットUUID /ハッシュ)ものであり、衝突を引き起こすことなくIDを生成する複数のホスト/プロセスがある(調整されていない)分散環境で使用できることです。そして、それらは連続的ですが、一定期間の猫の写真の数(または、より一般的には、「使用されたID」の数)に関する多くの情報を提供しません。

1
RobIII

これは、ハッシュアルゴリズムの仕事のように聞こえますよね?

いいえ、あなたが観察するようにあなたは衝突を心配する必要があるので。私にとっては、順列、つまりブロック暗号の仕事のように思えます。これにはマイナス面であるキーの管理が必要ですが、データベースの自動インクリメント機能を使用でき、衝突を心配する必要がありません。

トリッキーな部分はIVについて何をするかを決めることであり、ここにはオプションがあります。 URLを作成するたびに新しいURLを生成できるので、たとえば、猫の写真ごとに2 ^ 128個の異なるURL。 IVをユーザーごとまたはセッションごとに作成し、ユーザープロファイル/セッション状態の一部としてサーバー側に保存することができます。ユーザーごとに作成することもできますが、URLに含めることで、写真が口コミで広まった人物を追跡できます。

1
Peter Taylor

問題:

  • 連番の番号が必要です。そうしないと、インデックスの途中をほとんどランダムな順序で更新する必要があるため、データベースにレコードを追加するのにコストがかかります。
  • アップロードされた猫の数とは関係がありません。
  • 番号は一意である必要がありますが、Webサイト内のみです。

したがって:

  • nextCatは、Webサイトfirstの起動時に0に設定されます。64ビットである必要があります。
  • nextCatは、猫が追加されるたびにincrementedであり、newCattrueに設定されます。
  • nextCatはランダムなタイマーによるincrementedであり、猫が追加されると予想するよりも速い速度で起動します。ただし、newCattrueの場合、このタイマーの起動に対してインクリメントは行われず、newCatfalseに設定されます。
  • 各猫はGUIDも与えられますが、GUIDに基づいて見つける必要はありません
  • 猫のWebアドレスは、something.com/cats/catNumber-catGuidです。
  • 猫がリクエストされたときにcatGuidが間違っている場合は、猫に関係のないcatNumberに対して同じレスポンスが返されます。

(タイマーはランダムな時間で行われるため、タイマーの起動の間に2匹の猫が追加されたかどうかを判断するのは困難です。)

0
Ian Ringrose

1つのアプローチは hashids を使用することです。

Hashidsは、小さなオープンソースライブラリで、数字から短く一意の非シーケンシャルIDを生成します。

347のような数値を「yr8」のような文字列に、または[27、986]のような数値の配列を「3kTMd」に変換します。

これらのIDをデコードして戻すこともできます。これは、いくつかのパラメーターを1つにバンドルする場合、または単にそれらを短いUIDとして使用する場合に役立ちます。

内部で連続した数値のIDを引き続き使用できるため、DBのパフォーマンスは低下しません。一方、外部キーは不透明です。

0

この問題に対するローテクな解決策があります。 URL短縮サービスを使用するか、独自のサービスを作成してください。

以下を提供します。

  1. パブリックURLがソーシャルメディアサイトに公開されていません。
  2. URLはランダムで任意であることが保証されています。
  3. リソースの命名の基礎となる実装は自由に変更でき、外部リンクは引き続き機能します。
  4. 共有が簡単http://catpic.to/i34dhYhttp://catpictures.com/some-guid-string
  5. 一意のIDは簡単にインデックス付け/検索されます。

サードパーティのサービスに依存したくない場合は、お好みの言語で 全単射関数 を実装することにより、独自のサービスを簡単に導入できます。

0
Burhan Khalid