2016년 11월 22일 화요일

MySQL InnoDB Type의 데이터 파일 구조 분석과 삭제된 레코드의 복구 방안


[Tech Report] MySQL Type의 데이터 파일 구조 분석과 삭제된 레코드의 복구 방안



  • AhnLab


  • 2014-01-06

구조를 알면 데이터가 보인다

 

오픈소스 라이선스 기반의 DB 관리 시스템인 MySQL은 일반적으로 InnoDB 또는 MyISAM이라는 두 가지의 저장 방식(Storage Engine) 중 하나의 방식을 사용하여 데이터를 저장한다. InnoDB와 MyISAM은 각각의 절차와 구조에 따라 데이터를 읽거나 저장한다. 따라서 이들 저장 방식의 구조를 이해하면 데이터에 직접 접근할 수 있을 뿐만 아니라 DB 내부의 완전히 삭제되지 않은 데이터에 대한 접근 및 복구도 가능하다. 포렌식에서 삭제된 데이터의 복구는 공격자의 고의적인 데이터 은닉이나 삭제를 밝혀낸다는 점에서 중요한 의미를 갖는다. 이 글에서는 MySQL의 저장 방식 중 InnoDB 저장 방식의 구조를 분석하여 직접적으로 데이터에 접근하는 방법을 살펴보고 삭제된 데이터의 복구 방안에 대해 알아본다. MyISAM 저장 방식에 대해서는 3부에서 살펴볼 예정이다.

 

<연재 목차>


1부_MySQL의 현황 및 포렌식적 의미(2013년 12월 호)

2부_MySQL InnoDB Type의 데이터 파일 구조 분석과 삭제된 레코드의 복구 방안(이번 호)
3부_ MySQL MyISAM Type의 데이터 파일 구조 분석과 삭제된 레코드의 복구 방안

 

 

InnoDB는 대용량 데이터를 처리하기 위해 설계된 저장 방식이다. 기존의 저장 방식과는 달리 트랜잭션 기능을 포함하여 안전성을 크게 강화하였으며 외래 키(Foreign Key) 지원을 통한 무결성의 보장으로 데이터의 품질을 향상시키는 데 기여한다. 이 같은 다양한 장점을 기반으로 MySQL은 5.5 버전부터 InnoDB 방식을 기본 저장 방식으로 설치하고 있다.

 

InnoDB의 구조적 특징



InnoDB는 페이지 단위의 각 데이터들의 집합체이다. MySQL 설치 시 설정된 데이터 저장경로에 ibdata 파일을 생성하여 관련 데이터를 저장한다. 하나의 페이지는 일반적으로 16,384바이트(16KB)의 크기로 이루어져 있으며 ibdata 내부에 여러 개의 페이지가 순차적으로 저장되어 하나의 파일을 이룬다(경우에 따라 ibdata 파일을 분할하여 다수의 파일로 저장하는 것도 가능하다).



[그림 1]은 ibdata 파일의 내부 구조를 나타낸 것이다. 일반적으로 시스템 테이블(System Table) 영역과 트랜잭션 (Transaction) 영역, 그리고 데이터(Data) 영역으로 나눌 수 있다.

 



시스템 테이블 영역은 DB의 시스템이 생성한 영역이다. 사용자가 생성한 데이터베이스와 테이블, 테이블에 대한 메타 정보 등을 정리하여 관리한다. 또한 시스템 테이블 영역을 통해 현재 어떤 데이터베이스와 테이블이 생성되어 있는지 파악할 수 있으며 테이블 내에 생성된 필드, 필드의 데이터 타입 등 다양한 정보 수집이 가능하다.




트랜잭션 영역은 DB가 쿼리를 처리하는 과정에서 시스템 상의 오류가 발생할 경우 원상태로 복구하기 위해 쿼리 처리 이전의 데이터를 보관하는 영역이다.



데이터 영역은 실제 데이터가 저장되는 영역으로, DB 사용자가 저장한 모든 데이터는 이 영역에 저장된다. 이 영역에서는 DB의 성능을 유지하기 위해 데이터 삭제 시, 완전 삭제 대신 데이터가 삭제된 것으로 표시만 하고 삭제 영역에 데이터를 그대로 유지한다. 이 같은 특징 때문에 삭제된 데이터의 복구가 가능하다.

 

InnoDB 구성 파일


앞서 설명한 바와 같이 InnoDB는 모든 데이터를 ibdata 파일에 페이지 단위로 기록한다. 디스크 기반 저장 방식인 MyISAM과는 달리 InnoDB는 각각의 데이터를 파일 단위로 따로 저장하지 않고 하나의 파일 안에 모두 저장한다. 따라서 데이터가 축적될수록 ibdata 파일의 용량도 증가한다. InnoDB는 데이터베이스를 생성할 때 기존에 설정된 데이터 저장 위치(ibdata 파일이 존재하는 위치)에 데이터베이스명의 폴더를 생성한다. 데이터베이스를 생성하고 테이블을 생성하는 경우에는 해당 데이터베이스명의 폴더에 생성한 테이블명으로 frm이라는 확장자의 파일을 생성한다.

 

 

