Daily CS) JSON

goldenGlow_21·2024년 12월 12일
0

Daily CS

목록 보기
18/50

JSON

JavaScript Object Notation

JSON은 데이터 교환 형식으로 널리 사용되는 경량 텍스트 기반 구조이다. 꼭 컴퓨터공학을 배우지 않아도 알고 있는 사람이 있을 만큼 흔하고, 널리 쓰이는 형식이다. 대충 뭔지는 누구나 알지만, 늘 그렇듯 제대로 공부하고 싶다면 거기서 멈춰선 안된다. 한 발자국 더 들어가 알아보자.


1. JSON의 개요

1.1 JSON의 정의와 특징

JSON (JavaScript Object Notation) 은 데이터를 저장하거나 교환하기 위한 경량 텍스트 기반 데이터 형식이다. 원래는 JavaScript 에서 파생되었지만, 현재는 프로그래밍 언어와 독립적으로 사용되며 대부분의 언어에서 JSON을 생성하고 처리할 수 있다.

JSON은 사람이 읽고 쓰기 쉽고, 기계가 파싱하고 생성하기에도 간단하도록 설계되었다. 데이터는 키-값 쌍(Key-Value Pair) 또는 중첩된 데이터 구조(객체와 배열)로 표현되며, 이를 통해 복잡한 데이터도 간결하게 저장할 수 있다.

특징

  1. 간결성: 데이터 표현이 짧고 이해하기 쉽다.
  2. 확장성: 중첩 구조를 통해 복잡한 데이터 구조를 표현 가능하다.
  3. 플랫폼 독립성: 텍스트 기반이므로 모든 환경에서 사용 가능하다.
  4. 표준화: JSON 형식은 명확히 정의되어 있어 데이터 교환 시 일관성을 유지한다.

JSON은 API, 데이터베이스, 설정 파일 등 다양한 분야에서 널리 사용되며, 특히 웹 애플리케이션과 RESTful API에서 필수적인 데이터 포맷으로 자리 잡고 있다.

1.2 JSON의 역사와 발전 배경

JSON은 2001년 Douglas Crockford에 의해 설계되었다. 그는 복잡한 데이터 교환 형식이었던 XML의 대안을 모색하던 중, JavaScript 객체의 문법을 기반으로 하는 간단한 데이터 형식을 제안했다. JSON은 가볍고, 사람이 읽기 쉬우며, JavaScript와의 호환성이 뛰어나 빠르게 인기를 얻었다.

JSON은 초기에는 비공식적인 포맷으로 사용되었으나, 2013년 RFC 7159로 공식 표준화되었고, 이후 ECMA-404를 통해 JSON 문법이 정의되었다. 이는 JSON이 단순히 웹 애플리케이션뿐만 아니라 데이터베이스, 클라우드 컴퓨팅, IoT 등 다양한 분야에서 데이터 교환의 표준으로 자리 잡는 데 기여했다.

JSON의 발전은 AJAX(Asynchronous JavaScript and XML) 의 부상과 함께 이루어졌다. AJAX 기술은 동적인 웹 애플리케이션 개발을 가능하게 했고, JSON은 AJAX 요청과 응답에서 데이터를 전달하는 주요 포맷으로 채택되었다. 이후, RESTful API와 클라이언트-서버 간 통신에서도 JSON이 사실상의 표준으로 자리 잡았다.

1.3 JSON과 다른 데이터 형식 비교 (XML, YAML 등)

JSON은 XML과 YAML과 같은 다른 데이터 형식과 비교했을 때 여러 장단점을 가진다.

JSON vs XML

  • 단순성: JSON은 XML보다 문법이 간결하고, 가독성이 뛰어나다.
    - JSON: {"name": "John", "age": 30}
    • XML: <person><name>John</name><age>30</age></person>
  • 데이터 크기: JSON은 태그를 사용하지 않아 XML보다 데이터 크기가 작다.
  • 처리 속도: JSON은 대부분의 언어에서 내장된 파서(Parser)로 처리 가능하며, XML은 추가 라이브러리를 필요로 하는 경우가 많다.
  • 스키마 지원: XML은 XSD(스키마 정의)를 통해 엄격한 구조를 지원하지만, JSON은 기본적으로 스키마가 없으며, 이를 보완하기 위해 JSON Schema를 사용한다.

JSON vs YAML

  • 가독성: YAML은 JSON보다 사람이 읽고 쓰기 쉬운 문법을 제공하며, 공백과 들여쓰기를 이용해 구조를 나타낸다.
# YAML
name: John  
age: 30  

