기본 키를 공개하지 않는 이유


53

교육 과정에서 실제 기본 키 (DB 키뿐만 아니라 모든 기본 접근 자)를 사용자에게 노출시키는 것은 잘못된 아이디어라고 들었습니다.

공격자가 자신이 아닌 내용을 읽을 수 있기 때문에 항상 보안 문제라고 생각했습니다.

이제 사용자가 어쨌든 액세스 할 수 있는지 확인해야하므로 그 뒤에 다른 이유가 있습니까?

또한 사용자가 어쨌든 데이터에 액세스해야하므로 외부 세계를위한 공개 키가 있어야합니다. 이제 공개 키는 기본 키와 같은 문제가 있습니까?


어쨌든 왜 그런지에 대한 예의 요청이 있었으므로 여기에 하나가 있습니다. 질문은이 예제에 적용되는 경우뿐만 아니라 원리 자체에 관한 것임을 명심하십시오. 다른 상황에 대한 답변은 명시 적으로 환영합니다.

활동을 처리하고, 여러 UI와 시스템 간 통신을위한 하나 이상의 자동화 된 API가있는 애플리케이션 (Web, Mobile) (예 : 회계 부서는 수행 한 작업에 따라 고객에게 청구하는 금액을 알고 싶어 함). 애플리케이션에는 여러 고객이 있으므로 데이터 분리 (논리적으로 데이터는 동일한 DB에 저장 됨)는 시스템에 있어야합니다. 각 요청은 무엇이든 유효성을 검사합니다.

액티비티는 매우 세분화되어 일부 컨테이너 오브젝트에 함께 있으므로 "태스크"라고합니다.

세 가지 사용 사례 :

  1. 사용자 A는 사용자 B를 일부 작업으로 보내서 일부 활동을 수행 할 수 있도록 링크 (HTTP)를 보냅니다.
  2. 사용자 B는 건물 밖으로 나가서 모바일 장치에서 작업을 열어야합니다.
  3. 계정은 고객에게 작업에 대한 비용을 청구하려고하지만 응용 프로그램의 REST-API를 참조하는 일부 코드로 작업 / 활동을 자동으로로드하는 타사 계정 시스템을 사용합니다.

각 유스 케이스에는 에이전트가 태스크 및 활동에 대해 주소 지정 가능한 식별자가 있어야합니다 (또는 더 쉬워집니다).


3
관련 : 대리 키가 사용자에게 노출되어야합니까? "사용자 / 고객에게 노출되는 식별자를 변경해야하며, 데이터베이스에서 행의 ID를 변경하고 해당 변경 사항을 모든 외래 키에 전파하면 데이터가 중단됩니다."
gnat

@gnat는 ON UPDATE CASCADE(MySQL의 특정?) 그 위해 만들어진, 문제가있는 경우 보안이 다음 액세스 검사가 백엔드에 있어야 어쨌든 사용자를 신뢰하지 않지만
Izkata

2
@Izkata 예, 다른 데이터 스토어 (예 : LDAP의 UserID)에서 참조하거나 백업에서 일부 데이터를 복구해야하는 경우를 제외하고는 예외입니다. 모기는 거기에 좋은 지적이 있습니다.
Angelo Fuchs

"노출"의 의미에 대해 자세히 설명 할 수 있습니까? 실제 예가 도움이 될 수 있습니다. :-)
CodeCaster

"노출하다"는 것을 사용자에게 보여주는 것을 의미한다. (사용자에 의해 나는 주로 인간을 의미하지만 질문은 기계에도 유효 해 보입니다)
Angelo Fuchs

답변:


38

또한 사용자가 어쨌든 데이터에 액세스해야하므로 외부 세계를위한 공개 키가 있어야합니다.

바로 그거죠. 요청해야 할 리소스를 모르는 상태 비 저장 HTTP를 가져 와서 218306URL에 질문 ID 를 노출시킵니다 . 아마도 노출 된 식별자가 예측 가능한지 궁금 할 것입니다 .

이에 대한 부정적인 답변을 들었던 유일한 장소는 "그러나 URL에서 ID를 변경할 수 있습니다!"라는 이론적 근거를 사용했습니다 . . 따라서 적절한 권한 부여를 구현하는 대신 GUID를 사용했습니다.

식별자를 예측할 수없는 상황 (자원 수집)을 상상할 수 있습니다. 공개적으로 특정 리소스를 호스팅하는 사이트가 있고 다른 사람들이 관심을 가질 수있는 사이트를 보유하고 /images/n.jpg있거나 /videos/n.mp4n수가 증가하는 위치 와 비슷한 위치에있는 경우 웹 사이트를 오가는 트래픽을 보는 사람은 모든 리소스를 수집 할 수 있습니다.

