CodeGym /행동 /C# SELF /BinaryFormatter 논의하기

BinaryFormatter 논의하기

C# SELF
레벨 44, 레슨 1
사용 가능

1. 서론

많은 오래된 C# 교재와 예제에서 BinaryFormatter를 이용한 직렬화 방법을 볼 수 있어요. 예전에는 표준이었죠: 간편하고 빠르며, 걱정이 적었어요. 오래된 시절의 예제는 대략 이렇게 생겼어요:

// 위험한 오래된 코드! 새 프로젝트에서는 절대 이렇게 하지 마세요!
var bf = new BinaryFormatter();
using (var stream = File.Open("player.dat", FileMode.Create))
{
    bf.Serialize(stream, playerObject);
}

하지만 최신 .NET 9에서는 이 코드를 컴파일조차 할 수 없어요: BinaryFormatter는 플랫폼에서 제거되었고, 가장 위험한 직렬화 도구로 남아있죠.

영웅에서 배신자로

BinaryFormatter는 원래 범용 도구였어요: .NET 객체를 프로그램 간에 직렬화/역직렬화하거나, 객체 상태를 저장하고 복원하는 용도로 만들어졌죠. 복잡한 객체 그래프(예를 들어, 여러 클래스의 컬렉션 전체)를 빠르게 저장하는 데 딱이었어요. 그런데 시간이 지나면서 이 방식의 위험성이 드러났고, 지금은 마치 카세트 테이프처럼 향수만 남았고, 모두 클라우드 스트리밍을 원하게 되었어요.

2. BinaryFormatter 사용 중단의 주요 이유

엄청난 보안 구멍

BinaryFormatter는 데이터 직렬화뿐만 아니라, 데이터에서 타입을 "읽어내고" 객체를 복원하는 기능도 있어요. 즉, 만약 인터넷에서 받은 데이터를 무차별 역직렬화한다면, 공격자가 악의적인 "트로이 목마"를 삽입할 수 있죠. 이 데이터를 역직렬화하는 순간, 예상치 못한 코드가 실행될 수 있는데, 이는 .NET 세계에서는 Remote Code Execution (RCE)라고 불리며, 개발자와 시스템 관리자에게는 악몽이에요.

많은 기업용 앱의 취약점이 바로 BinaryFormatter 사용과 관련이 있었어요. Microsoft는 공개적으로 권고하길: "다른 선택권이 있다면 BinaryFormatter는 절대 사용하지 마세요". .NET 5부터는 이 클래스가 위험하고 구식(Obsolete)으로 표시됐고, .NET 9에서는 완전히 삭제됐어요.

내부 구조에 의존하는 문제

BinaryFormatter는 타입, 필드, 데이터 포장 등 전체 정보를 저장했어요. 만약 클래스 구조를 바꾸면(필드 추가, 삭제 등), 이전에 직렬화된 데이터는 새 클래스와 호환되지 않아 역직렬화가 불가능하거나 오류가 발생하죠.

즉, 보안 문제보다도, 이진 포맷은 장기 저장이나 버전 간 데이터 교환에 적합하지 않다는 의미입니다.

크로스 플랫폼 문제

BinaryFormatter는 .NET 내부 표현에 의존하기 때문에, 다른 플랫폼이나 언어, 또는 다른 .NET 버전에서 읽으려면 오류가 발생하거나 제대로 작동하지 않을 가능성이 높아요.

3. "구형 코드" 찾기와 대처법

대형 프로젝트(특히 2020년 이전에 작성된 레거시 코드)에서는 BinaryFormatter 사용 흔적을 쉽게 찾을 수 있어요. 다음과 같은 문자열이 있으면 의심하세요:

using System.Runtime.Serialization.Formatters.Binary; // <-- 의심!
BinaryFormatter bf = new BinaryFormatter();           // <-- 위험!
bf.Serialize(...);
bf.Deserialize(...);

최신 .NET에서는 이 코드를 컴파일하면 "타입 또는 이름을 찾을 수 없다"는 오류가 뜨고, 구버전에서는 경고 메시지가 나타납니다.

만약 .NET 4.8 이상 또는 유사한 환경이라면, BinaryFormatter 대신 안전한 현대적 방법으로 교체하는 게 필요해요(이하 계속).

오늘날 추천하는 포맷과 클래스