frm 파일은 MyISAM 방식에서도 동일하게 사용하는 파일이다. frm 파일 내부에는 테이블에 대한 각종 정보와 테이블을 구성하는 각 필드의 필드명과 데이터 타입에 대한 정보가 존재한다. InnoDB 저장 방식으로 생성된 테이블은 frm 파일을 생성함과 동시에 동일한 내용을 ibdata에 저장하기 때문에 frm 파일이 존재하지 않아도 데이터를 복구할 수 있다. 따라서 frm의 구조에 대해서는 frm 파일이 필수적으로 필요한 MyISAM 방식과 함께 3부에서 살펴보도록 하겠다.

 

InnoDB 헤더 구조


ibdata 파일은 각각의 데이터를 쉽게 구분하기 하기 위해 데이터를 페이지(블록) 단위로 구성하고 있다. 하나의 페이지는 16,384 바이트며, 여러 개의 페이지를 하나로 합친 것이 ibdata 파일이다. ibdata는 각 페이지의 상단(헤더)에는 해당 페이지의 속성을 정의하는 다양한 정보가 존재하기 때문에 헤더가 갖고 있는 값에 주목할 필요가 있다.

 

 

일반적으로 리프 노드에 해당하는 모든 페이지들은 [그림 2]와 같이 파일 헤더(FilHeader)와 페이지 헤더(PageHeader), 레코드(Record) 속성, 데이터(Data) 항목으로 구성되어 있다. 각 페이지에는 페이지의 시작 위치를 기준으로 [표 2]의 파일 헤더 항목과 [표 3]의 페이지 헤더와 같은 다양한 속성 값이 순차적으로 위치한다.

 

 

 


 

 

[표 2]와 [표 3]은 [그림 2]가 어떤 헤더 값을 갖고 있는지 보여준다. InnoDB는 기본적으로 ibdata 파일의 리프 노드에 모든 데이터를 저장한다. 따라서 InnoDB 방식의 데이터베이스를 분석하기 위해서는 리프 노드에 초점을 맞추어 분석을 진행해야 한다. 리프 노드는 페이지의 FIL_PAGE_TYPE 값(0x45BF)을 확인하여 찾을 수 있다. FIL_PAGE_TYPE 값을 확인해 해당 페이지가 리프 노드로 판단되면 어떤 데이터가 입력되어 있는지 분석할 수 있다.



[표 4]는 FIL_PAGE_TYPE 항목에 올 수 있는 값을 설명한 것이다. 해당 표의 FIL_PAGE_INDEX (0x45BF) 값이 리프 노드에 해당되며, 데이터 복구를 위해 중요한 항목이다.

 


버전별 InnoDB 복구 방안



MySQL의 InnoDB 저장 방식은 하나의 레코드에 하나의 속성을 부여하여 헤더 위치에 저장한다([그림 2]). 레코드 속성은 크게 리던던트 포맷(redundant format)과 콤팩트 포맷(compact format)으로 구분된다. 리던던트 포맷은 InnoDB 저장 방식이 생긴 이후로 현재까지 사용되고 있는 포맷이다. 콤팩트 포맷은 MySQL 5.0 버전 이후 리던던트 포맷의 비효율성을 해결하고 데이터를 효율적으로 관리하기 위해 도입된 포맷이다. 리던던트 포맷과 콤팩트 포맷은 각각의 레코드가 저장되기 전에 6바이트 길이로 헤더에 저장된다. 각 포맷을 통해 정의된 헤더 값은 각 레코드의 속성 정보를 파악할 수 있게 해준다. 리던던트 포맷과 콤팩트 포맷의 각 항목은 비트 단위로 구성되어 있으며 각 항목의 비트 길이에 따라 계산하여 해당 항목의 값을 계산할 수 있다.



[표 5]는 리던던트 포맷의 각 항목과 비트 수 등을 설명한 것으로, 속성 정보를 통해 현재 레코드의 상태 정보와 삭제 여부, 최소 레코드의 속성, 소유하는 레코드의 개수, 다음 레코드의 오프셋 정보 등을 확인할 수 있다.

 



 

[그림 3]은 각 레코드의 앞 6바이트에 존재하는 리던던트 포맷의 헤더이다. 이와 같이 InnoDB에서 레코드 속성은 6바이트의 속성 정보를 통해 정의되며 속성 정보와 함께 각 필드의 길이 정보도 포함하고 있다. 이 같은 방법을 통해 MySQL 4 버전의 InnoDB 저장 방식의 데이터를 분석할 수 있다.