따라서 귀하의 질문에 직접 대답하기 위해 : 아니오, 귀하의 프로그램에만 의미가있는 식별자를 직접 "노출"하는 것은 나쁘지 않으며, 일반적으로 귀하의 프로그램이 성공적으로 운영되어야합니다.


2
추측 할 수없는 URL (예 : 암호화 임의 128 비트 토큰 포함)은 적절한 권한 부여의 한 형태입니다.
코드 InChaos

재생 공격에 매우 민감한 것처럼 적절합니까? 암호 재설정 URL과 같은 일회성 사용은 좋지만 토큰이 공개되면 누구나 누구나 사용할 수 있기 때문에 정적 리소스를 식별하는 것이 적습니다. 그것.
CodeCaster 10

흠? 분명히 SSL이 필요하지만 인증 및 권한 부여 방법에 관계없이 해당됩니다. SSL을 통해 공격자는 쿠키를 배울 수없는 것처럼 토큰을 배울 수 없으며 재생 공격도 방지합니다. 이 방법의 주요 단점은 개별 사용자에 대한 액세스 권한을 취소 할 수 없으므로 변경 불가능한 리소스에만 사용하는 것이 좋습니다. 공격자가 단순히 로컬 복사본을 저장할 수 있으므로 변경 불가능한 리소스에 대한 액세스 권한을 취소하는 것은 의미가 없습니다.
코드 InChaos

2
요즘 실제로 의미하는 바를 표현할 수없는 것 같습니다. 죄송합니다. 리소스를 공개적으로 액세스 할 수는 있지만 추측 할 수 없도록하려는 경우 증분 ID가 아닌 정적 리소스에 임의 토큰을 사용하는 것이 좋습니다. 다른 용도로는 철회 때문에 일회성 사용을 선호합니다.
CodeCaster

1
아니, 내 요점은 정확히 그렇다면 "노출하다"라는 의미에 대해 자세히 설명해 주시겠습니까?
CodeCaster

29

그것을 보는 사람들이 그것을 '계정 번호'로 사용하지 않기 때문에 노출해서는 안됩니다. 예를 들어, 은행 계좌의 경우 계좌 번호가 무엇인지 알고 있습니다. 나는 그것을 기억하고, 나는 고객 서비스와 함께 전화로 사용하고, 다른 은행이 송금 할 양식, 법률 문서, 자동 지불 서비스 등을 작성할 때 사용합니다. 변경합니다. 반면에 내 계정의 기본 키는 알지 못합니다.
은행 병합, 시스템 업그레이드 및 교체 등을 통해 수년 동안 한 시스템에서 다른 시스템으로 변경 사항을 저장하는 시스템
. 기본 키는 이러한 변환 중 일부를 통해 변경 될 수 있으므로 노출, 기록 또는 기억되지 않은 경우 일반 사용자가
비즈니스 의미가없는 키는 종종 대리 키 라고 하며 종종 기본 키로 사용되는 것은 아닙니다.

btw, 내부 키 데이터베이스를 고유하게 식별하는 기본 키를 오용 및 노출하고 하나의 작업 대신 해당 시스템의 일부로 만드는 인터페이스 및 프로그램을 구축 한 경우에도 내부적으로 발생합니다. 나는 실제로 병원에서 데이터웨어 하우스 시스템을 지원하는 6 년 동안 위의 내용을 배웠습니다.


4
+1이지만 여기서 설명하는 것은 실제로 서로 게이트 키입니다. 모든 테이블에 서로 게이트 키가있는 것은 아니며 서로 게이트 키가 있어도 "기본"키가 아닐 수 있습니다.
nvogel

2
+1 나는 계좌 번호가 대리 열쇠가 될 것이라고 생각하지만 난 그것을 읽어 당신은 100 % 정확한 :)이다
마이클 듀런트

2
+1 사용자에게 노출 +1 암시 적 요구 사항 추가 (예 : 정적 상태 유지)
Matt

1
좋은 대답입니다. 이것을 말하는 나의 짧은 방법은 아무도 키를 신경 쓰지 않으므로 키를 변경하거나 변경하지 않으면 아무도 신경 쓰지 않기 때문에 대리 키가 유용하다는 것입니다. 노출하면 사람들이 관심을 갖기 시작합니다.
JimmyJames

