파이어버드 데이터베이스 암호화 작동 방식
(c) Alexey Kovyazin, IBSurgeon, Alex Peshkoff, Firebird Project, 2021
이 문서는 독일 베를린에서 열린 Firebird Conference 2019의 워크숍 “데이터베이스 암호화” 자료를 기반으로 작성되었습니다. Firebird 데이터베이스 암호화가 서버 수준과 클라이언트 측에서 어떻게 작동하는지, 데이터베이스 암호화를 구성하는 방법, 다양한 유형의 애플리케이션(Delphi, Java, .NET)에서 이를 사용하는 방법을 설명합니다. 이 문서의 예제는 IBSurgeon Firebird Encryption Framework(FEPF)를 기반으로 하지만, 현재 사용 가능한 대부분의 암호화 플러그인 구현에 적용할 수 있습니다.
목차:
- 데이터베이스 암호화가 필요한 이유(그리고 필요하지 않은 경우는)?
- Firebird 데이터베이스 암호화가 서버 측에서 작동하는 방식
- 데이터베이스의 어떤 부분이 암호화되나요?
- 데이터 페이지는 언제 암호화되나요?
- 키 전송을 보호하는 방법은?
- Firebird 암호화가 클라이언트 측에서 작동하는 방식
- 네이티브 애플리케이션
- Java 애플리케이션
- .NET 애플리케이션
- 설치 및 구성
- 암호화 진행 상황 추적 방법
- 요약
1. 데이터베이스 암호화가 필요한 이유(그리고 필요하지 않은 경우는)?
Firebird 데이터베이스 암호화는 Firebird 3.0 릴리스에서 도입되었으며(종종 논의 주제와 혼동되는 전송 프로토콜 암호화와 함께), 무단 액세스로부터 데이터를 보호하는 기능을 크게 향상시켰습니다. 그러나 이것은 만병통치약이 아니며, 올바르게 사용하려면 그 장점과 단점을 이해하는 것이 필요합니다.
이 문서에서는 데이터베이스 암호화의 내부 구조를 기본 수준에서 살펴보고, Firebird 애플리케이션 개발자들이 데이터베이스 암호화가 어떻게 작동하는지 더 잘 이해할 수 있도록 돕습니다.
그렇다면 데이터베이스 암호화가 왜 필요한가요?
- 민감하거나 가치 있는 데이터가 있는 데이터베이스를 “물리적” 도난으로부터 보호하기 위해. 침입자가 암호화된 데이터베이스의 복사본이 있는 디스크를 훔치거나 어떤 식으로든 데이터베이스 파일의 복사본을 얻더라도, 적절한 키 없이는 데이터를 읽을 수 없으며, FirstAID와 같은 복구 소프트웨어를 사용하여 데이터를 추출하는 것도 불가능합니다. 물론 암호화 알고리즘과 컴퓨팅 성능에 따라 다르지만, AES256을 크래킹하려면 너무 오랜 시간이나 너무 비싼 컴퓨팅 리소스가 필요합니다.
- 암호화 키가 없는 비인가 애플리케이션의 데이터베이스 접근을 보호하기 위해. 예를 들면:
- 비인가자가 개발자 도구로 직접 접근하여 민감한 정보(예: 금전 거래)를 변경하는 경우,
- 비즈니스 로직(저장 프로시저 및 트리거의 텍스트)을 변경하거나 도용하는 경우.
- 사전에 채워진 데이터가 있는 데이터베이스를 비인가 애플리케이션으로의 내보내기 또는 접근으로부터 보호합니다.
- 최근 정부들이 개인 및 기타 민감한 데이터에 대한 더 높은 수준의 보호를 요구하는 데이터 보호법(유럽의 GDPR/DSVGO, 브라질의 LGPD 등)을 도입했으며, 암호화는 적절한 보호 조치 중 하나로 언급됩니다.
데이터베이스 암호화가 유용하지 않은 경우는?
어떤 경우에는 데이터베이스 암호화 대신 Firebird의 보안 및 구성 기능을 사용하는 것이 더 좋습니다:
- 네트워크를 통한 물리적 접근으로부터 데이터베이스를 보호하려면 네트워크 접근을 구성해야 합니다: 즉, 네트워크 공유 폴더를 닫아야 합니다. Firebird는 데이터베이스 파일에 대한 네트워크 공유 접근을 요구하지 않기 때문입니다. 또한 보안 권한을 강화해야 합니다(예: Linux의 경우 데이터베이스 파일은 “firebird” 사용자에게만 읽기-쓰기 접근 권한이 있어야 합니다).
- 특정 사용자 하위 집합에 대한 특정 데이터베이스 접근을 제한하려면 별도의 보안 데이터베이스를 구성하는 것이 더 쉬운 해결책입니다.
- 데이터베이스 객체(테이블, 저장 프로시저)에 대한 접근을 제한하려면 Firebird 보안 메커니즘(사용자, 역할 등)을 사용해야 합니다.
물론 위의 두 목록 모두 완전하지는 않지만, 데이터베이스 암호화가 필요한 경우와 필요하지 않은 경우에 대한 대략적인 인상을 줍니다.
2. Firebird 데이터베이스 암호화가 서버 측에서 작동하는 방식
Firebird 데이터베이스 암호화의 내부 세부 사항을 살펴보고 서버 부분부터 시작하겠습니다.
2.1. 데이터베이스의 어떤 부분이 암호화되나요?
가장 먼저 고려해야 할 것은 데이터베이스의 어떤 부분이 암호화되는가입니다. 아시다시피 Firebird 데이터베이스는 “데이터베이스 페이지"라고 하는 동일한 크기의 부분들로 구성됩니다. 각 유형은 특정 목적을 제공하는 여러 유형의 페이지가 있습니다.
아래에서 주요 데이터 유형을 보여주는 그림을 볼 수 있습니다:

그림 1. 데이터베이스 페이지 유형
일부 페이지는 사용자 데이터를 저장하도록 설계되었고, 다른 페이지는 트랜잭션 및 페이지 인벤토리 페이지와 같은 시스템 정보를 저장하는 데 필요합니다(데이터베이스 페이지에 대한 자세한 내용은 여기에서 확인 가능).
Firebird 데이터베이스가 암호화될 때 사용자 데이터가 있는 페이지만 암호화됩니다: 데이터 페이지, 인덱스, 생성기 및 BLOB:

그림 2. 사용자 데이터가 있는 데이터베이스 페이지만 암호화됩니다
데이터베이스 메타데이터(저장 프로시저, 테이블, 뷰, 트리거, 생성기 이름 등)는 암호화를 담당하는 엔진 부분 내에서 “사용자 데이터"와 다르지 않으며 암호화된다는 점에 유의하세요.
시스템 페이지가 암호화되지 않는 이유는 무엇인가요? 주로 성능상의 이유와 보호가 필요한 민감한 데이터를 포함하지 않기 때문입니다.
데이터베이스 헤더 페이지는 암호화에 필요한 정보(예: 키 이름)를 포함하므로 암호화되지 않습니다.
2.2. 데이터 페이지는 언제 암호화되나요?
사용자가 암호화된 데이터베이스에서 SELECT를 실행하면 데이터는 암호화된 파일에서 읽히지만 애플리케이션의 결과 집합 그리드에는 암호화되지 않은 형태로 도착합니다.
이 프로세스의 세부 사항을 살펴보겠습니다:

그림 3. 데이터베이스 페이지는 언제 암호화되나요?
일반적으로 프로세스는 데이터베이스 파일에서 데이터베이스 페이지를 일련의 읽기로 시작하며, 페이지는 운영 체제 파일 캐시에 캐시됩니다.
Firebird는 파일 캐시를 우회하고 자체 캐시만 사용하도록 구성할 수도 있지만, 기본적으로 파일 캐시가 사용됩니다.
그 후 Firebird는 페이지를 읽어 Firebird 페이지 캐시에 넣습니다(firebird.conf 및/또는 databases.conf 또는 데이터베이스 헤더 페이지의 DefaultDBCachePages 매개변수로 정의됨).
그런 다음 캐시의 페이지가 특정 SQL 문(이 예에서는 SELECT)의 결과 집합으로 선택됩니다.
아래 그림은 세부 사항을 보여줍니다:

그림 4. 페이지는 Firebird 캐시와 OS 파일 캐시 사이에서 암호화됩니다
따라서 데이터베이스 페이지는 OS 파일 캐시에서 암호화되지만 Firebird 페이지 캐시에는 암호화되지 않은 상태로 도착하며, 그 반대도 마찬가지입니다.
암호화/복호화를 담당하는 Firebird 소프트웨어 부분을 " 암호화 플러그인“이라고 합니다. 알려진 대부분의 플러그인 구현이 DbCrypt라고 불리기 때문에, 이 문서에서는 DbCrypt라고 부르겠습니다.
아래 그림에서 Windows(DbCrypt.dll) 및 Linux(libDbCrypt.so)용 변형을 볼 수 있습니다:


