사용자가 온라인과 오프라인 모두에서 작업 할 수있는 웹 기반 프로젝트를 보유하고 있으며 클라이언트 측 레코드의 고유 ID를 생성하는 방법을 찾고 있습니다. 사용자가 오프라인 상태 (즉, 서버와 대화 할 수 없음)에서 작동하고 고유하며 안전하다는 접근 방식을 원합니다. "보안"을 통해 특히 고객이 중복 ID를 악의적으로 또는 다른 방식으로 제출하여 데이터 무결성에 혼란을 초래할 수 있습니다.
나는 이미 해결 된 문제가 있기를 희망하면서 인터넷 검색을 해왔다. 특히 프로덕션 시스템에서 사용되는 접근 방식 측면에서 매우 결정적인 것을 찾지 못했습니다. 사용자가 자신이 만든 데이터에만 액세스 할 수있는 시스템에 대한 몇 가지 예를 찾았습니다 (예 : 여러 장치에서 액세스하지만이를 만든 사용자 만 액세스하는 Todo 목록). 불행히도 좀 더 정교한 것이 필요합니다. 나는 여기 에서 정말 좋은 아이디어를 찾았 습니다.
아래는 내가 제안한 솔루션입니다.
일부 요구 사항
- ID는 전체적으로 고유해야합니다 (또는 시스템 내에서 고유해야합니다).
- 클라이언트에서 생성됩니다 (예 : 브라우저에서 자바 스크립트를 통해).
- 보안 (위에 설명 된대로)
- 데이터를 작성하지 않은 사용자를 포함하여 여러 사용자가 데이터를 보거나 편집 할 수 있습니다
- 백엔드 DB (예 : MongoDB 또는 CouchDB)에 대해 중대한 성능 문제가 발생하지 않습니다.
제안 된 해결책
사용자가 계정을 만들면 서버에 의해 생성되고 시스템 내에서 고유 한 uuid가 제공됩니다. 이 ID는 사용자 인증 토큰과 동일하지 않아야합니다. 이 ID를 사용자 "ID 토큰"이라고하겠습니다.
사용자가 새 레코드를 작성하면 javascript에서 새 uuid가 생성됩니다 (사용 가능한 경우 window.crypto를 사용하여 생성됨. 여기의 예제 참조 ). 이 ID는 사용자가 계정을 만들 때받은 "ID 토큰"과 연결됩니다. 이 새로운 복합 ID (서버 측 ID 토큰 + 클라이언트 측 uuid)는 이제 레코드의 고유 식별자입니다. 사용자가 온라인 상태이고이 새 레코드를 백엔드 서버에 제출하면 서버는 다음을 수행합니다.
- 이를 "삽입"조치로 식별하십시오 (예 : 업데이트 또는 삭제 아님)
- 복합 키의 두 부분이 유효한 uuid인지 확인하십시오.
- 제공된 복합 ID의 "ID 토큰"부분이 현재 사용자에 대해 올바른지 확인하십시오 (즉, 계정을 만들 때 서버가 사용자에게 할당 한 ID 토큰과 일치 함)
- 모든 것이 copasetic 인 경우, 데이터를 db에 삽입하십시오 (ID 가 이미 존재 하는 경우 실수로 기존 레코드를 업데이트하지 않도록 "upsert"가 아닌 삽입을 신중하게 수행하십시오 )
쿼리, 업데이트 및 삭제에는 특별한 논리가 필요하지 않습니다. 기존 애플리케이션과 동일한 방식으로 레코드의 ID를 사용합니다.
이 방법의 장점은 무엇입니까?
클라이언트 코드는 오프라인 상태에서 새 데이터를 작성하고 해당 레코드의 ID를 즉시 알 수 있습니다. 시스템에서 온라인 상태 일 때 임시 ID가 나중에 "최종"ID로 교체되는 임시 ID가 클라이언트에서 생성되는 대체 방법을 고려했습니다. 그러나 이것은 매우 부서지기 쉬운 느낌이 들었습니다. 특히 업데이트해야 할 외래 키로 자식 데이터를 만드는 것에 대해 생각할 때 특히 그렇습니다. ID가 변경되었을 때 변경되는 URL을 다루는 것은 말할 것도 없습니다.
ID를 클라이언트 생성 값과 서버 생성 값의 합성으로 만들어 각 사용자는 샌드 박스에서 효과적으로 ID를 생성합니다. 악의적 / 불량 클라이언트가 수행 할 수있는 피해를 제한하기위한 것입니다. 또한 모든 ID 충돌은 전체 시스템에 대한 전역이 아니라 사용자별로 이루어집니다.
사용자 아이디 토큰은 계정과 연결되어 있으므로 인증 된 클라이언트 (예 : 사용자가 성공적으로 로그인 한 클라이언트) 만 사용자 샌드 박스에서 아이디를 생성 할 수 있습니다. 이는 악의적 인 클라이언트가 사용자를 위해 잘못된 ID를 만들지 않도록하기위한 것입니다. 물론 악의적 인 클라이언트가 사용자 인증 토큰을 도난당한 경우 나쁜 일을 할 수 있습니다. 그러나 인증 토큰을 도난당한 후에는 계정이 손상됩니다. 이런 일이 발생하면 피해는 전체 시스템이 아닌 손상된 계정으로 제한됩니다.
우려 사항
이 접근법에 대한 몇 가지 우려 사항은 다음과 같습니다.
이것은 대규모 응용 프로그램을 위해 충분히 고유 한 ID를 생성합니까? 이것이 id 충돌을 일으킬 것이라고 생각할만한 이유가 있습니까? 자바 스크립트가 작동하기에 충분히 임의의 UUID를 생성 할 수 있습니까? window.crypto는 상당히 광범위하게 사용 가능 하며이 프로젝트에는 이미 최신 브라우저가 필요합니다. ( 이 질문은 이제 별도의 SO 질문이 있습니다 )
악의적 인 사용자가 시스템을 손상시킬 수있는 허점이 있습니까?
2 개의 UUID로 구성된 복합 키를 쿼리 할 때 DB 성능에 대해 걱정할 이유가 있습니까? 최상의 성능을 위해이 ID를 어떻게 저장해야합니까? 두 개의 별도 필드 또는 단일 개체 필드? Mongo와 Couch에 대해 다른 "최상의"접근 방식이 있습니까? 비 순차 기본 키를 사용하면 삽입을 수행 할 때 현저한 성능 문제가 발생할 수 있음을 알고 있습니다. 기본 키에 대해 자동 생성 된 값을 갖고이 ID를 별도의 필드로 저장하는 것이 더 똑똑할까요? ( 이 질문은 이제 별도의 SO 질문이 있습니다 )
이 전략을 사용하면 동일한 사용자가 특정 레코드 집합을 만들 었는지 쉽게 확인할 수 있습니다 (모두 공개적으로 표시되는 동일한 ID 토큰을 공유하므로). 이에 대한 즉각적인 문제는 보이지 않지만 필요한 것보다 내부 세부 정보에 대한 더 많은 정보를 유출하지 않는 것이 좋습니다. 다른 가능성은 복합 키를 해시하는 것이지만 가치가있는 것보다 더 문제가있는 것처럼 보입니다.
사용자에게 ID 충돌이 발생하는 경우 간단한 복구 방법이 없습니다. 클라이언트가 새 ID를 생성 할 수 있다고 생각하지만 실제로는 절대 일어나서는 안되는 최첨단 사례에 대한 많은 작업처럼 보입니다. 나는 이것을 주소없는 채로두고 싶습니다.
인증 된 사용자 만 데이터를 보거나 편집 할 수 있습니다. 이것은 내 시스템에 허용되는 제한입니다.
결론
합리적인 계획 이상입니까? 이 중 일부는 해당 응용 프로그램에 대한 완전한 이해를 바탕으로 판단 요청에 해당한다는 것을 알고 있습니다.