主キーを公開しないのはなぜですか


53

私の教育では、実際のプライマリキー(DBキーだけでなく、すべてのプライマリアクセサー)をユーザーに公開することは欠陥のあるアイデアであると言われました。

私はいつもそれをセキュリティの問題だと思っていました(攻撃者が自分のものではないものを読もうとする可能性があるため)。

ユーザーがとにかくアクセスを許可されているかどうかを確認する必要があるので、その背後に別の理由がありますか?

また、とにかくユーザーがデータにアクセスする必要があるため、その間のどこかに外部の公開キーが必要になります。公開キーには主キーと同じ問題がありますよね?


とにかくそれを行う理由についての例の要求があったので、ここに1つがあります。質問は、この例に当てはまる場合だけでなく、原則自体に関するものであることを忘れないでください。他の状況に対処する回答は明示的に歓迎されます。

アクティビティを処理し、複数のUIとシステム間通信用の少なくとも1つの自動APIを備えたアプリケーション(Web、モバイル)アプリケーションには複数の顧客がいるため、データの分離(論理的には、データは同じDBに格納されます)はシステムに必要です。各リクエストは、どのような場合でも有効性がチェックされます。

アクティビティは非常に細かいので、いくつかのコンテナオブジェクトにまとめられ、「タスク」と呼びます。

3つのユースケース:

  1. ユーザーAは、ユーザーBを何らかのタスクに送りたいので、ユーザーBにリンク(HTTP)を送信して、そこでアクティビティを実行させます。
  2. ユーザーBは建物の外に出て、モバイルデバイスでタスクを開く必要があります。
  3. アカウンティングは顧客にタスクの料金を請求したいが、REST-アプリケーションのAPIを参照するコードによってタスク/アクティビティを自動的にロードするサードパーティの会計システムを使用する

各ユースケースでは、エージェントがタスクとアクティビティのアドレス可能な識別子を持っていることが必要です(または、より簡単になります)。


3
関連:代理キーをユーザーに公開する必要がありますか?「あなたは、変更される必要があるユーザー/顧客にさらされている任意の識別子のために準備する必要があり、データベース内の行のIDを変更し、すべての外部キーにその変更を伝播することは、単にデータを破るために求めています...」
gnat

@gnatはON UPDATE CASCADEそのために作られた、問題はセキュリティである場合は、アクセスチェックがバックエンドにする必要がありますし、とにかくユーザーを信用していないが(mysqlの具体的な?)
Izkata

2
@Izkataええ、ただし、異なるデータストア(単純な例としてLDAPのユーザーID)でそれらを参照する場合、またはバックアップから一部のデータを回復する必要がある場合を除きます。gnatには良い点があります。
アンジェロフックス

「露出」の意味を詳しく説明していただけますか?実際の例が役立つかもしれません。:-)
CodeCaster

「公開」とは、ユーザーに表示することを意味します。(ユーザーによって私は主に人間を意味しますが、質問はマシンにも有効なようです)
アンジェロフックス

回答:


38

また、とにかくユーザーがデータにアクセスする必要があるため、その間のどこかに外部の公開キーが必要になります。

まさに。ステートレスHTTPを使用します。そうしないと、リクエストするリソースがわかりません218306。URLで質問のIDを公開します。おそらく、あなたは実際に公開された識別子が予測可能かどうか疑問に思っていますか?

それに対して否定的な答えを聞いた唯一の場所は、「URLのIDを変更できる!」という論理的根拠を使用しました。。そのため、適切な承認を実装する代わりにGUIDを使用しました。

識別子を予測可能にしたくない状況の1つを想像できます。それはリソースの収集です。他の人が興味を持っているかもしれない特定のリソースを公開してホストしているサイトがあり、それらを同じように、/images/n.jpgまたは増加する数字/videos/n.mp4でホストしている場合、nあなたのウェブサイトへのトラフィックを見る人はすべてのリソースを収穫できます。

だから、あなたの質問に直接答えるために:いいえ、あなたのプログラムに意味があるだけの識別子を直接「公開」することは悪くありません。通常、あなたのプログラムがうまく動作することさえ必要です。


2
推測不可能なURL(たとえば、暗号的にランダムな128ビットトークンを含む)は、適切な承認の1つの形式です。
CodesInChaos

リプレイ攻撃に非常に敏感なように適切ですか?パスワードリセットURLのような1回限りの使用には便利ですが、静的リソースを特定するためには、トークンが公開されると誰でも使用できるため、正当な参照を壊すことなく変更することはできませんそれ。
CodeCaster

