메모리 안전성 문제 정의하기 · Alex Gaynor

ko생성일: 2025. 9. 13.갱신일: 2025. 9. 13.

메모리 안전하지 않은 프로그래밍 언어의 정의와 범위를 명확히 하고, 어떤 종류의 소프트웨어와 보안 문제를 대상으로 하는지, 언어 차원에서 무엇을 해결하고 무엇은 해결하지 못하는지 정밀하게 규정한다.

월, 2023년 10월 2일

메모리 안전하지 않은 프로그래밍 언어가 초래하는 만연한 보안 문제를 해결하기 위해, 나는 메모리 안전하지 않은 프로그래밍 언어에서 벗어나야 한다는 입장의 강력한 옹호자다. 방금 문장에는 정의할 가치가 있는 여러 용어와, 보다 상세히 설명할 만한 여러 별표가 들어 있다. 이 글의 목적은 이 논의에 더 높은 정밀도를 부여하는 것이다.

메모리 안전하지 않은 언어란?

기본적으로 코드가 메모리 관련 취약점(해제 후 사용, 버퍼 오버/언더플로, 초기화되지 않은 메모리 사용, 타입 혼동)과 정의되지 않은 동작을 유발할 수 있도록 허용하며, 그 결과 이 언어로 작성된 코드가 보안 문제의 발생률이 증가하는 프로그래밍 언어를 말한다. 이 정의의 각 요소는 중요하다.

우리가 관심을 두는 것은 이러한 특성이 기본값인 언어다. Java의 sun.misc.Unsafe, Rust의 unsafe, Python의 ctypes처럼 선택적으로 비안전을 도입하는 수단만 제공하는 것은 이 정의에 부합하지 않는다.

취약점 발생률이 경험적으로 증가한다는 점은 필요한 조건이다. 어떤 언어들은 기술적으로 앞의 두 기준을 충족하지만, 실제로 취약점이 발생할 가능성이 충분히 미미하여 문제적 빈도로 나타나지 않는 경우가 있다. Go는 그 중요한 예시다.

우리가 어떤 소프트웨어를 염두에 두는가?

우리는 주로, 메모리 할당과 레이아웃에 대한 제어를 제공하고 가비지 컬렉터가 없는 언어를 사용할 필요가 있을 정도의 성능 요구 사항을 가진 시스템 소프트웨어를 염두에 두고 있다. 가비지 컬렉션이 있는 언어를 사용할 수 있다면, 메모리 안전한 프로그래밍 언어의 설계 공간은 매우 넓다.

우리는 신뢰할 수 없는 데이터나 작업을 처리하는 위협 모델을 가진 소프트웨어에 관심이 있다. 예를 들면 네트워크 클라이언트와 서버, 미디어 파서, 커널, 샌드박스 감독(슈퍼바이저) 프로세스 등이다.

우리는 주로 더 큰 코드베이스에 관심을 둔다. 경험적으로, 메모리 안전하지 않은 프로그래밍 언어를 위험 완화 전략(예: 퍼징, 정적 분석, 레드팀 훈련)으로 관리하는 접근은 코드베이스와 엔지니어링 팀의 규모가 커질수록 한계에 부딪히는 경향이 있다.

우리는 공격 표면이 전혀 없는 소프트웨어에는 관심이 없다. 예를 들어 모든 매개변수와 데이터가 신뢰되는 물리 시뮬레이션이 그러하다. 설령 그런 소프트웨어에 취약점이 가득하더라도, 공격 표면이 없다면 공격자가 이를 악용할 메커니즘이 없다. 다만 소프트웨어가 한 용도에서 다른 용도로 전환되는 일이 드물지 않다는 점(예: 연구용 프로토타입이 제품으로 발전)도 인정해야 한다. 이 시점에서는 이러한 보안 문제가 관련성을 띠게 된다.

마지막으로, 우리가 관심을 두는 대상은 일반 목적 소프트웨어이지, 자동차, 항공, 무기 제어처럼 더 제약되고 규제된 환경을 위해 설계·구현된 소프트웨어가 아니다. 그러한 환경의 소프트웨어는 특수한 툴체인 집합을 사용하므로, 설령 명목상 메모리 안전하지 않은 언어로 작성되었다 하더라도 그 코드는 그 언어로 일반적으로 작성되는 코드와는 전혀 닮지 않았다. 반대로, 이러한 안전한 툴체인의 존재가 해당 프로그래밍 언어를 안전하게 만들지도 않는다. 이들 툴체인은 소프트웨어 엔지니어에게 과중한 부담을 주기 때문에, 이러한 특수 도메인 밖에서는 사용되지 않기 때문이다.

우리가 다루는 문제는 무엇인가?

우리가 다루고자 하는 것은 프로그래밍 언어가 유발하는 취약점과 정의되지 않은 동작의 집합이다. 주목해야 할 점은, 이것이 모든 소프트웨어 보안 이슈의 전체 집합은 아니라는 것이다. 논리적 취약점은 언어 수준에서 해결되지 않는다. 일부는 안전한 언어가 더 표현력이 높아 논리적 취약점의 비율을 낮춘다고 주장하지만, 이 주장에는 아직 경험적 근거가 없다.

언어가 유발하는 메모리 안전성 취약점과 증상이 비슷한 중요한 부류의 논리적 취약점으로, 공격자가 JIT 컴파일러가 잘못된(그리고 악용 가능한) 코드를 방출하도록 유도하는 취약점(예: 브라우저 맥락)이 있다. 이러한 취약점은 JIT 컴파일러를 메모리 안전한 언어로 구현한다고 해서 해결되지 않는다. 물론 생성된 코드가 아니라 컴파일러 자체 내부에서의 메모리 손상 문제는 안전한 언어의 사용으로 해결할 수 있다.