[EXT-010][실무] 같은 JSON을 항상 같은 바이트로 만들기 > IT 기술 공유

본문 바로가기
사이트 내 전체검색

IT 기술 공유

[EXT-010][실무] 같은 JSON을 항상 같은 바이트로 만들기

페이지 정보

profile_image
작성자 기술팀장
댓글 0건 조회 23회 작성일 26-09-07 23:38

본문

[이번 수업]
두 JSON 객체의 내용이 같아도 키 순서와 공백이 다르면 파일 바이트와 해시가 달라집니다. 이번에는 정규 JSON(canonical JSON, 같은 데이터를 언제나 같은 바이트로 표현하는 규칙)이 왜 필요한지 배우고, 작은 자료를 일정한 형식으로 직렬화해 비교합니다.

[선수지식]
JSON 객체·배열·문자열·숫자를 알고 UTF-8과 SHA-256의 역할을 설명할 수 있으면 됩니다. 직렬화는 메모리의 값을 저장하거나 전송할 바이트 표현으로 바꾸는 과정입니다.

[학습목표]
1. 값의 동등성과 바이트의 동일성을 구분한다.
2. 정해진 규칙으로 JSON 키·공백·문자 인코딩을 고정한다.
3. 서명·캐시 키에 정규화된 바이트를 안전하게 사용한다.

[핵심개념]
JSON 표준에서 객체는 이름과 값의 순서 없는 모음입니다. 따라서 `{"a":1,"b":2}`와 `{"b":2,"a":1}`은 같은 정보를 표현할 수 있지만 원본 바이트는 다릅니다. 공백, 줄바꿈, 문자 이스케이프, 숫자 표기도 여러 방식이 가능합니다. 바이트를 입력으로 받는 해시나 디지털 서명은 이런 차이에도 전혀 다른 결과를 냅니다.

RFC 8785의 JSON Canonicalization Scheme(JCS)은 I-JSON 제약을 바탕으로 문자열·숫자 표현과 객체 속성 정렬을 정해 재현 가능한 바이트를 만듭니다. 문자열 정규화는 자동 적용되지 않으므로 제품 정책이 있다면 먼저 같은 규칙을 적용합니다. 중복 속성 이름과 NaN·Infinity 같은 JSON 밖의 숫자는 허용하지 않아야 합니다.

언어의 `키 정렬` 옵션만으로 완전한 JCS가 되지는 않습니다. 숫자 출력과 유니코드 키 정렬은 구현마다 다를 수 있습니다. 여러 언어가 서명값을 공유하면 RFC 8785 호환 라이브러리와 공식 테스트 벡터를 사용하고, 정규화 버전도 계약에 명시합니다. 정규화는 검증·암호화·인가를 대신하지 않습니다.

[따라하기]
아래를 canonical_demo.py로 저장합니다. 이 함수는 문자열과 정수로 된 작은 예제를 위한 학습용 부분집합이며 완전한 JCS 구현이 아닙니다.

```python
import hashlib
import json

def canonical_demo(value):
    text = json.dumps(
        value,
        ensure_ascii=False,
        sort_keys=True,
        separators=(",", ":"),
        allow_nan=False,
    )
    return text.encode("utf-8")

left = {"name": "테스트", "count": 2}
right = {"count": 2, "name": "테스트"}
one = canonical_demo(left)
two = canonical_demo(right)

print("객체 같음:", left == right)
print("바이트 같음:", one == two)
print("정규화 예:", one.decode("utf-8"))
print("SHA-256 같음:", hashlib.sha256(one).digest() == hashlib.sha256(two).digest())
```

macOS/Linux는 `python3 canonical_demo.py`, Windows는 `py canonical_demo.py`로 실행합니다. 예상 결과입니다.

```text
객체 같음: True
바이트 같음: True
정규화 예: {"count":2,"name":"테스트"}
SHA-256 같음: True
```

다른 언어와 결과를 교환할 때는 JCS 적합성을 확인한 구현을 선택하세요. 해시 계산과 서명 검증 양쪽에서 완전히 같은 정규화 절차를 거쳐야 합니다.

[흔한 실수]
파싱 전 원문 JSON과 파싱 후 다시 만든 JSON을 같은 것으로 생각하면 서명이 어긋날 수 있습니다. 보기 좋게 들여쓰기를 바꾸거나 키 정렬만 켜고 모든 숫자가 호환된다고 믿는 것도 실수입니다. 객체의 중복 키를 허용하면 파서마다 선택하는 값이 달라질 수 있으므로 입력 단계에서 거부합니다.

[보안 주의]
본인 소유의 로컬·격리 환경에서만 실습하세요. SHA-256 해시는 데이터 변경 확인에 도움을 주지만 누가 만들었는지는 증명하지 않습니다. 발신자 인증이 필요하면 검증된 서명 또는 메시지 인증 방식을 사용하고 키를 코드에 넣지 않습니다. 외부 JSON에는 크기·중첩 깊이·숫자 범위를 제한하고, 검증한 값만 정규화하세요.

[직접 해볼 과제]
`active: true`와 `tags: ["a", "b"]`를 두 객체에 서로 다른 키 순서로 추가해 바이트가 같은지 확인하세요. 이어 `float("nan")`을 넣어 `allow_nan=False`가 오류를 내는지 검사하고, 학습 함수가 완전한 JCS가 아닌 이유를 한 문장으로 적으세요.

[확인문제]
1. 내용이 같은 JSON의 SHA-256이 다를 수 있는 이유는 무엇입니까?
2. 단순한 키 정렬만으로 완전한 JCS가 되지 않는 이유는 무엇입니까?
3. 정규화가 입력 검증이나 발신자 인증을 대신할 수 없는 이유는 무엇입니까?

[다음 학습]
다음에는 JSON Schema로 필수 속성·자료형·값의 범위를 검사하고 오류 위치를 알려 주는 방법을 배웁니다.

[공식 참고 자료]
- IETF RFC 8785 JSON Canonicalization Scheme: https://www.rfc-editor.org/rfc/rfc8785.html
- IETF RFC 8259 JSON 표준: https://www.rfc-editor.org/rfc/rfc8259.html
- IETF RFC 7493 I-JSON: https://www.rfc-editor.org/rfc/rfc7493.html
- Python json 공식 문서: https://docs.python.org/3/library/json.html
- Python hashlib 공식 문서: https://docs.python.org/3/library/hashlib.html

댓글목록

등록된 댓글이 없습니다.

회원로그인

회원가입

사이트 정보

회사명 : 회사명 / 대표 : 대표자명
주소 : OO도 OO시 OO구 OO동 123-45
사업자 등록번호 : 123-45-67890
전화 : 02-123-4567 팩스 : 02-123-4568
통신판매업신고번호 : 제 OO구 - 123호
개인정보관리책임자 : 정보책임자명

접속자집계

오늘
4,802
어제
6,862
최대
16,772
전체
770,753
Copyright © 소유하신 도메인. All rights reserved.