"때때로 오프라인"웹 앱에서 사용하기위한 고유하고 안전한 식별자 생성 전략


47

사용자가 온라인과 오프라인 모두에서 작업 할 수있는 웹 기반 프로젝트를 보유하고 있으며 클라이언트 측 레코드의 고유 ID를 생성하는 방법을 찾고 있습니다. 사용자가 오프라인 상태 (즉, 서버와 대화 할 수 없음)에서 작동하고 고유하며 안전하다는 접근 방식을 원합니다. "보안"을 통해 특히 고객이 중복 ID를 악의적으로 또는 다른 방식으로 제출하여 데이터 무결성에 혼란을 초래할 수 있습니다.

나는 이미 해결 된 문제가 있기를 희망하면서 인터넷 검색을 해왔다. 특히 프로덕션 시스템에서 사용되는 접근 방식 측면에서 매우 결정적인 것을 찾지 못했습니다. 사용자가 자신이 만든 데이터에만 액세스 할 수있는 시스템에 대한 몇 가지 예를 찾았습니다 (예 : 여러 장치에서 액세스하지만이를 만든 사용자 만 액세스하는 Todo 목록). 불행히도 좀 더 정교한 것이 필요합니다. 나는 여기 에서 정말 좋은 아이디어를 찾았 습니다.

아래는 내가 제안한 솔루션입니다.

일부 요구 사항

  1. ID는 전체적으로 고유해야합니다 (또는 시스템 내에서 고유해야합니다).
  2. 클라이언트에서 생성됩니다 (예 : 브라우저에서 자바 스크립트를 통해).
  3. 보안 (위에 설명 된대로)
  4. 데이터를 작성하지 않은 사용자를 포함하여 여러 사용자가 데이터를 보거나 편집 할 수 있습니다
  5. 백엔드 DB (예 : MongoDB 또는 CouchDB)에 대해 중대한 성능 문제가 발생하지 않습니다.

제안 된 해결책

사용자가 계정을 만들면 서버에 의해 생성되고 시스템 내에서 고유 한 uuid가 제공됩니다. 이 ID는 사용자 인증 토큰과 동일하지 않아야합니다. 이 ID를 사용자 "ID 토큰"이라고하겠습니다.

사용자가 새 레코드를 작성하면 javascript에서 새 uuid가 생성됩니다 (사용 가능한 경우 window.crypto를 사용하여 생성됨. 여기의 예제 참조 ). 이 ID는 사용자가 계정을 만들 때받은 "ID 토큰"과 연결됩니다. 이 새로운 복합 ID (서버 측 ID 토큰 + 클라이언트 측 uuid)는 이제 레코드의 고유 식별자입니다. 사용자가 온라인 상태이고이 새 레코드를 백엔드 서버에 제출하면 서버는 다음을 수행합니다.

  1. 이를 "삽입"조치로 식별하십시오 (예 : 업데이트 또는 삭제 아님)
  2. 복합 키의 두 부분이 유효한 uuid인지 확인하십시오.
  3. 제공된 복합 ID의 "ID 토큰"부분이 현재 사용자에 대해 올바른지 확인하십시오 (즉, 계정을 만들 때 서버가 사용자에게 할당 한 ID 토큰과 일치 함)
  4. 모든 것이 copasetic 인 경우, 데이터를 db에 삽입하십시오 (ID 이미 존재 하는 경우 실수로 기존 레코드를 업데이트하지 않도록 "upsert"가 아닌 삽입을 신중하게 수행하십시오 )

쿼리, 업데이트 및 삭제에는 특별한 논리가 필요하지 않습니다. 기존 애플리케이션과 동일한 방식으로 레코드의 ID를 사용합니다.

이 방법의 장점은 무엇입니까?

  1. 클라이언트 코드는 오프라인 상태에서 새 데이터를 작성하고 해당 레코드의 ID를 즉시 알 수 있습니다. 시스템에서 온라인 상태 일 때 임시 ID가 나중에 "최종"ID로 교체되는 임시 ID가 클라이언트에서 생성되는 대체 방법을 고려했습니다. 그러나 이것은 매우 부서지기 쉬운 느낌이 들었습니다. 특히 업데이트해야 할 외래 키로 자식 데이터를 만드는 것에 대해 생각할 때 특히 그렇습니다. ID가 변경되었을 때 변경되는 URL을 다루는 것은 말할 것도 없습니다.

  2. ID를 클라이언트 생성 값과 서버 생성 값의 합성으로 만들어 각 사용자는 샌드 박스에서 효과적으로 ID를 생성합니다. 악의적 / 불량 클라이언트가 수행 할 수있는 피해를 제한하기위한 것입니다. 또한 모든 ID 충돌은 전체 시스템에 대한 전역이 아니라 사용자별로 이루어집니다.

  3. 사용자 아이디 토큰은 계정과 연결되어 있으므로 인증 된 클라이언트 (예 : 사용자가 성공적으로 로그인 한 클라이언트) 만 사용자 샌드 박스에서 아이디를 생성 할 수 있습니다. 이는 악의적 인 클라이언트가 사용자를 위해 잘못된 ID를 만들지 않도록하기위한 것입니다. 물론 악의적 인 클라이언트가 사용자 인증 토큰을 도난당한 경우 나쁜 일을 할 수 있습니다. 그러나 인증 토큰을 도난당한 후에는 계정이 손상됩니다. 이런 일이 발생하면 피해는 전체 시스템이 아닌 손상된 계정으로 제한됩니다.

우려 사항

이 접근법에 대한 몇 가지 우려 사항은 다음과 같습니다.

  1. 이것은 대규모 응용 프로그램을 위해 충분히 고유 한 ID를 생성합니까? 이것이 id 충돌을 일으킬 것이라고 생각할만한 이유가 있습니까? 자바 스크립트가 작동하기에 충분히 임의의 UUID를 생성 할 수 있습니까? window.crypto는 상당히 광범위하게 사용 가능 하며이 프로젝트에는 이미 최신 브라우저가 필요합니다. ( 이 질문은 이제 별도의 SO 질문이 있습니다 )

  2. 악의적 인 사용자가 시스템을 손상시킬 수있는 허점이 있습니까?

  3. 2 개의 UUID로 구성된 복합 키를 쿼리 할 때 DB 성능에 대해 걱정할 이유가 있습니까? 최상의 성능을 위해이 ID를 어떻게 저장해야합니까? 두 개의 별도 필드 또는 단일 개체 필드? Mongo와 Couch에 대해 다른 "최상의"접근 방식이 있습니까? 비 순차 기본 키를 사용하면 삽입을 수행 할 때 현저한 성능 문제가 발생할 수 있음을 알고 있습니다. 기본 키에 대해 자동 생성 된 값을 갖고이 ID를 별도의 필드로 저장하는 것이 더 똑똑할까요? ( 이 질문은 이제 별도의 SO 질문이 있습니다 )

  4. 이 전략을 사용하면 동일한 사용자가 특정 레코드 집합을 만들 었는지 쉽게 확인할 수 있습니다 (모두 공개적으로 표시되는 동일한 ID 토큰을 공유하므로). 이에 대한 즉각적인 문제는 보이지 않지만 필요한 것보다 내부 세부 정보에 대한 더 많은 정보를 유출하지 않는 것이 좋습니다. 다른 가능성은 복합 키를 해시하는 것이지만 가치가있는 것보다 더 문제가있는 것처럼 보입니다.

  5. 사용자에게 ID 충돌이 발생하는 경우 간단한 복구 방법이 없습니다. 클라이언트가 새 ID를 생성 할 수 있다고 생각하지만 실제로는 절대 일어나서는 안되는 최첨단 사례에 대한 많은 작업처럼 보입니다. 나는 이것을 주소없는 채로두고 싶습니다.

  6. 인증 된 사용자 만 데이터를 보거나 편집 할 수 있습니다. 이것은 내 시스템에 허용되는 제한입니다.

결론

합리적인 계획 이상입니까? 이 중 일부는 해당 응용 프로그램에 대한 완전한 이해를 바탕으로 판단 요청에 해당한다는 것을 알고 있습니다.


이 질문은 당신이 interess 있다고 생각 stackoverflow.com/questions/105034/... GUID처럼 나 또한이 읽기하지만 그들은 자바 스크립트 기본으로하지 않는 것
레미

2
UUID가 이미 5 가지 나열된 요구 사항을 충족한다는 사실에 놀랐습니다. 왜 부족합니까?
Gabe

@Gabe 거짓말 ryans에 대한 내 의견보기 아래 게시물
herbrandson

이 질문에 대한 메타 토론 : meta.stackoverflow.com/questions/251215/…
gnat

"악의적 / 경로 클라이언트"-불량.
David Conrad

답변:


4

당신의 접근 방식이 효과가 있습니다. 많은 문서 관리 시스템이이 방식을 사용합니다.

고려해야 할 한 가지는 사용자 uuid와 임의 항목 ID를 모두 문자열의 일부로 사용할 필요가 없다는 것입니다. 대신 두 연결을 해시 할 수 있습니다. 이렇게하면 식별자가 짧아지고 결과 ID가 더 균등하게 분산되기 때문에 다른 이점도있을 수 있습니다 (인덱싱 및 uuid를 기반으로 파일을 저장하는 경우 파일 저장에 더 적합합니다).

또 다른 옵션은 각 항목에 대해 임시 UUID를 생성하는 것입니다. 그런 다음 서버에 연결하여 게시하면 서버는 각 항목에 대해 uuid를 생성하고 보증합니다. 그런 다음 로컬 사본을 업데이트하십시오.


2
나는 2의 해시를 ID로 사용하는 것을 고려했다. 그러나 지원 해야하는 모든 브라우저에서 sha256을 생성하는 적절한 방법이있는 것으로 보이지 않았습니다. (
herbrandson

12

두 가지 우려를 분리해야합니다.

  1. ID 생성 : 클라이언트는 분산 시스템에서 고유 식별자를 생성 할 수 있어야합니다
  2. 보안 문제 : 클라이언트는 유효한 사용자 인증 토큰을 가져야하며 인증 토큰은 생성 / 수정중인 객체에 유효합니다.

불행히도이 두 가지에 대한 해결책은 별개입니다. 그러나 다행히도 호환되지 않습니다.

ID 생성에 대한 우려는 UUID로 생성하여 쉽게 해결할 수 있습니다. 즉 UUID가 설계된 것입니다. 그러나 보안 문제는 주어진 인증 토큰이 작업에 대해 권한이 있는지 서버에서 확인하도록 요구합니다 (예 : 인증 토큰이 해당 특정 개체에 대한 필요한 권한을 소유하지 않은 사용자를위한 것이라면). 거부 됨).

올바르게 처리하면 충돌로 인해 실제로 보안 문제가 발생하지 않습니다 (사용자 또는 클라이언트에게 다른 UUID로 작업을 다시 시도하라는 메시지가 표시됨).


이것은 정말 좋은 지적입니다. 아마도 그게 전부이고 나는 그것을 너무나 생각하고 있습니다. 그러나이 접근법에 대해 몇 가지 우려가 있습니다. 가장 큰 것은 자바 스크립트로 생성 된 UUID가 원하는만큼 임의적이지 않다는 것입니다 ( 감금에 대해서는 stackoverflow.com/a/2117523/13181 의 의견 참조 ). window.crypto 가이 문제를 해결 해야하는 것 같지만 지원 해야하는 모든 브라우저 버전에서 사용 가능한 것은 아닙니다.
herbrandson

계속 ... 충돌시 새 UUID를 재생성하는 클라이언트에 코드를 추가하라는 제안이 마음에 듭니다. 그러나 이것은 "이 접근법의 장점은 무엇입니까?"섹션 # 1의 1 번 지점에서 내가했던 관심사를 다시 소개하는 것으로 보입니다. 만약 내가 그 길을 갔다면, 클라이언트 쪽에서 임시 아이디를 생성 한 다음 일단 연결되면 서버에서 "최종 아이디"로 업데이트하는 것이
좋습니다.

다시 계속 ... 더 나아가 사용자가 자신의 고유 ID를 제출할 수있게하는 것은 보안 문제와 같습니다. 아마도 UUID의 크기와 충돌의 높은 통계적 불가능 성은 이러한 문제 자체를 완화시키기에 충분할 것입니다. 잘 모르겠습니다. 이 경우 각 사용자를 자신의 "샌드 박스"로 유지하는 것이 좋은 생각이라는 의심이 들었습니다. 즉, 사용자 입력을 신뢰하지 않습니다.
herbrandson

@herbrandson : 사용자에게 항상 작업 권한이 있는지 확인하기 만하면 사용자가 고유 한 ID를 생성하도록 허용 할 수있는 보안 문제는 없습니다. ID는 객체를 식별하는 데 사용할 수있는 것이므로 그 값이 무엇인지는 중요하지 않습니다. 유일하게 잠재적 인 피해는 사용자가 자신의 사용을 위해 다양한 ID를 예약 할 수 있지만 다른 사용자가 우연히 그 값에 도달 할 가능성이 거의 없기 때문에 시스템 전체에 전혀 문제가되지 않는다는 것입니다.
Lie Ryan

의견을 보내 주셔서 감사합니다. 정말 내 생각을 명확히해야합니다! 내가 당신의 접근 방식에주의를 기울인 이유가 있으며, 나는 그 길을 따라 잊어 버렸습니다. :). 많은 브라우저에서 RNG가 열악한 RNG와 관련이 있습니다. UUID 생성의 경우 암호로 강력한 RNG를 선호합니다. 많은 최신 브라우저는 window.crypto를 통해이 기능을 제공하지만 이전 브라우저는 그렇지 않습니다. 이로 인해 악의적 인 사용자가 다른 사용자 RNG의 시드를 파악하여 다음에 생성 될 UUID를 알 수 있습니다. 이것이 공격받을 수 있다고 느끼는 부분입니다.
herbrandson
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.