InnoDB 저장 방식은 MyISAM에 비해 삭제된 레코드의 분석시에도 장점이 있다. MyISAM이 필드의 일부를 다른 정보로 덮어쓰는 것과 달리 InnoDB는 레코드의 속성 정보에서 deleted_flag 값만 1로 바꾼 후 더 이상의 수정을 하지 않는다. 따라서 삭제된 지 오래된 레코드도 복구할 수 있는 가능성이 높다. 또한 MyISAM에 비해 데이터를 새로운 레코드가 덮어쓸 가능성이 낮기 때문에 복구시에도 상당히 유리하다.

 


MySQL 5 버전으로 넘어가면서 InnoDB는 기존에 사용하던 리던던트 포맷은 그대로 사용하면서 콤팩트 포맷을 추가로 도입하였다. 기존 4 버전의 데이터베이스 시스템 관련 필드와 유저 관련 필드가 모두 리던던트 포맷이었던 반면, 5 버전부터는 효율성을 위해 시스템 관련 필드는 리던던트 포맷을 사용하고 유저 관련 필드는 콤팩트 포맷을 사용하도록 개선되었다. 콤팩트 포맷은 기존의 리던던트 포맷과 같이 6바이트의 길이를 차지하고 있지만 실제로 활용하는 길이는 5바이트이다.

 

[표 6]은 유저 관련 필드의 레코드 속성을 정의하는 콤팩트 포맷이 나타내는 속성 정보이다. 콤팩트 포맷은 리던던트 포맷과 큰 차이는 없으며, 더 실용적인 데이터 활용을 위해 자주 사용되지 않는 두 개의 필드를 제거하였다. InnoDB는 각각의 레코드 속성을 통해 각 레코드의 상태를 파악할 수 있다. 이를 통해 정상적으로 존재하는 레코드인지, 삭제된 레코드인지 여부를 판단할 수 있다.




InnoDB는 페이지 헤더의 PAGE_HEAP_TOP 값을 이용해 정상 레코드의 시작 위치를 정의한다. 각 레코드는 리던던트 포맷 및 콤팩트 포맷의 속성 중 next 16bits를 통해 다음 정상 레코드의 위치로 연결된다. 마찬가지로 삭제된 레코드는 페이지 헤더의 PAGE_FREE 값을 통하여 첫 번째 삭제된 레코드의 위치로 연결되며 next 16bits를 통해 다음 삭제된 레코드의 위치로 연결된다. 따라서 페이지에서 첫 번째 정상 데이터, 또는 첫 번째 삭제된 데이터의 위치만 찾으면 링크를 통해 모든 정상 데이터와 삭제된 데이터를 찾을 수 있다. 링크를 통한 분석은 특정 레코드를 빠르게 분석하는 데 편리하다.

 

InnoDB, 복구의 안전성과 신뢰도 높아

디지털 포렌식 관점에서 삭제된 레코드의 복구는 공격자가 고의로 은닉하거나 삭제한 데이터를 복구할 수 있다는 점에서 중요한 의미를 갖는다. 따라서 가능한 많은 복구를 이뤄내는 것은 중요하다.




InnoDB의 ibdata 파일은 페이지 단위로 구분할 수 있으며 각 페이지의 속성 값을 통해 해당 페이지가 리프 노드인지 여부를 파악할 수 있다. 리프 노드에 일반적인 레코드 값이 저장되어 있기 때문에 리프 노드를 구분하는 것이 중요하다. 리프 노드의 페이지에서 페이지 헤더를 이용해 첫 번째 정상 레코드 또는 첫 번째 삭제 레코드를 확인할 수 있으며 하나의 레코드를 복구하면 대부분의 레코드 복구가 가능하기 때문이다.




InnoDB는 버전에 따라 각 레코드에 사용하는 포맷이 다르다. 따라서 각 버전에 따라 각기 다른 형태로 분석해야 한다. 또한 삭제된 레코드에 대한 데이터 손상이 크지 않기 때문에 복구 관점에서도 안전성과 신뢰도가 높다.



InnoDB는 frm 파일과 함께 분석이 이루어지면 테이블 단위의 추출이 가능하며 더욱 정교한 분석이 가능하다. 3부에서는 frm의 구조 분석과 함께 MyISAM이 어떻게 복구되는지 살펴보며 InnoDB와 어떻게 연결되어 데이터를 추출하고 복구할 수 있는지 알아보도록 하겠다.@










  • AhnLab 로고



  • 클라우드분석팀 남궁재웅 연구원




이 정보에 대한 저작권은 AhnLab에 있으며 무단 사용 및 도용을 금합니다.

단, 개인이 비상업적인 목적으로 일부 내용을 사용하는 것은 허용하고 있으나, 이 경우 반드시 출처가 AhnLab임을 밝혀야 합니다.

기업이 이 정보를 사용할 때에는 반드시 AhnLab 의 허가를 받아야 하며, 허가 없이 정보를 이용할 경우 저작권 침해로 간주되어 법적인 제재를 받을 수 있습니다. 자세한 내용은 컨텐츠 이용약관을 참고하시기 바랍니다.

정보 이용 문의 : contents@ahnlab.com


댓글 없음:

댓글 쓰기