ん?明らかにSSLが必要ですが、どのように認証および認可しても関係ありません。SSLを介して攻撃者はトークンを学習できず(Cookieを学習できないように)、リプレイ攻撃も防ぎます。このアプローチの主な欠点は、個々のユーザーのアクセスを取り消せないことです。したがって、不変のリソースにのみ使用することを好みます。攻撃者は単にローカルコピーを保存できるため、不変リソースへのアクセスを取り消すことは無意味です。
CodesInChaos

2
最近、私が言いたいことを実際に表現することができないようです。ごめんなさい。リソースをパブリックにアクセス可能にしたいが推測できないようにしたい場合、増分IDではなく、静的リソースにランダムトークンを使用することは問題ありません。他の用途では、取消しの理由により、1回限りの使用を希望します。
CodeCaster

1
なし、私のポイント。「露出」とはどういう意味ですか?
CodeCaster

29

それを見る人々はそれが彼らの「口座番号」としてそれを使用し始めるのでそれを露出するべきではない。たとえば、私の銀行口座については、口座番号が何であるかを知っています。覚えておいて、電話でカスタマーサービスと一緒に使用します。他の銀行が送金するためにフォームを記入するとき、法律文書、自動支払いサービスなどのために使用します。それは変わります。一方、(私のアカウントの)主キーは、私にはわかりません。
それを保存するシステムは、銀行の合併、システムのアップグレードおよび交換などを通じて、あるシステムから別のシステムへと長年にわたって変化します。
主キーはこれらの変換の一部によって変化する可能性があります。通常のユーザーが
ビジネス上の意味を持たないキーは、しばしば代理キーと呼ばれ、主キーとして(常にではありませんが)よく使用されます。

ところで、これは、主キーを誤用して公開するインターフェイスやプログラムを作成し、それらを1つのことだけでなくそのようなシステムの一部にすることで、データベースレコードを内部的に一意に識別するときにも発生します。私は実際に、病院のデータウェアハウスシステムをサポートする6年間のスティントを通じて上記のことを学びました。


4
+1ですが、ここで説明しているのは実際には代理キーです。すべてのテーブルに代理キーがあるわけではありません。代理キーがある場合でも、代理キーが「プライマリ」キーではない場合があります。
nvogel

2
+1アカウント番号が代理キーになると思ったが、それを読み上げて、あなたは100%正しい:)
マイケルデュラント

2
+1をユーザーに公開すると、暗黙的な要件が追加されます(静的なままなど)
Matt

1
素晴らしい答え。私がこれを簡単に言うと、代理キーは有用だということです。だれもそれらを気にしないので、あなたがそれらを変更しても変更しなくても誰も気にしません。それらを公開すると、人々はそれらを気にし始めます。
ジミージェームズ

tl; dr:未来だから。外部の何かがキーに依存するようになった場合、実装が後で変更されると事態は面倒になります。多少なりとも非表示にして、物事を簡単にします。
アダムトルリー

27

主キーは実装の詳細であるためです。

データベースを移行する場合、古いレコードの挿入、削除の順序などにより、主キーが変わる場合があります。いくつかの理由があります。データベースプラットフォームを移行すると、実際の主キーがまったくなくなる場合があります。データアクセス層の上にPKを公開することは、リーキーな抽象化であり、それに伴うすべてのカップリングの問題を伴います。


3
アプリケーション層は、主キーなしでデータ層から取得または更新するリソースをどのように一意に識別しますか?
CodeCaster

2
@CodeCaster-データの一意のインデックス付きセット、またはデータアクセスレイヤーによって提供されるオブジェクトの一部として返される非公開主キーによって。
テラスティン

1
@CodeCaster-コールバックが実行する操作を指定できるトークンを作成する方法はたくさんありますが、すべてのキーが主キーをそのまま渡すわけではありません。
テラスティン

2
ただし、そのためには、データレイヤーがどのトークンがどのPKに属する(または変換される)かを知る必要があります。私には、PKを隠すためだけに、不必要な複雑さの追加レイヤーのように聞こえます。建築家を満足させる以外に、それはどのような目的に役立ちますか?私はあなたの主張に同意します、私はそれが実際の使用法に適用できるとは思わないので、実際の例を感謝します。
CodeCaster

1
@CodeCaster-いいえ、中間層は実際に仕事をし、UIからのデータアクセスがあることを抽象化します。世界には多くの悪いアーキテクトがいますが、プログラム設計のベストプラクティスの多くは理由があります。一部のアプリは、その漏れやすい抽象化のリスクを取ることができますが、できないものもあります。
テラスティン

10