# JSON
{"name": "John", "age": 30}  
  • 복잡성: YAML은 추가적인 기능(주석, 앵커 등)을 지원하지만, JSON보다 문법이 복잡하고 파싱 오류의 가능성이 크다.
  • 호환성: JSON은 대부분의 언어와 라이브러리에서 기본적으로 지원되며, YAML은 별도의 파서가 필요할 수 있다.

정리하자면, JSON은 간결성과 효율성 덕분에 대부분의 웹 애플리케이션과 API에서 기본 데이터 형식으로 사용되지만, 특정 프로젝트에서는 XML이나 YAML이 더 적합할 수도 있다.


2. JSON의 구조와 문법

2.1 JSON의 데이터 타입 (객체, 배열, 문자열 등)

JSON은 데이터를 저장하고 전달하기 위해 몇 가지 기본 데이터 타입을 지원한다. 이 데이터 타입들은 대부분의 프로그래밍 언어에서 기본적으로 제공되며, 이를 조합하여 복잡한 데이터 구조를 표현할 수 있다.

JSON의 주요 데이터 타입

  1. 객체(Object)
  • 중괄호 {}로 감싸고, 키-값 쌍의 집합으로 구성된다.
  • 키는 항상 문자열이어야 하며, 값은 문자열, 숫자, 불리언, 배열, 객체, 또는 null이 될 수 있다.
{
    "name": "Alice",
    "age": 25,
    "isStudent": false
}
  1. 배열(Array)
  • 대괄호 []로 감싸고, 쉼표로 구분된 값의 집합을 포함한다.
  • 배열의 값은 혼합된 데이터 타입을 가질 수 있다.
["apple", "banana", "cherry"]
  1. 문자열(String)
  • 큰따옴표 ""로 감싸며, 유니코드 문자를 포함할 수 있다.
  • 예: "hello", "123", "Alice"
  1. 숫자(Number)
  • 정수와 부동소수점 숫자를 모두 지원한다.
  • 예: 42, 3.14
  1. 불리언(Boolean)
  • true 또는 false 값을 가진다.
  • 예: true, false
  1. null
  • 값이 없음을 나타내는 특별한 데이터 타입이다.
  • 예: null

2.2 JSON 문법 규칙과 예제

JSON은 명확한 규칙을 따르며, 문법이 간단해 사람이 읽고 쓰기 쉽다. 다만 일부 규칙을 위반하면 JSON 자체가 유효하지 않게 되므로 주의가 필요하다.

JSON 문법 규칙

  1. 데이터는 키-값 쌍으로 구성된다
  • 키는 항상 큰따옴표 ""로 감싸야 하며, 값은 JSON 데이터 타입 중 하나를 사용한다.
"key": "value"
  1. 쉼표로 데이터 구분
  • 객체와 배열 내에서 항목은 쉼표로 구분된다.
{
    "name": "Alice",
    "age": 25
}
  1. 중괄호와 대괄호 사용
  • 중괄호 {}는 객체를, 대괄호 []는 배열을 나타낸다.
  1. 문자열은 큰따옴표로 감싼다
  • 작은따옴표는 허용되지 않는다.
"correct": "This is valid",
"incorrect": 'This is invalid'
  1. 마지막 쉼표 금지
  • 객체와 배열의 마지막 요소 뒤에 쉼표를 사용하면 안 된다.
{
    "name": "Alice",
    "age": 25
}

종합 예제

{
   "person": {
       "name": "Bob",
       "age": 30,
       "isMarried": true,
       "children": ["Anna", "Tom"],
       "address": {
           "city": "New York",
           "zipcode": "10001"
       }
   }
}

2.3 JSON의 유효성 검사 (Validation)

JSON 문서가 올바른 문법을 따르는지 확인하는 과정을 유효성 검사(Validation) 라고 한다. 이를 통해 JSON 데이터가 파싱 가능한 상태인지 확인할 수 있다.

JSON 유효성 검사 도구

  • 온라인 도구
    - https://jsonlint.com
    - JSONLint는 JSON 문서를 입력하면 구조적 오류를 검사해 준다.

  • 개발 환경에서의 검증

    • 대부분의 프로그래밍 언어는 JSON을 검증하는 라이브러리를 제공한다.
import json

json_data = '{"name": "Alice", "age": 25}'

try:
    parsed_data = json.loads(json_data)
    print("유효한 JSON입니다!")
except json.JSONDecodeError as e:
    print(f"유효하지 않은 JSON: {e}")

JSON Schema

