Lobsters

Git 3.0's upcoming SHA-256 default will be a costly mistake

Git 3.0의 SHA-256 기본값은 값비싼 실수가 될 수 있습니다

Scott Chacon은 Git 3.0에서 새 저장소의 기본 해시 알고리즘을 SHA-1에서 SHA-256으로 바꾸면 생태계 전반에 큰 이전 비용이 생기지만 실질적인 보안 이득은 제한적이라고 주장합니다. 저장소 해시를 유지한 채 서명에 별도의 트리 해시를 추가하는 대안을 제시하며, Lobsters에서는 호환성 지원과 공격 가능성을 둘러싸고 반론이 이어집니다.

에디터 노트

저자가 GitHub 공동 창업자라는 점이 가장 재밌습니다. Lobsters의 @hailey가 그 점을 찔렀습니다. 신뢰는 해시가 아니라 배포 경로에 있다는 주장인데, GitHub는 fork 네트워크 전체에서 객체를 공유합니다. 인증을 뚫지 않아도 fork에 조작 객체를 push하면 원본에서 보입니다. 탄탄한 대목은 충돌 공격과 제2원상 공격의 구분입니다. 현실적인 공격은 공격자가 원본부터 준비해야 하는 충돌 공격뿐인데, 그럴 거면 유지보수를 매수하는 게 수십억 배 쉽다는 겁니다. 다만 @pyfisch의 정정도 있습니다. SHA-256 저장소도 SHA-1 원격과 push·pull이 됩니다. 번역 테이블이 있으면 형식이 달라도 오갑니다. 파멸론은 과장된 셈입니다.

AI 요약

GitButler 공동 창업자 Scott Chacon은 Git 3.0에서 새 저장소의 기본 해시 알고리즘을 SHA-1에서 SHA-256으로 바꾸려는 계획이 막대한 이전 비용을 낳는다고 주장합니다. SHA-1에서 충돌 공격이 가능하다는 사실은 맞지만, 저자는 이를 실제 공급망 공격에 쓰기는 어렵다고 봅니다. 공격자가 신뢰를 얻은 뒤 악성 콘텐츠로 바꿔치기하는 충돌 공격은 원본 콘텐츠를 미리 준비해야 합니다. 이미 존재하는 파일을 악성 파일로 바꾸는 제2 원상 공격(second-preimage attack)은 훨씬 어렵다고 설명합니다.

저자가 제기하는 보안 쟁점

저자는 Git에서 해시가 콘텐츠를 식별하고 변경 여부를 검증하지만, 저장소를 신뢰하는 근거는 해시 자체보다 어디서 코드를 가져오는지에 있다고 주장합니다. GitHub나 패키지 저장소의 계정·관리자 권한을 노리는 공격이 해시 충돌을 만드는 공격보다 현실적이라는 설명입니다. 따라서 대다수 프로젝트는 저장소 출처와 서명 검증을 신뢰하며, SHA-1 충돌 공격을 막기 위한 전면 전환의 실익이 작다고 봅니다.

SHA-256 전환에 따른 비용

새 Git 저장소가 SHA-256을 기본으로 쓰면 원격 호스트도 저장소 형식을 맞춰야 합니다. 형식이 다른 로컬 저장소와 원격 저장소 사이에서 push가 거부될 수 있고, Git submodule은 서로 다른 형식의 저장소를 함께 쓰지 못한다고 저자는 지적합니다. 기존 저장소를 SHA-256으로 바꾸면 객체를 다시 만들며 기존 서명이 깨지고, 참여자와 도구가 동시에 전환해야 합니다. 커밋 해시를 식별자로 쓰는 링크와 내부 도구도 영향을 받습니다. Git 코어 외부에서 Git을 구현한 라이브러리 가운데 새 형식을 지원하지 않거나 일부만 지원하는 경우도 많다고 설명합니다.

대안으로 제시한 별도 트리 해시

저자는 SHA-1을 콘텐츠 주소 지정용 키로 유지하면서, 서명할 때 트리 전체를 SHA-256이나 BLAKE3로 다시 해시해 별도 헤더에 넣는 방식을 제안합니다. 서명 검증 때 두 해시를 각각 확인하면 저장소의 객체 형식을 바꾸지 않고도 콘텐츠 무결성을 검증할 수 있다는 주장입니다. Colin Walters의 git-evtag은 2015년부터 커밋, 트리, 블롭과 하위 모듈을 재귀적으로 검사한 SHA-512 체크섬을 태그에 추가하는 유사한 방식을 제공한다고 소개합니다.

저자가 만든 개념 증명 도구는 하위 모듈까지 포함해 35GB, 210만 파일인 Chromium 작업 트리의 체크섬을 M5 Mac에서 5초 만에 계산했습니다. Linux 트리는 1.5GB 기준 257밀리초, Git 저장소는 17밀리초가 걸렸다고 합니다. 저자는 서명할 때만 추가 비용이 들고 기존 커밋에도 나중에 서명과 체크섬을 붙일 수 있다고 주장합니다. NIST의 2030년 SHA-1 사용 제한도 SHA-1을 보안 보호 수단으로 쓰지 않고 별도 해시가 서명에 포함된다면 피할 수 있다고 덧붙입니다.

Lobsters 반응

  • @pyfisch — 제가 틀렸거나 Git 문서가 오래되지 않았다면, 글의 설명은 틀렸습니다. SHA-256 해시를 쓰는 로컬 저장소도 SHA-1을 쓰는 원격 저장소와 push·pull할 수 있고, 그 반대도 가능합니다. 각 객체의 해시 두 개를 디스크에 저장하고 필요한 때 변환합니다. 이 방식이 서로 호환되지 않는 문제를 대부분 피합니다. https://git-scm.com/docs/hash-function-transition
    • @kel — Git 3.0까지 구현이 다듬어져 필요할 때 변환 테이블을 자동 생성한다면, 글에서 언급한 문제 대부분이 해결됩니다. 이렇게 길고 숨 가쁜 글에서 놓치기엔 꽤 아쉬운 부분입니다.
    • @mort — SHA-1 이름과 SHA-256 이름을 양방향으로 연결하는 인덱스 지원이 있는 것으로 보입니다. 다만 실제로 모두가 이 방식을 쓰게 될지는 궁금합니다. SHA-1 저장소를 SHA-256으로 옮기는 방법에 관한 안내는 많지 않습니다. 흔히 권하는 fast-export와 fast-import 방식으로 저장소를 만들면 변환 테이블이 생기지 않습니다. 테이블을 만들려면 fast-import 전에 extensions.compatObjectFormat을 설정해야 하는 것으로 보이지만, 제 환경에서는 Rust가 필요하다는 오류가 나서 확인하지 못했습니다. 마이그레이션 때마다 변환 테이블이 생기지 않는다면, 실수로 테이블 없이 저장소를 만드는 사람이 충분히 많아져 빌드가 깨질 수 있습니다.
    • @orib — 제가 나눈 대화로는 이 기능이 실제로 구현된 상태가 아닙니다. 너무 복잡하니 구현하지 않는 편이 낫다고 생각합니다. 전환하려면 저장소를 다시 clone하면 됩니다. Plan 9용 Git에 구현하는 것도 어렵지는 않으니, 시작해야겠습니다.
  • @mort — 저자의 주장에 동의하는지는 모르겠지만 흥미로운 주제입니다. Yocto 레시피, Nix, Git submodule, repo, gclient처럼 SHA-1을 영구적인 커밋 식별자로 가정하는 소프트웨어를 많이 씁니다. 저장소가 SHA-256으로 옮기면서 기록을 다시 쓰고 기존 커밋을 정리하면 여러 도구가 깨지고, 그 문제를 해결하는 일이 제 몫이 될 수 있습니다. Merkle tree 태그를 쓸 기회가 생겼네요. 제가 아는 한 Merkle tree가 흥미롭게 쓰이는 곳은 Git 같은 DVCS뿐입니다.
    • @fanf — Certificate Transparency도 꽤 괜찮은 활용 사례입니다.
    • @janus — BitTorrent에서도 씁니다. DVCS는 아닙니다.
    • @mort — 알려줘서 고맙습니다. 그런데 이 글이 Merkle tree에 관한 내용인데도 태그가 삭제됐네요.
    • @janus — 그 태그가 예전에 ‘blockchain’이라고 불렸고, 운영진에게도 여전히 그렇게 보이는지도 모르겠습니다. 적절한 이름으로 부르지 않는 건 어리석다고 봅니다.
    • @mort — 아쉽습니다. Merkle tree에 관해 쓸 흥미로운 주제가 많습니다. 이 태그를 암호화폐 태그처럼 쓰면 주제의 범위가 왜곡됩니다. 암호화폐 글을 모두 삭제하는 규칙을 만들거나, Merkle tree 수학과 무관한 암호화폐 전용 태그를 만들었어야 합니다.
  • @hailey — GitHub와 관련한 저자의 ‘배포 경로가 신뢰의 근거’라는 주장에는 큰 구멍이 있습니다. GitHub는 fork 네트워크 전체에서 객체를 공유하고 refs만 분리합니다. GitHub 인증을 뚫지 않아도 저장소를 fork한 뒤 조작한 객체를 push하면 원본 저장소에서도 그 객체를 볼 수 있습니다. GitHub 공동 창업자인 저자가 이 가능성을 놓친 점이 놀랍습니다.
    • @mort — 미러도 문제입니다. Git의 장점은 어느 미러에서든 저장소를 내려받은 뒤 해시를 다시 계산해 예상한 커밋 해시와 맞는지 확인할 수 있다는 점입니다. Yocto처럼 온갖 호스트에서 수백 개 프로젝트를 받는 환경에서는 저장소 호스트 하나가 침해돼도 체크섬으로 탐지할 수 있습니다.
    • @op — 이 취약점이 지금도 악용 가능하다면, 왜 이미 이 방식으로 활발히 공격하지 않나요?
    • @mort — SHA-1은 충돌이 발견됐고, 비트 수가 시사하는 것보다 훨씬 약하게 만드는 암호학적 약점도 발견됐습니다. 하지만 원하는 악성 페이로드를 넣으면서 관련 커밋과 충돌하는 객체를 만드는 일은 여전히 쉽지 않습니다. 지금까지의 충돌은 개념 증명에 가깝습니다. 그래도 실제 악용이 문제로 커지기 전에 전환하는 편이 낫습니다. Git과 호스트는 충돌 탐지 기능을 갖춘 sha1dc를 사용해 지금까지 충돌을 만드는 데 쓰인 방식에 대응합니다. 충돌하는 PDF 두 개를 GitHub에 push하는 일도 막힙니다.
    • @fanf — 어떤 취약점을 뜻하는지는 분명하지 않지만, fork 사이 객체 참조 공격으로 저장소에서 ‘삭제된’ 브랜치를 복구하거나 악성 코드를 주입해 신뢰하는 상위 저장소 URL에서 보이게 하는 일은 종종 있습니다.
  • @df — 2016년쯤 해시를 많이 쓰는 독점 백업 시스템을 만들 때도 비슷한 경험을 했습니다. “FIPS 규정상 SHA-256만 써야 합니다.” “해시는 보안이 아니라 중복 제거에 씁니다.” “상관없습니다. FIPS 규정입니다.” “사용자가 수천 명이고 오래된 CPU에서는 해시가 느립니다.” “상관없습니다.” 결국 모든 사용자를 SHA-256으로 업그레이드했습니다.
    • @elobdog — 그 싸움은 이미 졌습니다. 해시를 서명처럼 보안에 중요한 용도로 쓰지 않더라도, ‘컴플라이언스’ 업계는 SHA-1을 보면 크게 반응합니다.
    • @quasi_qua_quasi — 최근에는 회사 보안 교육에서 파일의 진위를 확인하라며 MD5를 권하는 정반대 상황을 겪었습니다. 정말 웃겼습니다.
    • @ceph — 하지만 Git은 커밋 서명 기능이 있으니 객체와 커밋 해시의 보안 속성도 필요합니다.
    • @mort — SHA-1을 보안과 무관한 중복 제거에 어떻게 쓸 수 있나요? 파일 A를 백업한 뒤 A와 충돌하는 파일 B를 내려받고, 나중에 B가 있던 시점으로 복원하면 백업 시스템이 B를 A로 바꾸지 않나요? 반대로 B를 받게 만들면 복원 때 A가 B로 바뀌도록 백업을 오염시킬 수도 있습니다. 파일을 내려받는 것만으로 백업이 영구적으로 오염될 줄은 예상하지 못할 겁니다.
    • @fanf — 그 논리 때문에 SHAttered 충돌로 SVN 저장소가 심각하게 손상됐다고 생각합니다. 충돌에 대비한 별도 처리가 없다면, 해시 함수의 보안성이 깨졌을 때 데이터 무결성과 가용성이 무너질 수 있습니다.
  • @SamRW — 이 변경이 고통스러울 수 있다는 점은 이해하지만, 충돌의 영향을 축소해서 말하는 데는 신중해야 합니다. SHA-1의 여러 약점을 오랫동안 지적해 온 암호학자들의 견해를 더 중요하게 봐야 합니다.
  • @grahamc — 제가 지나치게 낙관적인 걸 수도 있지만, 전환이 시작되면 사용자와 자원봉사자, 고객이 통합과 이전을 쉽게 하라는 압력을 강하게 넣을 것이라고 봅니다. 초반에는 울퉁불퉁하겠지만 글에서 예상하는 것보다 빨리 자리 잡을 것 같습니다.
  • @soulcutter — Git submodule은 없애야 합니다. 쓰는 분들께는 미안하지만, 실제로 잘 작동하지 않은 시도였습니다.
  • @interlandi — 암호학자도 소프트웨어 생태계의 ‘공중 보건’ 전문가도 아니지만, 이번 결정은 당장 존재하지 않는 문제를 막으려는 게 아니라 미래를 대비하려는 것이라고 봅니다. 15년 뒤에도 SHA-1 저장소가 얼마나 남을지 아무도 확신할 수 없습니다. 지금 전환을 시작하면 기다리는 경우보다 그 수가 줄어들 겁니다. 기존 해시에 다른 해시를 덧붙이는 대안도 적절하지 않을 수 있습니다. 직관적으로 보면 암호학적 무결성을 높이는 동시에 취약한 공격 표면도 넓힐 수 있습니다.

원문: GitButler Blog / 번역·요약: Trawling