그림 5. 암호화 플러그인(DbCrypt)이 암호화/복호화를 수행하는 모습
이 그림을 충분히 오래 보면, 다음 질문이 곧 떠오를 것입니다: DbCrypt가 데이터베이스 페이지를 암호화/복호화하기 위해 올바른 키를 어떻게 얻을까요?
답은 - 키 관리를 위한 또 다른 플러그인이 있다는 것입니다.
키 관리의 일반적인 이름은 KeyHolder로, 암호화 플러그인(DbCrypt)을 위한 키 저장/관리 기능을 제공합니다. KeyHolder는 DbCrypt가 사용하는 키 관리 인터페이스를 구현합니다.

그림 6. DbCrypt와 KeyHolder
“키 관리"란 무엇을 의미하나요?
가장 간단한 경우, DbCrypt는 서버의 파일에서 키를 읽을 수 있습니다. 파일은 “비밀” 장소나 USB 스틱에 숨길 수 있는 단순한 일반 텍스트 파일일 수 있으며, 암호화된 파일(예: Windows Crypto API 또는 내장 내부 키 사용)일 수도 있습니다.
키 파일은 편의를 위해 이름이 지정된 목록으로 저장된 여러 키를 포함할 수 있으며, 다음과 같이 보일 수 있습니다(아래 예제는 IBSurgeon Encryption Framework에서 가져온 것입니다):
Key=Red 0xec,0xa1,0x52,0xf6,0x4d,0x27,0xda,0x93,0x53,0xe5,0x48,0x86,0xb9,0x7d,0xe2,0x8f,0x3b,0xfa,0xb7,0x91,0x22,0x5b,0x59,0x15,0x82,0x35,0xf5,0x30,0x1f,0x04,0xdc,0x75,
Key=Green 0xab,0xd7,0x34,0x63,0xae,0x19,0x52,0x00,0xb8,0x84,0xa3,0x44,0xbd,0x11,0x9f,0x72,0xe0,0x04,0x68,0x4f,0xc4,0x89,0x3b,0x20,0x8d,0x2a,0xa7,0x07,0x32,0x3b,0x5e,0x74,
데이터베이스가 암호화되면 헤더 페이지는 암호화 플러그인과 키 이름에 대한 정보를 저장하기 위해 암호화되지 않은 상태로 유지되며, “gstat -h databasename” 명령으로 이 정보를 확인할 수 있습니다:
Database header page information:
....
Creation date Jan 11, 2017 15:12:20
Attributes force write, encrypted, plugin DBCRYPT
Variable header data:
Crypt checksum: MUB2NTJqchh9RshmP6xFAiIc2iI=
Key hash: ask88tfWbinvC6b1JvS9Mfuh47c=
Encryption key name: RED
Sweep interval: 0
*END*
DbCrypt는 여러 데이터베이스와 여러 키에 대한 페이지를 처리할 수 있습니다:

그림 7. 동일한 서버(즉, Firebird 인스턴스)의 여러 데이터베이스에 대한 여러 키
올바른 키 선택
개발자들은 종종 “플러그인이 어떤 키가 어떤 데이터베이스에 해당하는지 어떻게 인식하나요?“라는 질문을 합니다. 답은 매우 간단합니다: 데이터베이스의 헤더 페이지에 저장된 키 이름을 통해서입니다.
덜 자주 묻지만 여전히 중요한 질문은 - 키 이름이 헤더에 기록된 것과 같지만 키 값이 다르면 어떻게 될까요? 잘못된 키로 인한 페이지 읽기 오류를 방지하기 위해 DbCrypt 플러그인은 헤더에 암호화된 테스트 시퀀스(숫자 0…F)를 저장하고, 키가 활성화되면 플러그인은 샘플 데이터를 키로 암호화하고 그 해시를 저장된 결과와 비교하여 전달된 키 값이 실제로 이 특정 데이터베이스에 올바른지 확인합니다.
암호화 플러그인이 키를 직접 읽는 방식은 디버깅, 성능 테스트 등에 간단하고 유용합니다. 암호화를 투명한 방식으로 구현하기 때문입니다: 즉, 클라이언트 애플리케이션과 개발자 도구는 데이터베이스가 암호화되어 있다는 것을 알지 못합니다.
그러나 실제로는 애플리케이션의 데이터베이스 접근을 제한해야 합니다: 키를 가진 클라이언트 애플리케이션만 암호화된 데이터베이스에 연결할 수 있어야 합니다.
이를 위해 KeyHolder 플러그인이 필요하며, Firebird 네트워크 프로토콜을 통해 클라이언트 애플리케이션(일반적으로 다른 컴퓨터에 있음)에서 키를 가져옵니다.
2.3. 키 전송을 어떻게 보호할까요?
고객이 승인된 애플리케이션을 우회하여 암호화된 데이터베이스에 직접 접근하기로 결정한 상황에서 데이터베이스를 보호하고 싶을 수 있습니다(많은 공급업체가 읽기 전용 또는 읽기-쓰기 모두 직접 접근으로부터 데이터를 제한하려고 합니다).
이는 침입자가 서버에 접근할 수 있지만 키는 가지고 있지 않은 상황과 동일합니다.
서버 측에서 키를 가로채기 위한 다음과 같은 공격 시나리오를 고려해 봅시다:
- 침입자가 가짜 암호화 플러그인(DBCrypt.dll)을 만들어 서버에 배치하고, KeyHolder가 키를 전달할 때 가짜 DbCrypt가 키의 덤프를 만드는 경우:

그림 8. 가짜 DbCrypt.dll을 사용한 공격
- 침입자가 가짜 firebird.exe 파일을 만들어 덤프를 만드는 경우:

그림 9. 가짜 firebird.exe를 사용한 공격
이러한 공격으로부터 보호하기 위해, 암호화 및 키 관리 플러그인의 좋은 구현은 키 교환을 보호해야 합니다.
키 교환은 공개/개인 키 쌍을 사용한 비대칭 암호화로 보호할 수 있습니다.
이러한 키는 빌드 프로세스 중에 생성되어 특정 암호화 및 키 관리 플러그인 쌍에 내장됩니다. 최상의 보호를 위해 특별히 빌드된 DbCrypt/KeyHolder 쌍을 사용하는 것이 필요합니다.