tl; dr : 미래 때문에. 외부에서 무언가가 키에 의존한다면 나중에 구현이 변경되면 문제가 발생합니다. 일을 더 쉽게하기 위해 그것들을 다소 숨겨 두십시오.
Adam Tolley

27

기본 키는 구현 세부 정보이므로

데이터베이스를 마이그레이션하는 경우 삽입 순서, 오래된 레코드 제거 등 몇 가지 다른 이유로 기본 키가 변경 될 수 있습니다. 데이터베이스 플랫폼 을 마이그레이션 하면 더 이상 실제 기본 키가 없을 수 있습니다. PK를 데이터 액세스 계층 위에 노출시키는 것은 누출이 발생하는 것이며, 모든 커플 링 문제가 수반됩니다.


3
응용 프로그램 계층은 기본 키없이 데이터 계층에서 검색하거나 업데이트하려는 리소스를 어떻게 고유하게 식별합니까?
CodeCaster

2
@CodeCaster-고유 한 인덱스 데이터 집합 또는 데이터 액세스 계층에서 제공 한 개체의 일부로 반환되는 비공개 키를 사용합니다.
Telastyn

1
@CodeCaster-콜백에서 수행 할 작업을 지정할 수있는 토큰을 생성하는 방법에는 여러 가지가 있으며 반드시 기본 키를 모두 전달하는 것은 아닙니다.
Telastyn

2
그러나이를 위해서는 데이터 계층이 어느 토큰이 어느 PK에 속하는지 (또는 그로 변환되는지) 알아야합니다. 나에게 그것은 단지 PK를 숨기기 위해 불필요한 복잡성의 추가 층처럼 들린다. 건축가를 만족시키는 것 외에 어떤 목적이 있습니까? 나는 당신의 요점에 동의하며, 실제 사용에 적용 할 수는 없으며 실제 예를 높이 평가할 것입니다.
CodeCaster

1
@CodeCaster-아니요, 중간 계층은 실제로 작업을 수행하고 UI에서 데이터 액세스가 있다는 것을 추상화합니다. 세계에는 나쁜 건축가가 많이 있지만, 프로그램 디자인의 모범 사례 중 많은 것이 이유가 있습니다. 일부 앱은 유출이 발생할 위험이 있으며 일부는 그렇지 않습니다.
Telastyn

10

이것은 다른 것들 (일명 배운 것)의 조합 답변입니다. 이 중 하나를 찬성하는 느낌이 든다면 적어도 다른 한 쪽을 찬성하고 실제 작업을 수행해야합니다. 더 관심이 있으시면 다른 답변을 읽으십시오.

데이터베이스 기본 키를 공개하지 말고 대신 대리 키를 사용해야합니다.

  1. 사용자가 항목의 식별자를 기억 (적어도 약간)하거나 인식 할 수있게하려면 ( Graystone28s 답변 )
  2. 미리 계획하고 PK가 변경 될 수있는 시스템 (데이터베이스 또는 기타)을 변경할 수 있다고 생각하는 경우. ( Telastyns 답변 )
  3. 회사가 소유권을 이전하고 다른 시스템으로 데이터를 마이그레이션하더라도 사용자가 일관되게 변경되지 않는 데이터에 액세스 할 수 있도록하려면 ( Michael Durrants 답변 )
  4. PK가 (시퀀스와 같이) 예측 가능한 경우 시스템에 자원 수확 문제가 발생할 수 있습니다. ( CodeCasters Answer ) 이는 시스템에 수확 할 가치가 있고 수확 관심이있는 사람 또는 누군가가 액세스 할 수있는 정보가있는 경우에만 적용됩니다.

참고 : 생성 된 키는 (kinda) 사람이 이해할 수있는 것이어야합니다 ( Sqlvogels Answer ).

시스템에 1-4가 필요하지 않은 경우 데이터베이스 PK를 공용 식별자 (여러 답변)로 사용하지 않을 이유가 없습니다. 또한 보안은 여기서 문제가되지 않습니다 (여러 답변).


8

내가 찾은 한 가지 이유는, 최종 사용자가 자신의 식별자가 접두사 나 그 해가 들어간 연도의 지표와 같은 것을 의미한다고 최종 사용자가 요구하는 것을 보았습니다. PK 변경은 어렵지만 대리가 훨씬 쉽습니다.

기본 키는 아마도 성능상의 이유로 데이터베이스 인덱싱을 원하는 것일 수 있으며 기술적 인 이유로 인해 예를 들어 숫자에서 길드로 변경할 수 있습니다. 새로운 기술이나 지식의 이유를 모릅니다. 당신을 안내 할 수 있습니다. 귀하의 pk는 기술 데이터 항목이며 공개 키는 최종 사용자가 사용하는 것입니다.


7
질문 : "기본 키를 노출하는 것이 좋지 않습니까?" . 귀하의 답변 : "사용자는 자신의 식별자를 원할 수 있습니다" . 나는 관계가 없습니다. 나는 InvoiceNumber고객에게 의미가 있고 변경할 수있는 노출하지만 InvoiceID코드도 인보이스를 고유하게 식별하는 데 사용합니다. 사용자 키를 스토리지 키로 설정 하지 않아도되며 더 자주 원하지 않습니다 . 이 질문은 후자에 관한 것입니다.
CodeCaster

APP의 다중 테넌트 버전으로 이동하면 동일한 구문을 유지하고 동일한 InvoiceNumber(다른 테넌트의 경우) 동일한 송장을 여러 개 가질 수 있지만 기본 키는 다릅니다. )도 답변에 언급되었습니다.
14시 43 분

1
@CodeCaster이 질문은 실제로 "왜 당신이 같은 것을 원하지 않습니까"에 관한 것입니까?
Angelo Fuchs

이 경우 Telastyns answer를 참조하십시오 .
CodeCaster

2

대부분의 응용 프로그램에서는 키를 사용자에게 노출시키는 것이 매우 중요합니다. 정보 시스템을 효과적으로 사용하려면 해당 시스템의 사용자는 일반적으로 정보를 식별하고 해당 정보를 데이터베이스 외부 세계의 정보와 연관시키는 방법이 필요합니다. 관계형 데이터베이스 용어에서 이러한 식별자는 키입니다.

잘 사용되는 디자인 패턴 중 하나는 추상화 수단으로 데이터베이스 테이블에 대한 추가 "기술적"키를 작성하는 것입니다. 예를 들어 일부 대체 키가 변경 될 수있는 안정적인 (상대적으로 변하지 않는) 키를 제공합니다. 이러한 기술 키는 일반적으로 최종 사용자에게 노출되지 않습니다. 그렇게하면 사용자 요구 사항의 의도 된 추상화가 손상되기 때문입니다. 보안과는 아무런 관련이 없습니다.

질문에 내재 된 문제 / 오해는 기본 키라 는 용어를 부적절하게 사용했기 때문 입니다. 기본 키는 여러 "후보"키 중 하나입니다 (데이터베이스 테이블에서 여러 가지 가능한 식별자). 기본 키는 다른 키와 근본적으로 다른 속성을 요구할 필요가 없으므로 기본 키에는 적용되고 다른 키에는 적용되지 않는 어설 션 및 디자인 원칙은 항상 의심스럽고 종종 잘못된 것입니다.

일반적으로 사용자에게 키를 공개해야한다면 그 키는 무엇이어야합니까? 친숙하고 간단하며 안정적으로 키를 만드십시오. 친숙 함과 단순성으로 키를 쉽게 읽고 기억할 수 있으며 데이터 입력 오류를 피할 수 있습니다. 안정성은 중요한 변경이 드물게 발생하여 잘못 식별 할 가능성을 방지하는 데 도움이됩니다.


1
그것은 무엇에 달려 있습니까? 언제 적용 할 것인지 아닌지를 알기 위해 일반적인 개념의 이유가 무엇인지 알고 싶습니다.
Angelo Fuchs

1
안녕하십니까, 도와 드릴 수 있도록 ID를 알려주십시오. 물론 gfds789gxb3456bgfx789fgh98076hytd6734nhg5678nghf875nhgf456입니다. 흠, 당신의 사회는 어떻습니까? ... 대리 id
마이클 Durrant

@ 마이클, 답변이 업데이트되었습니다. 친숙하고 간단하며 안정적인 키입니까?
nvogel

1

이것은 CodeCaster의 Greystone28의 답변에 대한 의견입니다. 그것은 당신이 말하는 것의 예입니다 :

고객에게 의미가 있고 변경할 수있는 InvoiceNumber를 공개하지만, 코드에서 청구서를 고유하게 식별하는 데 사용하는 InvoiceID도 공개합니다. 사용자 키를 스토리지 키로 설정하지 않아도되며 더 자주 원하지 않습니다. 이 질문은 후자에 관한 것입니다.

앱에서 InvoiceID를 표시하는 목적은 무엇입니까?