다행히도, .NET에서는 이미 여러 안전한 직렬화 수단이 활발히 개발되고 있어요:

  • JSON용:
    • System.Text.Json — 최신, 내장, 빠르고 안전하며 유연한 직렬화 라이브러리.
      Microsoft 공식 문서: System.Text.Json
    • Newtonsoft.Json (Json.NET) — 인기 많은 서드파티 라이브러리, 복잡한 경우에 유용하지만, System.Text.Json 등장 이후 사용 빈도는 줄었어요.
  • XML용:
  • 바이너리 포맷(필요할 때만):
    • System.Formats.Cbor — CBOR 포맷을 위한 새 라이브러리
    • Protocol Buffers (Protobuf.Net) 또는 MessagePack C# — 크로스 플랫폼 지원 프로토콜
  • 기타 특수 포맷: 각 포맷에 맞는 별도 라이브러리를 사용하는 게 좋아요. 표준 "범용" 포맷은 이제 거의 없어요(그리고 그게 더 좋아요!).

4. BinaryFormatter 대신하는 코드 작성법

왜 BinaryFormatter를 쓰면 안 될까?

절대 금지:

  • 사용자 설정이나 중요한 데이터를 BinaryFormatter로 저장하는 것
  • 네트워크를 통한 데이터 전송, 특히 서버와 클라이언트 간에 BinaryFormatter 사용
  • 알 수 없는 출처의 데이터를 무차별 역직렬화하는 것

대신 사용할 것:

  • System.Text.Json — 거의 모든 경우에 충분히 안전하고 빠름
  • 설정 데이터는 JSON, XML, 또는 간단한 INI 파일(라이브러리 활용)
  • 다른 프로그램이나 언어 간 데이터 교환은 크로스 플랫폼 지원 포맷(예: JSON, XML, Protobuf, MessagePack)만 사용

이제 어떤 코드로 직렬화할까?

아래는 현대적 직렬화 예제입니다(처음 위험한 예제와 비교하세요):

JSON 직렬화 (추천 방법):

using System.Text.Json;
// 클래스 정의:
public class Player
{
    public string Name { get; set; } = "";
    public int Health { get; set; }
    public bool IsAlive { get; set; }
}

// 직렬화 대상 객체
var player = new Player { Name = "Aragorn", Health = 100, IsAlive = true };

// 객체를 JSON 문자열로 변환
string json = JsonSerializer.Serialize(player);

// 안전하게 파일에 저장!
File.WriteAllText("player.json", json);

// 파일에서 객체 복원:
string loadedJson = File.ReadAllText("player.json");
Player loadedPlayer = JsonSerializer.Deserialize<Player>(loadedJson)!;

XML 직렬화 (엄격한 포맷 필요 시):

using System.Xml.Serialization;
// 클래스는 파라미터 없는 퍼블릭 생성자 필요

var player = new Player { Name = "Aragorn", Health = 100, IsAlive = true };
var serializer = new XmlSerializer(typeof(Player));
using (var fs = File.Create("player.xml"))
{
    serializer.Serialize(fs, player);
}

구형과 신형 직렬화 방식 비교 표

작업 구형 (BinaryFormatter) 현대적 방법
파일에 저장 bf.Serialize(stream, obj) JsonSerializer.Serialize
XmlSerializer.Serialize
파일에서 읽기 bf.Deserialize(stream) JsonSerializer.Deserialize
XmlSerializer.Deserialize
보안 취약함 안전함
크로스 플랫폼 아니요 네 (JSON/XML/Protobuf)
속도 빠름(위험함) 빠르고 안전함

초보자가 자주 하는 실수

가끔 오래된 영상이나 책의 습관대로 System.Runtime.Serialization.Formatters.Binary를 연결하려 하고, Visual Studio가 "타입 또는 이름을 찾을 수 없다"고 경고하는 경우가 있어요. 또는 오래된 버전의 .NET에서만 작동하는 라이브러리도 있죠. .NET 9에서는 이 모든 게 작동하지 않기 때문에, 지금이 바로 현대적 도구로 전환할 절호의 기회입니다.

2
과제
C# SELF, 레벨 44, 레슨 1
잠금
간단한 객체에 대한 JSON과 XML 직렬화 비교
간단한 객체에 대한 JSON과 XML 직렬화 비교
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION