티스토리 뷰
말머리
본 포스팅은 dreamhack(드림핵)의 mongoboard라는 문제를 풀다가 정리하는 내용입니다. 문제 내용이 궁금하다면 아래 링크를 참고해보세요. 별로 궁금하지 않다면 다음 제목으로 넘어가세요.
https://dreamhack.io/wargame/challenges/128/
해당 문제는 아래와 같이 게시글 목록이 존재하고 관리자가 작성한 글에만 mongodb의 ObjectID가 보이지 않는 형태인데요.
다만 이렇게 /detail/{ObjectID} 로 직접 접속하게 되면 비밀 글도 보이게 되는 비인가 접근이 가능한 취약점을 가지고 있는 문제입니다.
위 문제를 풀기위해서는 관리자가 작성한 비밀 게시글이 작성된 날짜를 기준으로 ObjectID를 변환하면 풀 수 있는 문제였습니다. 이 문제를 풀다가 MongoDB의 ObjectID에 대해서 정리해봅니다.
MongoDB의 ObjectID란
MongoDB의 ObjectId 는 총 12byte 로 이루어져있고 모두 16진수 형태로 이루어져있습니다. 아래 테이블은 ObjectID 를 각 의미를 가지는 바이트 별로 나눈 예시입니다.
62 4d dc 67 | 38 ff b0 cf 6d | d1 11 52 |
- 첫 4 바이트는 Unix Timestamp 값을 의미합니다.
- 다음 5 바이트는 고유한 랜덤값을 가집니다.
- 마지막 3 바이트는 계속 증가하는 값을 가지는 counter 값이며, 최초값은 랜덤하게 생성됩니다.
MongoDB는 BSON 포맷으로 데이터를 저장하는데, BSON 포맷 자체는 리틀엔디안(little-endian)이지만, 타임스탬프나 카운터 값의 경우에는 빅 엔디안(big-endian)이며, 바이트 시퀀스에서 MSB(most significant bytes)가 먼저 앞에 온다고 합니다.
위 내용의 원본은 아래 링크에서 볼 수 있습니다.
https://www.mongodb.com/docs/manual/reference/method/ObjectId/
ObjectID 와 Datetime 간의 변환(convert)
우선 ObjectID의 앞 4바이트만 변환한다고 생각하면 됩니다. 왜냐하면 뒤 나머지 8바이트는 모두 랜덤한 값이기 때문입니다.
아래는 ObjectID로부터 datetime 을 추출하는 코드입니다.
var objId = '624ddc6738ffb0cf6dd11152';
var dateFromObjectId = function (objectId) {
return new Date(parseInt(objectId.substring(0, 8), 16) * 1000);
};
dateFromObjectId(objId).toISOString();
// '2022-04-06T18:31:03.000Z'
dateFromObjectId 함수는 0번째부터 7번째 index 까지의 문자들을 파싱해서 날짜로 변환합니다. 그리고 toISOString 함수로 Date 객체를 ISO 시간 포맷으로 datetime 을 출력했습니다.
그리고 반대로 datetime 으로부터 ObjectID를 추출할 수도 있습니다. 일단 말머리에서 언급했던 문제에서 사용된 날짜/시간 값이 ISO 포맷이기 때문에 ISO 포맷의 시간 값을 ObjectID로 변환하는 코드를 작성해보았습니다.
var objectIdFromDate = function (date) {
return Math.floor(date.getTime() / 1000).toString(16) + "0000000000000000";
};
var date = new Date('2022-04-06T18:31:08.269Z');
objectIdFromDate(date);
// '624ddc6c0000000000000000'
위와 같이 timestamp 값만을 변환해주었습니다. 뒤의 랜덤한 값은 MongoDB 자체에서 정해지는 값들이라 필요하다면 따로 붙여주기만 하면 되기 때문입니다.
이로써 MongoDB의 ObjectId 와 날짜/시간(Datetime) 간의 변환에 대해서 알아보았습니다. dreamhack 의 mongoboard 문제풀이는 위 내용을 활용한다면 쉽게 풀 수 있겠습니다.
- 끝 -
'개발환경 > DB' 카테고리의 다른 글
[mysql] mysqldump 사용해서 DB 백업하기 (0) | 2023.03.02 |
---|---|
[mongoDB] linux mongoDB 주기적으로 백업하는 방법 (2) | 2023.01.27 |
[MySQL] ASCII() 와 ORD() 함수의 차이점 (0) | 2021.10.30 |
[mongoDB] ubuntu16.04 mongoDB 설치+실행+관리자만들기 (0) | 2021.10.27 |
[MySQL 문법] - String Literals (문자열) (0) | 2021.09.22 |