DbCrypt와 KeyHolder가 키를 교환할 때 다음 프로토콜을 사용합니다(단순화되었지만 아이디어는 명확합니다):
DbCrypt → KeyHolder:
이 Salt로 데이터베이스 키를 제공하세요
KeyHolder:
DbCrypt의 salt를 사용하여 공개 키로 DbKey를 암호화합니다
암호화된 DbKey를 DbCrypt로 전송합니다
DbCrypt:
개인 키로 DbKey를 복호화합니다
salt의 정확성을 검증합니다
작업 준비 완료
KeyHolder 인스턴스 간의 키 교환과 클라이언트 애플리케이션과 KeyHolder 간의 키 교환에도 거의 동일한 프로토콜이 사용됩니다.
전송된 키의 암호화와 정확성은 플러그인 구현에 달려 있으며, Firebird 엔진은 “이 플러그인 인스턴스에서 저 플러그인 인스턴스로 N바이트를 보내는” 기본적인 저수준 전송 서비스만 제공한다는 점에 유의하세요.
서버 측 암호화 요약
- 암호화/복호화는 운영 체제 파일 캐시와 Firebird 페이지 캐시 간의 데이터 교환 중에 데이터베이스 암호화 플러그인(DbCrypt)에 의해 페이지 단위로 수행됩니다
- 키 관리는 DbCrypt가 키를 직접 읽는 간단한 방식으로 구현될 수 있지만, 일반적으로 키 관리 플러그인(KeyHolder)으로 수행됩니다
이제 클라이언트 애플리케이션이 암호화된 데이터베이스와 어떻게 작동하는지 알아봅시다.
3. Firebird 암호화가 클라이언트 측에서 어떻게 작동하나요?
3.1. 네이티브 애플리케이션
클라이언트 애플리케이션이 암호화된 데이터베이스에 연결할 때 어떤 일이 발생하는지 이해하기 위해, 네이티브 애플리케이션의 일반적인 비암호화 데이터베이스 연결 프로세스를 고려해 봅시다.
참고: 여기부터 아래까지 “네이티브"란 해당 애플리케이션이 fbclient.dll을 사용하여 서버와 네트워크 연결을 설정한다는 의미이며, 일반적으로 이러한 앱은 Delphi, C++, PHP로 빌드됩니다. 네이티브 애플리케이션과 달리 Java 및 .NET은 자체 버전의 프로토콜을 구현하며, 이는 아래에서 고려됩니다.
연결 프로세스:
- 클라이언트 애플리케이션이 클라이언트 라이브러리를 로드합니다
- fbclient.dll - 네이티브 Windows 앱
- libfbclient.so - 네이티브 Linux 앱
- 클라이언트 애플리케이션이 연결을 시작하며 다음을 전송합니다
- 사용자 이름, 예: SYSDBA
- 비밀번호, 예: masterkey
- 데이터베이스 경로/별칭
암호화된 데이터베이스의 경우 추가 단계가 필요합니다: 암호화 키의 이름과 값을 전달해야 합니다.
키 전달은 일반 연결 전에 수행되어야 한다는 점이 중요합니다. 데이터베이스 소유자 이름, 문자 집합 등을 포함한 메타데이터가 있는 데이터 페이지가 암호화되어 있기 때문입니다.
따라서 다음과 같은 결론이 나옵니다:
- 일반 연결 전에 키를 전달하기 위한 추가 네트워크 왕복이 필요합니다
- 클라이언트 애플리케이션에서 Firebird로의 키 전송은 비대칭 암호화 사용과 콜백 인터페이스 구현이 필요한 코딩을 요구하며, 상당히 복잡할 수 있습니다. 이 작업을 단순화하기 위해 플러그인 공급업체는 연결 코드 예제를 제공하거나, IBSurgeon 플러그인 프레임워크에서처럼 클라이언트 애플리케이션에서 키를 전송하기 위한 사용하기 쉬운 적절한 인터페이스를 구현하는 추가 라이브러리 fbcrypt.dll/libfbcrypt.so를 만듭니다.
네이티브 애플리케이션(fbclient.dll을 사용하는)을 암호화된 데이터베이스에 연결하려면 3개의 호출이 필요합니다. 아래는 Delphi 예제입니다(오류 처리가 없는 단순화된 버전):
BeforeConnect 이벤트 핸들러에서:
fbcrypt_init(PAnsiChar(‘C:\Firebird30.bclient.dll’));
fbcrypt_key(‘RED’, ‘0xec,0xa1,0x52,0xf6,...’));
fbcrypt_callback(nil);
// 그런 다음 평소처럼 연결
Database1.Active:=True;
아래 그림에서 네이티브 애플리케이션에서 암호화된 데이터베이스와의 연결 프로세스 개요를 볼 수 있습니다:

그림 10. 네이티브 애플리케이션의 암호화된 데이터베이스 연결 프로세스
멀티스레드 클라이언트 애플리케이션의 경우 스레드 안전성은 어떻습니까?
멀티스레드 클라이언트 애플리케이션 구현의 몇 가지 일반적인 사항을 상기시켜 드리겠습니다.
Firebird 2.5부터 애플리케이션 내의 여러 스레드는 단일 데이터베이스 첨부(attachment)를 안전하게 사용할 수 있습니다. 모든 필요한 동기화는 fbclient.dll 내부에서 수행되기 때문입니다.
그러나 이 경우 스레드는 첨부와 하나씩만 작업할 수 있습니다.
이는 데이터베이스와의 고성능 데이터 교환을 요구하지 않는 애플리케이션에는 적합합니다. 한 스레드가 다른 SQL을 실행 중일 때 다른 스레드가 SQL 쿼리를 수행하기 위해 기다려도 문제가 없다면, 여러 스레드 간에 1개의 첨부를 공유하는 간단한 모델을 사용하는 것이 더 쉽습니다.
애플리케이션이 SQL 쿼리를 병렬로 실행해야 하는 경우(즉, 본격적인 클라이언트 애플리케이션인 경우), 각 연결마다 별도의 스레드를 사용하는 것이 좋습니다.
암호화된 데이터베이스에 대한 첨부의 키 교환 상황은 조금 더 복잡합니다.
모든 첨부에서 클라이언트 라이브러리는 클라이언트에서 키를 전송하지만, 이는 클라이언트 애플리케이션의 스레드와 직접적인 관련이 없으며 상황은 사용된 API에 따라 다릅니다.
아시다시피 Firebird 클라이언트 라이브러리는 3.0부터 2가지 유형의 API를 제공합니다: 프로바이더 개념에 기반한 새로운 객체 지향 API와, 이전 Firebird 드라이버와의 호환성을 유지하기 위한 해결책으로 구현된 레거시 isc_ API입니다.
새로운 객체 지향 클라이언트 API를 사용하는 경우, 프로바이더를 생성하고 필요한 키를 제공한 다음 새 첨부에 사용하는 것으로 충분합니다.
isc_ 클라이언트 API를 사용하는 경우, 모든 첨부에 대해 클라이언트 라이브러리는 자체 임시 프로바이더를 생성하며, 이는 최종 사용자가 직접 보거나 액세스할 수 없습니다.
이 경우 키는 isc_attach_database가 호출된 스레드에서 정확히 전송되며, 스레드 로컬 저장소가 해당 키를 저장하는 데 사용됩니다.
실제로 거의 모든 클라이언트 라이브러리가 isc_ API를 사용하므로(현재 인기 있는 드라이버 중 Python 드라이버만 OO API를 사용), 암호화된 데이터베이스에 연결하는 각 스레드에서 fb_database_crypt_callback()을 호출해야 합니다.
키 전송 호출(FEPF 예제의 fbcrypt.dll 호출)은 연결이 설정될 동일한 스레드에서 연결 전에 수행되어야 합니다.
많은 데이터베이스로 작업할 때(예: 많은 클라이언트 데이터베이스를 가진 SaaS 웹 서버), fbcrypt_key()를 호출할 때마다 현재 연결과 연결된 KeyHolder 저장소에 키가 추가된다는 점을 기억하는 것이 중요합니다.
키 값은 연결 전에 설정되어야 하며, 첨부 후에는 키 값을 변경할 수 없습니다.
분리(detach)의 경우 키는 언로드되지 않으며, fbcrypt.dll이 언로드될 때까지 메모리에 유지됩니다.
3.2. Java 애플리케이션
Java 드라이버(JayBird)는 Firebird 연결 프로토콜의 자체 구현(순수 Java)을 가지고 있습니다. Jaybird 4(및 3.0.4+)는 버전 13 프로토콜의 순수 Java 구현에서 Firebird 3 데이터베이스 암호화 콜백 지원을 추가합니다.
" 현재 구현은 간단하며 연결 속성에서 정적 값으로 응답하는 것만 지원합니다. 데이터베이스 암호화에 대한 정적 값 응답은 재생 공격이나 의도하지 않은 키 노출로 쉽게 이어질 수 있으므로 매우 안전하지 않습니다.
Jaybird의 향후 버전(아마도 5)은 더 복잡한 콜백이 필요한 데이터베이스 암호화 플러그인에 대한 플러그인 지원을 도입할 것입니다.”
실질적으로 이는 연결 속성 dbCryptConfig에 암호화 콜백 값(일반적으로 키 이름과 키-값 쌍)을 설정해야 함을 의미합니다.
예를 들어:
edConnectionString.setText("jdbc:firebirdsql://localhost/g:/Databases/ODS12/crypt.fdb?lc_ctype=utf8&dbCryptConfig=MyKey:0xec,0xa1,0x52,0xf6,0x4d,0x27,0xda,0x93,0x53,0xe5,0x48,0x86,0xb9,0x7d,0xe2,0x8f,0x3b,0xfa,0xb7,0x91,0x22,0x5b,0x59,0x15,0x82,0x35,0xf5,0x30,0x1f,0x04,0xdc,0x75,");
base64로 문자열을 지정하는 것도 가능합니다 - readme에서:
" base64:: 접두사가 붙은 문자열은 나머지 문자열이 base64로 바이트로 디코딩됩니다.
= 패딩 문자는 선택 사항이지만, 존재하는 경우 유효해야 합니다(즉, 패딩을 사용하는 경우 길이에 맞는 올바른 수의 패딩 문자를 사용해야 합니다).
base64로 인코딩된 값에 +가 포함된 경우 JDBC URL에서 %2B로 이스케이프해야 합니다. Jaybird 3과의 역호환성을 위해 URL-safe 변형 base64로 전환할 수 없습니다.”
IBSurgeon의 키 관리 플러그인 구현에서 이러한 키 전송 방식은 다소 안전하지 않은 것으로 간주됩니다: 네트워크 프로토콜 암호화가 활성화되지 않은 경우( 참고로, 활성화하려면 firebird.conf에서 WireCrypt=Required로 설정하고 레거시 인증을 사용하지 마세요), 키는 WireShark와 같은 네트워크 트래픽 분석기로 쉽게 발견될 수 있습니다. 따라서 이러한 방식으로 키 전송을 활성화하려면 IBSurgeon 키 관리 플러그인의 KeyHolder.conf에서 UnsafeClient=true를 설정해야 합니다.
3.3 .NET 애플리케이션
Firebird.NET 프로바이더는 암호화된 데이터베이스에 대한 유사한 키 교환 방식을 구현하며 FEPF의 KeyHolder.conf에서 UnsafeClient=true 매개변수를 설정해야 합니다.
암호화된 데이터베이스에 대한 .NET 연결 문자열 예제:
string connectionString =
"User=SYSDBA;" +
"Password=masterkey;" +
"Database=G:\\Databases\\ODS12.RYPT.FDB;" +
"DataSource=localhost;" +
"Port=3053;" +
"Dialect=3;" +
"Charset=NONE;" +
"Role=;" +
"Connection lifetime=15;" +
"Pooling=true;" +
"MinPoolSize=0;" +
"MaxPoolSize=50;" +
"Packet Size=8192;" +
"ServerType=0;" +
"cryptkey = TXlLZXk6MHhlYywweG…...;";
암호화 키가 네이티브 애플리케이션 및 JayBird의 예제와 다르게 보이는 것을 알 수 있습니다. 이는 Base64 변환의 결과이기 때문입니다. .NET 또는 Java 애플리케이션용 키를 얻으려면 문자열에서 base64를 계산해야 합니다:
“MyKey:0xec,0xa1,0x52,0xf6,0x4d,0x27,0xda,0x93,0x53,0xe5,0x48,0x86,0xb9,0x7d,0xe2,0x8f,0x3b,0xfa,0xb7,0x91,0x22,0x5b,0x59,0x15,0x82,0x35,0xf5,0x30,0x1f,0x04,0xdc,0x75,”
그리고 연결 문자열 끝에 “;“와 함께 “cryptkey=xxx;” 매개변수로 사용합니다.
4. 설치 및 구성
데이터베이스 암호화 및 키 관리 플러그인을 사용하려면 Firebird 구성 파일 firebird.conf에서 암호화 플러그인의 이름을 지정해야 합니다:
KeyHolderPlugin = KeyHolder
또는 대안으로 databases.conf에서 암호화된 데이터베이스의 별칭에 대해:
myencrypted = C:\Temp\EMPLOYEE30.MPLOYEE30.FDB { KeyHolderPlugin = KeyHolder }
그런 다음 플러그인에 필요한 모든 파일이 서버에 있는지 확인해야 합니다.
아래 예제는 IBSurgeon의 FEPF에 대한 것이지만, 다른 플러그인도 대체로 유사합니다:
%FirebirdFolder$\plugins에서
• DbCrypt.dll
• DbCrypt.conf
• KeyHolder.dll
• KeyHolder.conf - 디버그 모드 전용!
%FirebirdFolder$ 폴더에 다음 파일을 넣으세요:
• fbcrypt.dll
• libcrypto-1_1-x64.dll
• libssl-1_1-x64.dll
• firebird.msg
그런 다음, 서버에서 테스트 암호화를 수행할 수 있습니다. 이를 위해 isql에서 다음을 실행합니다:
isql.exe localhost:C:\Temp\EMPLOYEE30.MPLOYEE30.FDB -user SYSDBA -pass masterkey
SQL>alter database encrypt with dbcrypt key red;
SQL> show database;
Database: localhost:C:\Temp\EMPLOYEE30.MPLOYEE30.FDB
….
ODS = 12.0
Database encrypted
Default Character set: NONE
Linux를 사용 중이라면 대소문자가 중요하다는 점을 기억하세요. 따라서 명령은 다음과 같습니다:
alter database encrypt with "DbCrypt" key Red;
이제 암호화된 데이터베이스에 대한 클라이언트 접근을 테스트할 수 있습니다. 이를 위해 KeyHolder.conf 구성 파일을 제거(또는 이름 변경 또는 편집)하고, 간단한 테스트 애플리케이션으로 암호화된 데이터베이스에 연결을 시도합니다.
이를 위해 클라이언트 앱이 있는 폴더에 다음 파일들을 넣어야 합니다:
- FEPF의 데모 앱 - CryptTest.exe (32비트)
- 필수 파일:
- fbclient.dll
- fbcrypt.dll
- libcrypto-1.1.dll
- libssl-1.1-x64.dll
- 선택 파일:
- firebird.conf
- plugins 폴더에
- ◦ KeyHolder.conf
- ◦ keyhodler.dll
일부 키 관리 플러그인 구현에서는 클라이언트 소프트웨어를 수정하지 않고도 클라이언트 라이브러리(fbclient.dll)에 키를 로드할 수 있습니다.
이를 통해 Firebird 개발자 도구(Firebird SQL Studio, DatabaseWorkbench, IBExpert, FlameRobin, RedExpert 등)의 투명한 작동과 Firebird 명령줄 도구(gfix.exe, nbackup.exe 등)의 투명한 사용이 가능합니다.
5. 암호화 진행 상황 추적 방법
Firebird는 활성 연결이 있을 때만 데이터베이스를 암호화합니다. 암호화 프로세스는 별도의 병렬 스레드에서 실행되며, 대용량 데이터베이스의 경우 전체 암호화에 상당한 시간이 걸릴 수 있습니다.
암호화 프로세스를 추적하려면 MON$에서 SQL 쿼리를 실행하거나:
select mon$crypt_page * 100.0 / mon$pages as Percent from mon$database;
commit;
특수 스위치와 함께 gstat 도구를 실행합니다:
gstat -e dbname
Database "D:\ENCDB\TESTENCRYPT.FDB"
Gstat execution time Tue Mar 16 11:45:11 2021
Database header page information:
Flags 0
Generation 10697
System Change Number 3
Page size 8192
ODS version 12.0
Oldest transaction 7053
Oldest active 7054
Oldest snapshot 7054
Next transaction 7054
Sequence number 0
Next attachment ID 17834
Implementation HW=Intel/i386 little-endian OS=Windows CC=MSVC
Shadow count 0
Page buffers 0
Next header page 0
Database dialect 3
Creation date Oct 9, 2019 6:42:31
Attributes encrypted, plugin DBCRYPT
Variable header data:
Database backup GUID: {866B4967-ED58-427E-A481-DB9206CEA2ED}
Crypt checksum: MUB2NTJqchh9RshmP6xFAiIc2iI=
Key hash: ask88tfWbinvC6b1JvS9Mfuh47c=
Encryption key name: RED
Database GUID: {323FE494-1771-4608-E99D-C1B69C84578B}
*END*
Data pages: total 105, encrypted 105, non-crypted 0
Index pages: total 95, encrypted 95, non-crypted 0
Blob pages: total 0, encrypted 0, non-crypted 0
Generator pages: total 1, encrypted 1, non-crypted 0
Gstat completion time Tue Mar 16 11:45:11 2021
gstat 실행은 시간이 오래 걸릴 수 있다는 점에 유의하세요.
6. 요약
- Firebird 데이터베이스 암호화는 데이터베이스의 정보를 비인가 접근으로부터 보호하는 강력한 기능입니다.
- 암호화 프로세스에는 서버 측 동적 라이브러리인 암호화 플러그인(보통 DbCrypt라고 함)과 대부분의 경우 키 관리 플러그인(보통 KeyHolder라고 함)이 필요합니다.
- DbCrypt 및 KeyHolder 플러그인의 안전하고 신뢰할 수 있는 구현은 가장 일반적인 공격 유형을 고려하여 이루어져야 합니다.
- 암호화된 데이터베이스로 작업하려면 클라이언트 애플리케이션이 암호화 키를 전송해야 합니다.
- 서버 측 암호화 플러그인의 설치 및 구성은 간단하며, firebird.conf/databases.conf에 1개의 매개변수와 여러 파일만 필요합니다.
- 암호화 프로세스는 시간이 오래 걸릴 수 있으며 별도의 백그라운드 스레드에서 수행됩니다. 진행 상황은 MON$ 호출 또는 gstat로 확인할 수 있습니다.
다음 단계는?
Firebird 데이터베이스 암호화에 대한 상세한 성능 테스트를 진행 중입니다. 일반적으로 성능은 4-8% 정도 감소하지만, 하드웨어와 Firebird 설정에 따라 다릅니다. 계속 지켜봐 주세요!
문의하기:
제안 사항, 오타, 오류 등과 모든 질문을 이메일로 보내주세요: [email protected]