JSON Schema는 JSON 데이터의 구조를 정의하고 유효성을 검사하는 데 사용된다. 이를 통해 데이터가 예상되는 형식과 일치하는지 확인할 수 있다. JSON Schema는 데이터를 검증할 뿐만 아니라 문서화하고, API 설계에도 유용하다.

{
   "$schema": "http://json-schema.org/draft-07/schema#",
   "type": "object",
   "properties": {
       "name": { "type": "string" },
       "age": { "type": "integer" },
       "isStudent": { "type": "boolean" }
   },
   "required": ["name", "age"]
}

3. JSON의 활용

3.1 웹 API와 JSON

JSON은 웹 API에서 데이터 교환의 표준 포맷으로 널리 사용된다. 클라이언트와 서버 간 데이터를 주고받는 데 적합하며, RESTful API나 GraphQL에서도 기본적으로 사용된다.

예를 들어, 클라이언트가 서버에 HTTP GET 요청을 보내면, 서버는 JSON 형식으로 데이터를 응답할 수 있다. 다음은 간단한 JSON 응답 예제다:

{
    "status": "success",
    "data": {
        "id": 1,
        "name": "Alice",
        "email": "alice@example.com"
    }
}

JSON의 간결한 문법은 웹 브라우저, 모바일 애플리케이션, IoT 기기 등 다양한 클라이언트가 데이터를 쉽게 파싱하고 처리할 수 있도록 돕는다.
또한, JSON은 Cross-Origin Resource Sharing(CORS) 과 호환되어, 다른 도메인 간의 데이터 교환에서도 안정적으로 작동한다.

3.2 데이터 직렬화와 역직렬화

JSON은 데이터를 직렬화(Serialization)하고 역직렬화(Deserialization)하는 데 유용하다. 직렬화는 데이터를 텍스트 형식으로 변환하여 저장하거나 전송할 수 있게 하는 과정이며, 역직렬화는 이를 다시 원래의 데이터 구조로 복원하는 과정이다.

직렬화

import json

data = {
    "name": "Bob",
    "age": 30,
    "isStudent": False
}

# 데이터를 JSON 문자열로 직렬화
json_string = json.dumps(data)
print(json_string)
{"name": "Bob", "age": 30, "isStudent": false}

역직렬화

# JSON 문자열을 파이썬 객체로 역직렬화
parsed_data = json.loads(json_string)
print(parsed_data["name"])  # 출력: Bob

JSON은 다양한 프로그래밍 언어에서 직렬화/역직렬화를 지원하여, 언어 간 데이터 교환을 간소화한다. 예를 들어, Python에서 직렬화한 JSON 데이터를 JavaScript에서 파싱하여 사용할 수 있다.

3.3 데이터베이스와 JSON (MongoDB, PostgreSQL 등)

JSON은 데이터베이스에서도 강력하게 활용된다. 특히, NoSQL 데이터베이스와 JSON을 지원하는 관계형 데이터베이스에서 중요한 역할을 한다.

MongoDB

MongoDB는 JSON 형식을 기반으로 하는 BSON(Binary JSON) 포맷을 사용하여 데이터를 저장한다. JSON-like 문서를 통해 데이터 구조를 유연하게 관리할 수 있다.

{
    "_id": 1,
    "name": "Alice",
    "age": 25,
    "hobbies": ["reading", "traveling"]
}

MongoDB에서는 JSON 문서를 기반으로 복잡한 쿼리를 작성할 수 있다. 예를 들어, 특정 조건에 맞는 데이터를 검색할 때도 JSON 형식을 사용한다:

db.users.find({ "age": { "$gt": 20 } })

PostgreSQL

PostgreSQL은 관계형 데이터베이스이지만, JSON 및 JSONB(Binary JSON)를 지원한다. JSON 데이터를 저장, 검색, 조작할 수 있는 강력한 기능을 제공한다.

  • JSON 저장
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    data JSONB
);
INSERT INTO users (data) VALUES ('{"name": "Bob", "age": 30}');
  • JSON 데이터 검색
SELECT data->>'name' AS name FROM users WHERE data->>'age' = '30';

PostgreSQL의 JSONB는 JSON 데이터를 효율적으로 인덱싱하고 검색할 수 있어, 대량의 JSON 데이터를 처리하는 애플리케이션에서 널리 사용된다.

JSON을 지원하는 데이터베이스는 데이터 모델링의 유연성을 제공하며, 전통적인 테이블 기반 데이터 저장소와 달리 반정형 데이터를 다룰 때 효과적이다.


4. JSON과 보안