노출함으로써 사용자가 볼 수 있다고 가정합니다. 사용자가 앱을 사용해야하는 경우에만 노출하십시오. 기술 지원이나 일부 관리 도구로 사용할 수 있습니다. 이 작업을 수행하는 몇 가지 앱으로 작업했습니다. 문제의 특정 기록을 알면 쉽게 지원을 제공 할 수 있습니다.


인보이스에는 고유 식별자 (숫자)가 있지만 작성하는 식별자 만 있습니다. 당신이 얻는 것은 어떻습니까? 인보이스 번호는 있지만 두 회사가 동일한 회사를 사용하고 두 회사가 모두 인보이스를 보내므로 중복됩니다. 이 상황에서 귀하의 InvoiceID는 고유하고, 숫자는 고유하지 않으며, 고유하게 만드는 것은 데이터에 대한 좋은 식별자가 아닌 Customername이됩니다 (너무 길고, 너무 자주 변경하고, 모호한 문자를 포함 할 수 있습니다 ...)
Angelo Fuchs

@AngeloNeuschitzer-사용자가 고객 이름과 번호로 송장을 고유하게 식별 할 수 있으면 InvoiceID PK가 필요하지 않지만 데이터베이스 및 기본 코드에서이를 사용할 수 있습니다. 상호 배타적 인 기능입니다.
JeffO

내 사례의 사례 1-3을 참조하십시오. 어떤 경우에도 고객 이름은 사용자 (사람 또는 기계)의 해당 오브젝트를 처리하는 유용한 방법입니다. InvoiceID PK는
Angelo Fuchs

1

엔터티가 외부 세계에 노출되는 고유 식별자를 갖는 것은 완전히 정상입니다. 일부 개체의 경우 실제로 의미가있는 식별자 (예 : 송장 번호)를 찾을 수 있지만 다른 식별자의 경우 해당 식별자가 없으므로 생성해야합니다.

일관성과 가독성을 위해 시스템의 모든 엔터티가 식별자에 대해 정확히 동일한 유형과 이름을 사용하는 것이 좋습니다. 일반적으로이 식별자는 <type> getId()일부 추상 기본 클래스에서 노출됩니다 ( ).

같은 이유로 시스템의 각 서비스 (예 : 송장 서비스)는 식별자로 엔티티에 액세스하는 동일한 방법을 제공해야합니다. 일반적으로이 메소드 ( findById(<type> id))는 일반 서비스 인터페이스 또는 기본 클래스에서 상속됩니다.

이 식별자는 엔티티의 기본 키일 필요는 없지만 하나 일 수 있습니다. 키 생성 전략이 합리적으로 고유 한 식별자 (일반적으로 고유하지는 않지만 적어도 시스템 내에서)를 생성한다는 것만 보장하면됩니다.

시스템이 나중에 다른 데이터베이스로 마이그레이션되면 (기본 키를 기반으로하지 않는) 다른 전략 (기본 키를 기반으로하지 않음)을 사용하여 전략이 원본과 호환되는 한 식별자를 만드는 데 문제가되지 않습니다.


다른 답변에서 답변하지 않은 내용에 대해 설명해 주시겠습니까?
Angelo Fuchs

2
내 대답에서 나는 적어도 당신의 요약 2와 3에 동의하지 않습니다. 나는 이것이 PK를 객체 식별자로 사용하지 않는 유효한 이유라고 생각하지 않습니다.
Muton

0

기본 키는 개발자로서 액세스하려고하는 튜플 (레코드, 행)에 대한 핸들과 같습니다. 또한 참조 무결성 (외부 키 제약 조건)에 사용되며 하나 이상의 사용 사례가있을 수도 있습니다.

기본적으로 사용자 나 해커에게 노출시키는 것은 나쁘지 않습니다. 예를 들어 기본 키를 사용하는 공격을 모르기 때문입니다.

그러나 보안에는 많은 원칙 (승인 및 승인하지 않음)이 있으며이를 준수해야합니다.

  1. 임대 특전의 원칙
  2. 모호함을 통한 보안

그리고 다른 원칙들도 있습니다. 그들이 본질적으로 말하는 것은 :

데이터를 공개 할 필요가 없다면 왜 하시겠습니까?


손잡이 부분은 내가 동의하는 곳입니다. 보안은 아닙니다. 보안과 관련 이 있을 수 있지만 사용자에게 보이지 않는 독립적 인 내부 키를 갖는 것은 실제로 보안에 관한 것이 아닙니다. 나는 그것을 좋은 부작용이라고 부를 것입니다.
JensG

왜 당신은 : 질문에 추가 한 예를 참조하십시오.
Angelo Fuchs
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.