반응형
CBOR 완벽 가이드 - 효율적인 데이터 교환 형식 활용 방법
CBOR(Concise Binary Object Representation)은 FIDO2, IoT, 블록체인 등 다양한 분야에서 활용되는 효율적인 바이너리 데이터 교환 형식입니다. JSON보다 최대 35% 작은 크기와 2~5배 빠른 처리 속도로 제한된 리소스 환경에서 필수적인 기술로 자리잡고 있습니다. 이 글에서는 CBOR의 기본 개념부터 실무 활용까지 모든 것을 상세히 다룹니다.

목차
1. CBOR이란 무엇인가
2. CBOR vs JSON 비교 분석
3. CBOR 데이터 타입과 인코딩
4. 프로그래밍 언어별 활용
5. 자주 묻는 질문 (FAQ)
#1. CBOR이란 무엇인가
CBOR(Concise Binary Object Representation)은 RFC 8949 인터넷 표준으로 제정된 바이너리 데이터 교환 형식입니다. 2013년 IETF에서 처음 표준화되었으며, 제한된 네트워크 환경과 리소스가 부족한 기기에서 효율적인 데이터 통신을 가능하게 합니다.
1) CBOR의 핵심 특징
CBOR이 주목받는 이유는 다음과 같은 강력한 장점 때문입니다.
(1) 효율적인 데이터 표현
작은 크기로 데이터를 표현하여 네트워크 대역폭을 절약합니다. 동일한 데이터를 JSON 대비 약 35% 작게 인코딩할 수 있으며, 특히 숫자와 바이너리 데이터에서 큰 효율을 보입니다.
① 정수 10은 단 1바이트(0x0A)로 표현
② 문자열 "hello"는 6바이트로 인코딩
③ 배열과 맵은 요소 개수 정보와 함께 효율적으로 저장
(2) 자기 기술적 형식
별도의 스키마 정의 없이 데이터 자체에 타입 정보가 포함되어 있습니다. 이는 JSON처럼 유연하게 사용할 수 있으면서도 바이너리의 효율성을 동시에 제공합니다.
(3) 빠른 처리 속도
단순한 인코딩 규칙으로 JSON 대비 2~5배 빠른 인코딩 및 디코딩이 가능합니다. 저전력 CPU를 탑재한 IoT 기기에서도 무리 없이 처리할 수 있습니다.
. . . . .
2) CBOR의 탄생 배경
CBOR은 기존 데이터 형식들의 한계를 극복하기 위해 개발되었습니다.
| 기존 형식 | 한계점 | CBOR의 해결책 |
|---|---|---|
| JSON | 텍스트 형식으로 크기가 크고 파싱 비용이 높음 | 바이너리 형식으로 크기 축소 및 빠른 처리 |
| XML | 매우 복잡하고 용량이 큼 | 간결한 구조로 단순화 |
| Protocol Buffers | 스키마 정의 필수, 복잡한 설정 | 스키마 없이 즉시 사용 가능 |
CBOR은 2020년 RFC 8949로 업데이트되면서 보안 기능과 확장성이 더욱 강화되었습니다. 특히 센서 네트워크, IoT 디바이스, 모바일 환경에서 효율적인 통신을 목표로 설계되었습니다.
. . . . .
3) CBOR 주요 활용 분야
CBOR은 다양한 산업 분야에서 실제로 활용되고 있습니다.
(1) FIDO2 인증
FIDO2 표준에서 인증 데이터 교환 형식으로 CBOR을 공식 채택했습니다. WebAuthn API와 CTAP2 프로토콜에서 생체 인증 정보와 공개키 자격 증명을 CBOR 형식으로 전송합니다.
(2) IoT 및 센서 네트워크
제한된 배터리와 메모리를 가진 IoT 기기에서 CBOR은 필수적입니다. CoAP 프로토콜과 함께 사용되어 경량 HTTP 통신을 구현합니다.
① 스마트 홈 센서 데이터 전송
② 산업용 모니터링 시스템
③ 웨어러블 디바이스 통신
(3) 블록체인과 암호화폐
Cardano 블록체인은 기본 직렬화 형식으로 CBOR을 사용하며, IPFS(InterPlanetary File System)도 내부적으로 CBOR을 활용합니다.
#2. CBOR vs JSON 비교 분석
CBOR과 JSON은 모두 데이터 교환 형식이지만, 설계 철학과 성능 특성에서 중요한 차이가 있습니다.
1) 기본 특성 비교
| 특성 | CBOR | JSON |
|---|---|---|
| 형식 | 바이너리 | 텍스트 |
| 크기 | 작음 (약 35% 절감) | 큼 |
| 가독성 | 사람이 직접 읽기 어려움 | 사람이 읽고 편집하기 쉬움 |
| 처리 속도 | 빠름 (2~5배) | 상대적으로 느림 |
| 데이터 타입 | 풍부 (정수, 실수, 바이너리, 태그 등) | 제한적 (숫자, 문자열, 배열, 객체) |
| 확장성 | 높음 (태그 시스템 지원) | 제한적 |
. . . . .
2) 실제 크기 비교 예시
동일한 데이터를 JSON과 CBOR로 인코딩했을 때의 차이를 살펴보겠습니다.
// JSON 형식 (84 바이트)
{
"name": "John Doe",
"age": 28,
"isActive": true,
"hobbies": ["reading", "swimming", "cycling"]
}
// CBOR 형식 (약 54 바이트)
// 16진수: A4 64 6E 61 6D 65 68 4A 6F 68 6E 20 44 6F 65 ...
// 약 35% 크기 절감 효과
{
"name": "John Doe",
"age": 28,
"isActive": true,
"hobbies": ["reading", "swimming", "cycling"]
}
// CBOR 형식 (약 54 바이트)
// 16진수: A4 64 6E 61 6D 65 68 4A 6F 68 6E 20 44 6F 65 ...
// 약 35% 크기 절감 효과
복잡한 데이터 구조일수록 CBOR의 크기 절감 효과는 더욱 커집니다. 특히 바이너리 데이터나 큰 숫자를 다룰 때 CBOR의 효율성이 극대화됩니다.
. . . . .
3) 성능 비교 분석
실제 애플리케이션에서 측정한 성능 차이는 다음과 같습니다.
(1) 인코딩 및 디코딩 속도
① 인코딩 속도: CBOR이 JSON 대비 2~3배 빠름
② 디코딩 속도: CBOR이 JSON 대비 3~5배 빠름
③ 메모리 사용량: CBOR이 약 30% 적게 사용
(2) 네트워크 전송 효율
모바일 환경에서 CBOR 사용 시 데이터 사용량이 크게 줄어들어 배터리 수명과 통신 비용을 절감할 수 있습니다.
① 전송 시간 단축: 작은 크기로 인한 전송 속도 향상
② 대역폭 절약: 제한된 네트워크 환경에서 유리
③ 배터리 효율: 빠른 처리로 전력 소비 감소
#3. CBOR 데이터 타입과 인코딩
CBOR의 효율성은 간결한 인코딩 방식에서 비롯됩니다. 각 데이터 타입이 어떻게 표현되는지 이해하면 더 효과적으로 활용할 수 있습니다.
1) 기본 데이터 타입
CBOR은 8가지 메이저 타입으로 모든 데이터를 표현합니다.
| 메이저 타입 | 번호 | 설명 | 예시 |
|---|---|---|---|
| 부호 없는 정수 | 0 | 0부터 2^64-1까지의 정수 | 10 → 0x0A |
| 음수 | 1 | -1부터 -2^64까지의 정수 | -10 → 0x29 |
| 바이트 문자열 | 2 | 바이너리 데이터 | 이미지, 파일 등 |
| 텍스트 문자열 | 3 | UTF-8 인코딩된 문자열 | "hello" |
| 배열 | 4 | 데이터 항목의 시퀀스 | [1, 2, 3] |
| 맵 | 5 | 키-값 쌍의 집합 | {"name": "John"} |
| 태그 | 6 | 추가 의미 정보 부여 | 날짜/시간, URL 등 |
| 플로트/심플 | 7 | 부동소수점, 특수 값 | 3.14, true, false, null |
. . . . .
2) 인코딩 방식 이해하기
CBOR의 인코딩은 초기 바이트 + 추가 정보 + 데이터 구조를 따릅니다.
(1) 초기 바이트 구조
초기 바이트는 8비트로 구성되며, 상위 3비트는 메이저 타입을, 하위 5비트는 추가 정보를 나타냅니다.
// 초기 바이트 구조
[메이저 타입 3비트] [추가 정보 5비트]
// 예: 정수 10
000 (메이저 타입 0) + 01010 (값 10) = 0x0A
// 예: 문자열 "hello" (길이 5)
011 (메이저 타입 3) + 00101 (길이 5) = 0x65
이어서: 0x68 0x65 0x6C 0x6C 0x6F ("hello"의 UTF-8 바이트)
[메이저 타입 3비트] [추가 정보 5비트]
// 예: 정수 10
000 (메이저 타입 0) + 01010 (값 10) = 0x0A
// 예: 문자열 "hello" (길이 5)
011 (메이저 타입 3) + 00101 (길이 5) = 0x65
이어서: 0x68 0x65 0x6C 0x6C 0x6F ("hello"의 UTF-8 바이트)
(2) 정수 인코딩 효율
CBOR은 값의 크기에 따라 자동으로 최적화된 바이트 수를 사용합니다.
① 0~23: 1바이트 (초기 바이트에 직접 포함)
② 24~255: 2바이트 (초기 바이트 + 1바이트 값)
③ 256~65535: 3바이트 (초기 바이트 + 2바이트 값)
④ 더 큰 값: 5바이트 또는 9바이트
. . . . .
3) 복합 데이터 인코딩 예제
간단한 JSON 객체를 CBOR로 인코딩하는 과정을 살펴보겠습니다.
// JSON 원본
{
"name": "Alice",
"age": 30
}
// CBOR 인코딩 과정
0xA2 // 맵, 2개 항목
0x64 0x6E 0x61 0x6D 0x65 // "name" (길이 4 + UTF-8)
0x65 0x41 0x6C 0x69 0x63 0x65 // "Alice" (길이 5 + UTF-8)
0x63 0x61 0x67 0x65 // "age" (길이 3 + UTF-8)
0x18 0x1E // 30 (24 이상이므로 2바이트)
// 총 18바이트 (JSON 23바이트 대비 약 22% 절감)
{
"name": "Alice",
"age": 30
}
// CBOR 인코딩 과정
0xA2 // 맵, 2개 항목
0x64 0x6E 0x61 0x6D 0x65 // "name" (길이 4 + UTF-8)
0x65 0x41 0x6C 0x69 0x63 0x65 // "Alice" (길이 5 + UTF-8)
0x63 0x61 0x67 0x65 // "age" (길이 3 + UTF-8)
0x18 0x1E // 30 (24 이상이므로 2바이트)
// 총 18바이트 (JSON 23바이트 대비 약 22% 절감)
이처럼 CBOR은 데이터 구조를 최소한의 바이트로 효율적으로 표현합니다.
(3) 태그 시스템
CBOR의 태그는 데이터에 추가 의미를 부여합니다. 표준 태그 번호가 정의되어 있어 날짜/시간, URL, 정규식 등을 명확하게 표현할 수 있습니다.
① 태그 0: 날짜/시간 (RFC 3339 형식)
② 태그 1: Unix 타임스탬프
③ 태그 32: URL 문자열
④ 태그 35: 정규식
#4. 프로그래밍 언어별 활용
대부분의 주요 프로그래밍 언어에서 CBOR을 쉽게 사용할 수 있도록 안정적인 라이브러리가 제공됩니다.
1) JavaScript/TypeScript
웹 및 Node.js 환경에서 CBOR을 활용하는 방법입니다.
// cbor-js 라이브러리 사용 예제
import * as CBOR from 'cbor-js';
// 인코딩
const data = {
name: "John",
age: 30,
hobbies: ["reading", "coding"]
};
const encoded = CBOR.encode(data);
// 디코딩
const decoded = CBOR.decode(encoded);
console.log(decoded);
// 주요 라이브러리
// - cbor-js: 기본 구현체
// - cbor-x: 고성능 구현 (추천)
// - cbor-web: 브라우저 최적화
import * as CBOR from 'cbor-js';
// 인코딩
const data = {
name: "John",
age: 30,
hobbies: ["reading", "coding"]
};
const encoded = CBOR.encode(data);
// 디코딩
const decoded = CBOR.decode(encoded);
console.log(decoded);
// 주요 라이브러리
// - cbor-js: 기본 구현체
// - cbor-x: 고성능 구현 (추천)
// - cbor-web: 브라우저 최적화
. . . . .
2) Python
Python에서는 cbor2 라이브러리가 가장 널리 사용됩니다.
# cbor2 라이브러리 설치
# pip install cbor2
import cbor2
# 인코딩
data = {
"name": "John",
"age": 30,
"hobbies": ["reading", "coding"]
}
encoded = cbor2.dumps(data)
# 디코딩
decoded = cbor2.loads(encoded)
print(decoded)
# 파일 입출력
with open('data.cbor', 'wb') as f:
cbor2.dump(data, f)
with open('data.cbor', 'rb') as f:
loaded_data = cbor2.load(f)
# pip install cbor2
import cbor2
# 인코딩
data = {
"name": "John",
"age": 30,
"hobbies": ["reading", "coding"]
}
encoded = cbor2.dumps(data)
# 디코딩
decoded = cbor2.loads(encoded)
print(decoded)
# 파일 입출력
with open('data.cbor', 'wb') as f:
cbor2.dump(data, f)
with open('data.cbor', 'rb') as f:
loaded_data = cbor2.load(f)
. . . . .
3) Java
Java에서는 jackson-dataformat-cbor가 많이 사용됩니다.
// Maven 의존성
// <dependency>
// <groupId>com.fasterxml.jackson.dataformat</groupId>
// <artifactId>jackson-dataformat-cbor</artifactId>
// </dependency>
import com.upokecenter.cbor.*;
import java.util.*;
// 데이터 생성
Map<String, Object> map = new HashMap<>();
map.put("name", "John");
map.put("age", 30);
map.put("hobbies", Arrays.asList("reading", "coding"));
// 인코딩
CBORObject cbor = CBORObject.FromObject(map);
byte[] encoded = cbor.EncodeToBytes();
// 디코딩
CBORObject decoded = CBORObject.DecodeFromBytes(encoded);
System.out.println(decoded.toString());
// <dependency>
// <groupId>com.fasterxml.jackson.dataformat</groupId>
// <artifactId>jackson-dataformat-cbor</artifactId>
// </dependency>
import com.upokecenter.cbor.*;
import java.util.*;
// 데이터 생성
Map<String, Object> map = new HashMap<>();
map.put("name", "John");
map.put("age", 30);
map.put("hobbies", Arrays.asList("reading", "coding"));
// 인코딩
CBORObject cbor = CBORObject.FromObject(map);
byte[] encoded = cbor.EncodeToBytes();
// 디코딩
CBORObject decoded = CBORObject.DecodeFromBytes(encoded);
System.out.println(decoded.toString());
. . . . .
4) Go
Go 언어에서는 fxamacker/cbor이 권장됩니다.
// go get github.com/fxamacker/cbor/v2
package main
import (
"fmt"
"github.com/fxamacker/cbor/v2"
)
type Person struct {
Name string `cbor:"name"`
Age int `cbor:"age"`
Hobbies []string `cbor:"hobbies"`
}
func main() {
// 인코딩
p := Person{
Name: "John",
Age: 30,
Hobbies: []string{"reading", "coding"},
}
encoded, _ := cbor.Marshal(p)
// 디코딩
var decoded Person
cbor.Unmarshal(encoded, &decoded)
fmt.Printf("%+v\n", decoded)
}
package main
import (
"fmt"
"github.com/fxamacker/cbor/v2"
)
type Person struct {
Name string `cbor:"name"`
Age int `cbor:"age"`
Hobbies []string `cbor:"hobbies"`
}
func main() {
// 인코딩
p := Person{
Name: "John",
Age: 30,
Hobbies: []string{"reading", "coding"},
}
encoded, _ := cbor.Marshal(p)
// 디코딩
var decoded Person
cbor.Unmarshal(encoded, &decoded)
fmt.Printf("%+v\n", decoded)
}
. . . . .
5) 실무 활용 팁
프로덕션 환경에서 CBOR을 사용할 때 주의할 점입니다.
(1) 보안 고려사항
① 입력 검증 필수: 신뢰할 수 없는 소스의 CBOR 데이터는 반드시 검증
② 깊이 제한: 깊게 중첩된 구조는 스택 오버플로우 위험
③ 크기 제한: 메모리 소진 공격 방지를 위한 최대 크기 설정
(2) 성능 최적화
① 스트리밍 파싱: 대용량 데이터는 스트리밍 방식 사용
② 객체 재사용: 메모리 풀링으로 가비지 컬렉션 부하 감소
③ 버퍼 크기 조정: 적절한 버퍼 크기로 I/O 효율 향상
#5. 자주 묻는 질문 (FAQ)
1) Q: CBOR은 JSON을 완전히 대체할 수 있나요?
A: CBOR은 JSON의 모든 데이터 타입을 표현할 수 있으며 추가로 바이너리 데이터와 태그도 지원합니다. 하지만 사람이 직접 읽고 편집하기 어렵다는 단점이 있어 디버깅이 중요한 개발 단계에서는 JSON이 더 유리합니다. 프로덕션 환경에서 성능과 효율이 중요하다면 CBOR이, 개발 편의성이 중요하다면 JSON이 적합합니다.
. . . . .
2) Q: CBOR 데이터를 어떻게 디버깅하나요?
A: cbor.me, cbor.io 같은 온라인 도구를 사용하면 CBOR 바이너리를 JSON으로 변환하여 확인할 수 있습니다. 또한 명령줄에서는
hexdump -C data.cbor로 16진수 덤프를 확인하거나, Python의 python -m cbor2.tool 명령으로 CBOR 데이터를 변환할 수 있습니다.
. . . . .
3) Q: CBOR은 JSON보다 얼마나 빠른가요?
A: 일반적으로 인코딩은 2~3배, 디코딩은 3~5배 빠릅니다. 특히 숫자나 바이너리 데이터가 많을수록 성능 차이가 더 커집니다. 다만 실제 성능은 구현체와 데이터 특성에 따라 달라질 수 있으므로, 프로덕션 적용 전 벤치마크 테스트를 권장합니다.
. . . . .
4) Q: 웹 브라우저에서 CBOR을 사용할 수 있나요?
A: 네, cbor-web이나 cbor-x 같은 라이브러리를 사용하면 브라우저에서도 CBOR을 활용할 수 있습니다. WebSocket이나 Fetch API와 함께 사용하여 서버와 효율적으로 통신할 수 있습니다. 다만 브라우저 개발자 도구에서는 바이너리 데이터로 표시되므로 디버깅 시 별도 도구가 필요합니다.
. . . . .
5) Q: CBOR과 Protocol Buffers의 차이는 무엇인가요?
A: Protocol Buffers는 스키마 정의가 필수이지만 CBOR은 스키마 없이 즉시 사용할 수 있습니다. Protocol Buffers는 사전에 .proto 파일로 데이터 구조를 정의해야 하고 코드 생성이 필요하지만, CBOR은 JSON처럼 자유롭게 사용할 수 있습니다. 대신 Protocol Buffers가 약간 더 작은 크기를 제공할 수 있습니다.
. . . . .
6) Q: IoT 프로젝트에서 CBOR 사용 시 주의할 점은?
A: 메모리와 전력 제약을 고려해야 합니다. 경량 구현체인 tinycbor(C/C++) 사용을 권장하며, 깊이와 크기 제한을 설정하여 메모리 소진을 방지해야 합니다. 또한 CoAP 프로토콜과 함께 사용하면 최적의 효율을 얻을 수 있습니다. 배터리 소모를 줄이기 위해 데이터 전송 빈도도 조절해야 합니다.
. . . . .
7) Q: CBOR 라이브러리 간 호환성은 보장되나요?
A: RFC 8949 표준을 준수하는 라이브러리 간에는 호환성이 보장됩니다. 다만 비표준 태그나 확장 기능을 사용하면 호환성 문제가 발생할 수 있으므로, 여러 플랫폼 간 통신 시에는 표준 기능만 사용하는 것을 권장합니다. 결정적 인코딩(Deterministic Encoding)이 필요한 경우 라이브러리가 이를 지원하는지 확인해야 합니다.
. . . . .
8) Q: CBOR의 미래 전망은 어떤가요?
A: IoT, 5G, 엣지 컴퓨팅의 확산으로 CBOR의 활용은 지속적으로 증가할 것으로 예상됩니다. 특히 COSE(CBOR Object Signing and Encryption)를 통한 보안 기능 강화, CDDL(Concise Data Definition Language)을 통한 스키마 지원 등 생태계가 계속 발전하고 있습니다. FIDO2, WebAuthn 등 주요 표준에서 채택되면서 안정성도 검증되었습니다.
. . . . .
9) Q: CBOR 데이터를 파일로 저장할 때 확장자는?
A: 일반적으로
.cbor 확장자를 사용합니다. MIME 타입은 application/cbor입니다. HTTP 헤더에서 Content-Type을 설정할 때도 이 값을 사용하면 됩니다. 파일 저장 시 바이너리 모드로 쓰고 읽어야 하며, 텍스트 모드로 처리하면 데이터가 손상될 수 있습니다.
. . . . .
10) Q: CBOR을 RESTful API에 적용하려면?
A: 클라이언트와 서버 모두 CBOR 인코딩/디코딩을 지원해야 합니다. Accept와 Content-Type 헤더를
application/cbor로 설정하고, 서버는 요청 헤더를 확인하여 JSON 또는 CBOR 응답을 선택적으로 제공하는 것이 좋습니다. 기존 JSON API와의 호환성을 위해 클라이언트가 Accept 헤더로 원하는 형식을 명시하도록 구현하면 유연한 마이그레이션이 가능합니다.
마무리
CBOR은 효율성과 유연성을 동시에 제공하는 현대적인 데이터 교환 형식입니다. JSON보다 작은 크기와 빠른 처리 속도로 IoT, 모바일, 블록체인 등 다양한 분야에서 핵심 기술로 자리잡고 있습니다.
특히 FIDO2 인증, CoAP 프로토콜, Cardano 블록체인 등 주요 표준과 프로젝트에서 CBOR을 채택하면서 그 가치가 입증되었습니다. RFC 8949 표준을 준수하는 다양한 라이브러리가 제공되어 JavaScript, Python, Java, Go 등 모든 주요 언어에서 쉽게 활용할 수 있습니다.
CBOR 도입을 고려 중이라면 먼저 프로젝트의 특성을 분석하세요. 네트워크 대역폭이 제한적이거나, 처리 속도가 중요하거나, 배터리 효율이 필요한 환경이라면 CBOR이 탁월한 선택이 될 것입니다. 반면 사람이 직접 데이터를 확인하고 수정해야 하는 개발 단계에서는 JSON과 병행하는 것이 효율적입니다.
CBOR의 생태계는 COSE, CDDL, CWT 등의 표준과 함께 지속적으로 발전하고 있습니다. 5G와 IoT의 확산, 엣지 컴퓨팅의 성장으로 효율적인 데이터 형식의 중요성은 더욱 커질 것이며, CBOR은 이러한 미래 기술의 핵심 인프라로 자리매김할 것입니다.
긴 글 읽어주셔서 감사합니다.
끝.
끝.
반응형
'Development > Etc' 카테고리의 다른 글
| [Etc] Windows에서 해시(Hash)로 명령어부터 GUI 도구까지 파일 비교하는 방법 총정리 (0) | 2023.01.25 |
|---|---|
| [Etc] Git에서 HEAD 의미 (0) | 2022.09.28 |
| [Etc] 웹사이트 주소로 IP 주소 알아내는 방법 (0) | 2020.04.08 |
| [ETC] JWT 완벽 가이드 : 개념부터 실적 적용까지 (0) | 2019.09.11 |
| [Etc] CDN 완벽 가이드 : 개념부터 실전 적용까지 (0) | 2016.03.23 |