4.1 JSON 데이터의 취약점 (JSON Injection 등)

JSON은 간결하고 효율적인 데이터 포맷이지만, 보안적인 취약점을 가지고 있다. 이를 악용하면 JSON 데이터를 통해 애플리케이션에 심각한 위협을 초래할 수 있다.

JSON Injection

JSON Injection은 사용자가 입력한 데이터를 신뢰 없이 처리하는 경우 발생한다. 공격자는 JSON 데이터에 악성 코드를 삽입하여 애플리케이션의 로직을 변경하거나, 민감한 데이터를 탈취할 수 있다.
예를 들어, 서버가 JSON 데이터를 받아 파싱할 때 사용자의 입력을 검증하지 않는 경우, 공격자는 다음과 같은 JSON을 삽입할 수 있다:

{
    "username": "admin",
    "password": "123456",
    "isAdmin": true
}

이로 인해 서버는 isAdmin 속성을 신뢰하게 되어, 권한을 부여하는 보안 취약점이 발생할 수 있다.

CSRF(Cross-Site Request Forgery)

JSON을 사용하는 API는 CSRF 공격에 취약할 수 있다. 사용자가 인증된 상태에서 악의적인 웹사이트가 JSON 요청을 보내도록 유도하면, 권한이 없는 데이터 조작이 발생할 수 있다.

MitM(Man-in-the-Middle) 공격

HTTPS를 사용하지 않는 경우, JSON 데이터는 네트워크 상에서 평문으로 전송되므로 중간자 공격에 의해 탈취되거나 조작될 위험이 있다.

4.2 JSON Web Token(JWT)와 인증

JWT(JSON Web Token) 는 JSON 형식을 기반으로 인증과 정보 교환을 위한 안전하고 간결한 방식이다. JWT는 사용자가 인증되었음을 증명하는 토큰으로, 클라이언트-서버 간 신뢰를 유지하는 데 사용된다.

JWT의 구조

JWT는 세 부분으로 구성되며, 각 부분은 Base64Url로 인코딩된다.

  1. Header: 토큰의 타입(JWT)과 서명 알고리즘(예: HS256)을 포함한다.
{
    "alg": "HS256",
    "typ": "JWT"
}
  1. Payload: 클레임(Claim)이라 불리는 사용자 정보와 메타데이터를 포함한다.
{
    "userId": 123,
    "role": "admin",
    "iat": 1670000000
}
  1. Signature: Header와 Payload를 조합한 후, 비밀 키를 사용하여 생성된 서명

JWT의 사용 사례

  • 인증: 사용자가 로그인하면 서버는 JWT를 발급하며, 이후 클라이언트는 이 토큰을 사용하여 인증된 요청을 보낸다.
  • 정보 교환: JWT는 서명된 데이터이므로, 데이터를 변경할 수 없음을 보장한다.

JWT의 보안 강화

  • HTTPS를 사용하여 데이터 탈취를 방지
  • 민감한 정보를 Payload에 저장하지 않기(토큰은 암호화되지 않음)
  • 짧은 만료 기간 설정과 주기적인 토큰 갱신

4.3 안전한 JSON 데이터 처리 방법

JSON 데이터를 처리할 때 보안을 강화하기 위해 다음의 방법들을 고려해야 한다.

  1. 입력 검증

사용자가 입력한 JSON 데이터를 신뢰하지 말고, 항상 유효성을 검사해야 한다. 예를 들어, 특정 키가 필수인지, 값이 예상되는 데이터 타입인지 확인해야 한다.

import jsonschema
from jsonschema import validate

schema = {
    "type": "object",
    "properties": {
        "username": {"type": "string"},
        "password": {"type": "string"}
    },
    "required": ["username", "password"]
}

data = {"username": "Alice", "password": "1234"}
validate(instance=data, schema=schema)
  1. HTTPS 사용

모든 JSON 데이터를 HTTPS로 전송하여 네트워크 상에서 가로채는 것을 방지한다.

  1. CORS 정책 설정

API가 특정 도메인에서만 접근 가능하도록 CORS(Cross-Origin Resource Sharing)를 올바르게 설정한다.

Access-Control-Allow-Origin: https://example.com
  1. JSON 데이터 크기 제한

JSON 데이터의 크기를 제한하여 대규모 요청으로 인한 DoS(Denial of Service) 공격을 방지한다.

  1. 보안 라이브러리 사용

최신 보안 패치를 적용한 JSON 파서와 라이브러리를 사용하여 알려진 취약점을 방지한다.


5. JSON의 확장과 미래

5.1 JSON Schema와 데이터 검증

JSON Schema는 JSON 데이터의 구조를 명시적으로 정의하고, 데이터를 검증하는 데 사용되는 포맷이다. 이를 통해 데이터가 예상되는 형식과 일치하는지 확인할 수 있다. JSON Schema는 API와 데이터베이스 통합에서 데이터의 일관성을 유지하고 오류를 줄이는 데 중요한 역할을 한다.

JSON Schema의 주요 구성 요소

  1. 타입 지정: 각 필드의 데이터 타입을 정의
{
    "type": "object",
    "properties": {
        "name": { "type": "string" },
        "age": { "type": "integer" },
        "email": { "type": "string" }
    },
    "required": ["name", "email"]
}
  1. 필드 제약 조건: 값의 최소/최대 길이, 범위, 형식 등을 제한
{
    "type": "string",
    "minLength": 5,
    "maxLength": 50,
    "format": "email"
}
  1. 배열의 구조 정의: 배열 요소의 타입과 최소/최대 요소 수를 정의
{
    "type": "array",
    "items": { "type": "integer" },
    "minItems": 1,
    "maxItems": 5
}

JSON Schema의 활용

  • API 데이터 검증: 클라이언트가 보낸 데이터가 서버에서 처리 가능한지 확인
  • 데이터 마이그레이션: 데이터베이스 구조 변경 시 데이터의 호환성을 검증
  • 테스팅 자동화: 예상되는 데이터 구조와 실제 데이터를 비교하여 일관성을 확인

5.2 JSON의 한계와 대체 기술 (Protobuf, Avro 등)

JSON은 간결성과 범용성으로 인해 널리 사용되지만, 특정 상황에서는 몇 가지 한계를 보인다. 이러한 한계를 극복하기 위해 ProtobufAvro 같은 대체 기술이 등장했다.

JSON의 한계

  1. 데이터 크기: JSON은 텍스트 기반 포맷이므로, 바이너리 데이터를 처리할 때 효율성이 떨어진다. JSON 문서의 크기가 커질수록 전송 및 처리 속도가 느려진다.
  2. 스키마 부족: 기본적으로 스키마를 강제하지 않기 때문에 데이터 구조가 불명확하거나 예상치 못한 오류가 발생할 수 있다.
  3. 파싱 성능: JSON의 가독성을 위해 포함된 공백과 구분자는 데이터 크기를 늘리고, 파싱 속도를 저하시킬 수 있다.

대체 기술

  1. Protobuf (Protocol Buffers)
  • Google에서 개발한 바이너리 직렬화 포맷으로, JSON보다 더 작고 빠르다.
  • 스키마를 미리 정의하며, 이를 통해 데이터 구조를 명확히 하고 유효성을 검증한다.
  • Protobuf는 대량의 데이터 전송이 필요한 시스템(API, 분산 시스템 등)에서 많이 사용
message Person {
    string name = 1;
    int32 age = 2;
    string email = 3;
}
  1. Avro
  • Apache에서 개발한 데이터 직렬화 시스템으로, 빅데이터 환경에서 효율적인 데이터 저장과 전송을 지원한다.
  • JSON과 유사하게 데이터를 직렬화하지만, 바이너리 포맷으로 변환하여 크기를 줄이고 처리 속도를 높인다.
  • Avro는 Hadoop 기반의 데이터 처리와 같은 대규모 데이터 분석 시스템에서 주로 사용

JSON vs Protobuf vs Avro 비교

특성JSONProtobufAvro
형식텍스트 기반바이너리바이너리
스키마선택적필수필수
크기상대적으로 큼작음작음
속도느림빠름빠름
주요 사용 사례웹 API, 설정 파일분산 시스템, 메시징빅데이터 처리

JSON은 간단한 데이터 교환에 여전히 적합하지만, Protobuf와 Avro는 고성능과 데이터 구조의 명확성을 요구하는 환경에서 점점 더 많이 사용되고 있다고 한다.


6. 마무리

프로젝트를 하나 수행할 때마다 주 언어 다음으로 많이 보는 게 json 형식인 것 같다... 이번 프로젝트에서도 물론 마찬가지였고, 크롤링한 데이터를 처리하는 과정을 수행중인 입장에서 특히 얻어가는 게 많았던 것 같다.

그리고... 가능하다면 다음에 규모가 좀 있는 프로젝트를 하나 마련해서 protobuf를 사용해보는 것도 좋은 공부가 될 것 같다.

profile
안드로이드는 리눅스의 꿈을 꾸는가

0개의 댓글