これは、他の回答と組み合わせた回答です(別名。私が学んだこと)。これに賛成票を投じたいと思うなら、少なくとも実際の作業を行ったのと同様に、他の1つにも賛成する必要があります。より興味がある場合は、代わりに他の回答をお読みください。

データベースの主キーを公開するのではなく、代理キーを使用する必要があります

  1. ユーザーがエントリの識別子を(少なくとも少し)覚えたり、認識できるようにしたい場合。(Graystone28s回答
  2. 事前に計画し、PKを変更する可能性のあるシステム(データベースなど)を変更する可能性があることを考慮したい場合。(テラスティンズ回答
  3. 会社が所有権を変更し、データが完全に別のシステムに移行された場合でも、ユーザーが変更されないデータに一貫した方法でアクセスできるようにする場合。(マイケルデュランツ回答
  4. PKが(シーケンスのように)予測可能な場合、システムはリソース獲得の問題に悩まされる可能性があります。(CodeCasters Answer)これは、システムに収穫する価値のある情報があり、だれか、または少なくとも収穫に興味がある人がアクセスできる場合にのみ適用されます。

注:作成するキーは、(やや)人間が理解できるものでなければなりません(Sqlvogels Answer)。

システムに1.〜4.が必要ない場合、データベースPKを公開識別子として使用しない理由はありません(いくつかの回答)。また、セキュリティはここでは問題になりません(いくつかの回答)。


8

私が見つけた理由の1つは、エンドユーザーが自分の識別子が何かを意味することを要求する時間をたっぷり見てきたことです(プレフィックスや、受信した年のインジケーターなど)。PKを変更するのは難しいですが、サロゲートははるかに簡単です。

主キーは、パフォーマンス上の理由でデータベースのインデックスを作成するものである可能性が高く、技術的な理由で、たとえば数値からGUIDに変更する場合があります...新しい技術や知識の理由がわからないだけですあなたを導くかもしれません。pkはデータの技術的なアイテムであり、公開キーはエンドユーザーが使用するためのものです。


7
質問:「主キーを公開するのは悪いことですか?」。あなたの答え:「ユーザーは独自の識別子を持ちたいかもしれません」。私は関係を得られません。を公​​開しますInvoiceNumber。これは顧客にとって意味があり、顧客が変更InvoiceIDできますが、請求書を一意に識別するためにコードが使用するを公開します。あなたがする必要はありません(と、より頻繁にしないでくださいしたいために)ユーザー・キーは、ストレージ・キーとします。この質問は後者についてです。
CodeCaster

APPのマルチテナントバージョンに移行する場合、同じ構文を維持し、同じInvoiceNumber(複数のテナントに対して)複数の請求書を持つことができますが、異なるプライマリキーを持つことができるので、これは良い例だと思います-ポイント(種類)回答にも記載されています。
14:43に

1
@CodeCasterこの質問は、実際には「なぜあなたはそれらを同じにしたくないのですか」についてですか?
アンジェロフックス

その場合は、Telastynsの回答を参照してください。
CodeCaster

2

ほとんどのアプリケーションでは、ユーザーにキーを公開することが非常に重要です。情報システムを効果的に使用するには、そのシステムのユーザーは通常、システム内の情報を識別し、その情報をデータベース外の世界の何かに関連付ける方法を必要とします。リレーショナルデータベースの用語では、これらの識別子はキーです。

よく使用される設計パターンの1つは、抽象化の手段として、データベーステーブルに追加の純粋に「技術的な」キーを作成することです。たとえば、いくつかの代替キーが変更される可能性がある安定した(比較的変化しない)キーを提供します。通常、このような技術キーは、ユーザー要件から意図した抽象化を損なうため、エンドユーザーには公開されません。セキュリティとは関係ありません。

あなたの質問に潜在する問題/誤解は、キーという用語の不適切な使用によるものです。主キーは、いくつかの「候補」キー(データベーステーブル内のいくつかの可能な識別子)のうちの1つにすぎません。主キーは、他のキーとは根本的に異なるプロパティを必ずしも必要としないため、主キーにのみ適用され、他のキーには適用されないアサーションと設計原則は常に疑わしく、しばしば間違っています。

通常、ユーザーにキーを公開する必要がある場合、そのキーはどうあるべきでしょうか?キーを使い慣れたシンプルで安定したものにしてください。親しみやすさとシンプルさにより、キーの読み取りと記憶が容易になり、データ入力エラーの回避に役立ちます。安定性とは、キーの変更がめったに行われないことを意味し、誤認の可能性を回避するのにも役立ちます。


1
それは...何に依存しますか?その一般的な概念の背後にある理由を知り、それをいつ適用するのか、しないのかを知りたい。
アンジェロフックス

1
こんにちは。お客様のIDを教えてください。確かに、そのgfds789gxb3456bgfx789fgh98076hytd6734nhg5678nghf875nhgf456。うーん、あなたのソーシャルはどうですか?...サロゲートID
マイケルデュラント

@Michael、回答が更新されました。それは使い慣れた、シンプルで安定したキーですか?
nvogel

1

これは、CodeCasterによるGreystone28の回答に対するコメントからです。それはあなたが言っていることの例です:

InvoiceNumberを公開します。これは、顧客にとって意味があり、顧客が変更できますが、InvoiceIDも公開します。これは、コードが請求書を一意に識別するために使用します。ユーザーキーをストレージキーにする必要はありません(また、したくない場合もあります)。この質問は後者についてです。

InvoiceIDを表示することは、アプリのどのような目的に役立ちますか?

公開するということは、ユーザーがそれを見ることができるということです。ユーザーがアプリを使用する必要がある場合にのみ公開してください。テクニカルサポートまたは管理スタッフが使用できます。これを行ういくつかのアプリで作業しました。問題の特定のレコードを知っているときにサポートを提供するのが簡単になります。


請求書には自然な識別子(番号)がありますが、それはあなたが書いたもののみです。あなたが得るものはどうですか?InvoiceNumbersはありますが、重複しています(2つの会社が同じ会社を使用しており、両方が請求書を送信しているため)。この状況では、InvoiceIDは一意であり、Numberは一意ではなく、一意にするのはデータの適切な識別子ではないCustomernameです(長すぎる、頻繁に変更される、あいまいな文字が含まれる可能性があります...)
Angelo Fuchs

@AngeloNeuschitzer-ユーザーが顧客の名前と番号で請求書を一意に識別できる場合、ユーザーはInvoiceID PKを必要としませんが、データベースと基になるコードはそれを使用できます。これらは相互に排他的な機能です。
ジェフ

私の例のケース1〜3を参照してください。いずれの場合も、顧客名は、ユーザー(オブジェクトであれ、機械であれ)に対してそのオブジェクトをアドレスする便利な方法です。InvoiceID PKです。
アンジェロフックス

1

エンティティが外部の世界に公開される一意の識別子を持つことは完全に正常です。一部のオブジェクトでは、実際に意味を持つ識別子(請求書番号など)を見つけることができるかもしれませんが、他のオブジェクトではそのような識別子が存在しないため、生成する必要があります。

一貫性と読みやすさのために、システム内のすべてのエンティティがまったく同じタイプと名前を識別子に使用することをお勧めします。通常、この識別子は<type> getId()いくつかの抽象基本クラスで公開されます()。

同じ理由で、システム内の各サービス(請求書サービスなど)は、識別子によってエンティティにアクセスするための同一のメソッドを提供する必要があります。通常、このメソッド(findById(<type> id))は汎用サービスインターフェイスまたは基本クラスから継承されます。

この識別子はエンティティの主キーである必要はありませんが、1つでもかまいません。確認する必要があるのは、キー生成戦略が合理的に一意の識別子を生成することです(必ずしもシステム全体で一意である必要はありませんが、少なくともシステム内で)。

システムが後で別のデータベースに移行された場合(私の経験では大きな場合)、戦略が元の戦略と互換性がある限り、識別子を作成するために別の戦略(主キーに基づいていない)を使用しても問題ありません。


他の回答では回答されていないものを説明してください。
アンジェロフックス

2
私の答えでは、少なくともあなたの要約のポイント2と3に同意していません。これらがオブジェクト識別子としてPKを使用しない正当な理由だとは思いません。
ムートン

0

開発者としてアクセスしようとするタプル(レコード、行)のハンドルと同じように、主キーがあります。また、参照整合性(外部キーの制約)でも使用され、1つ以上のユースケースもある可能性があります。

基本的に、ユーザーやハッカーにさらすことについて何も悪いことはありません。たとえば、主キーを使用する攻撃を知らないからです。

しかし、セキュリティでは、多くの原則(承認し、承認しません)があり、それらを遵守する必要があります。

  1. リース特権の原則
  2. あいまいさによるセキュリティ

そして、他のいくつかの原則。彼らが本質的に言うことは:

データを公開する必要がない場合、なぜそうするのでしょうか?


ハンドル部分は私が同意するところです。セキュリティはそうではありません。それは可能性があるセキュリティ関連性があるが、ユーザに表示されていない独立した内部キーを持つことは、セキュリティについては、実際にほとんどありません。私はそれを素晴らしい副作用と呼びます。
JensG

なぜですか:質問に追加した例をご覧ください。
アンジェロフックス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.