Git은 BLOB에서의 SHA-1 충돌에 어떻게 대처합니까?
이것은 아마 아직 현실에서 일어난 적이 없을지도 모릅니다만, 이것을 생각해 봅시다.예를 들어 git 저장소가 있고, 커밋을 하고, 매우 운이 나쁘다고 합시다.그 중 하나의 블록은 이미 저장소에 있는 것과 같은 SHA-1을 갖게 됩니다.문제는 Git이 이 일을 어떻게 처리할 것인가 하는 것이다.단순히 실패?두 블럽을 연결하는 방법을 찾고 컨텍스트에 따라 어떤 블럽이 필요한지 확인하십시오.
실제 문제라기보다는 두뇌를 움직이는 문제지만, 나는 그 문제가 흥미롭다는 것을 알았다.
이 경우 Git이 정확히 어떻게 동작하는지 알아보기 위해 실험을 했습니다.이것은 버전 2.7.9~rc0+ 다음 버전입니다.20151210(데비안 버전).기본적으로 다음과 같은 diff를 적용하여 git을 재구축함으로써 해시 크기를 160비트에서 4비트로 줄였습니다.
--- git-2.7.0~rc0+next.20151210.orig/block-sha1/sha1.c
+++ git-2.7.0~rc0+next.20151210/block-sha1/sha1.c
@@ -246,6 +246,8 @@ void blk_SHA1_Final(unsigned char hashou
blk_SHA1_Update(ctx, padlen, 8);
/* Output hash */
- for (i = 0; i < 5; i++)
- put_be32(hashout + i * 4, ctx->H[i]);
+ for (i = 0; i < 1; i++)
+ put_be32(hashout + i * 4, (ctx->H[i] & 0xf000000));
+ for (i = 1; i < 5; i++)
+ put_be32(hashout + i * 4, 0);
}
그리고 나서 몇 가지 커밋을 하고 나서, 다음과 같은 점에 주목했습니다.
- 동일한 해시를 가진 BLOB가 이미 존재하는 경우 경고 메시지가 전혀 표시되지 않습니다.모든 것이 정상인 것 같습니다만, 누르는 사람, 클론, 또는 되돌리는 경우(위의 설명에 따라) 최신 버전이 손실됩니다.
- 트리 개체가 이미 존재하고 동일한 해시를 사용하여 BLOB를 만드는 경우: 저장소의 푸시를 시도하거나 다른 사용자가 복제하기 전까지는 모든 것이 정상입니다.그러면 보고서가 부패했다는 것을 알 수 있을 것이다.
- 커밋 개체가 이미 존재하고 #2와 같은 해시를 가진 BLOB를 만드는 경우: crupted
- BLOB가 이미 존재하고 동일한 해시를 가진 커밋 개체를 만들면 "ref" 업데이트 시 실패합니다.
- BLOB가 이미 존재하고 동일한 해시를 사용하여 트리 개체를 만드는 경우.커밋 작성 시 실패합니다.
- 트리 개체가 이미 존재하고 동일한 해시를 가진 커밋 개체를 만들면 "ref" 업데이트 시 실패합니다.
- 트리 개체가 이미 존재하고 동일한 해시를 사용하여 트리 개체를 만들면 모든 것이 정상으로 표시됩니다.그러나 커밋하면 모든 저장소가 잘못된 트리를 참조합니다.
- commit 객체가 이미 존재하고 동일한 해시를 가진 commit 객체를 만들면 모든 것이 정상으로 보입니다.그러나 커밋할 때 커밋은 생성되지 않고 HEAD 포인터는 이전 커밋으로 이동합니다.
- 커밋 개체가 이미 존재하고 동일한 해시를 가진 트리 개체를 만들면 커밋 작성 시 실패합니다.
#2의 경우 일반적으로 "git push"를 실행하면 다음과 같은 오류가 발생합니다.
error: object 0400000000000000000000000000000000000000 is a tree, not a blob
fatal: bad blob object
error: failed to push some refs to origin
또는 다음과 같이 입력합니다.
error: unable to read sha1 file of file.txt (0400000000000000000000000000000000000000)
파일을 삭제하고 "filename checkout file.txt"를 실행하면 됩니다.
#4 및 #6의 경우 일반적으로 다음과 같은 오류가 발생합니다.
error: Trying to write non-commit object
f000000000000000000000000000000000000000 to branch refs/heads/master
fatal: cannot update HEAD ref
"commitledge commit 。이 경우 일반적으로 "git commit"를 다시 입력하면 새로운 해시가 생성됩니다(타임스탬프가 변경되었기 때문에).
#5 및 #9의 경우 일반적으로 다음과 같은 오류가 발생합니다.
fatal: 1000000000000000000000000000000000000000 is not a valid 'tree' object
"commit" 실행 시
손상된 리포지토리를 복제하려고 하면 일반적으로 다음과 같은 메시지가 표시됩니다.
git clone (one repo with collided blob,
d000000000000000000000000000000000000000 is commit,
f000000000000000000000000000000000000000 is tree)
Cloning into 'clonedversion'...
done.
error: unable to read sha1 file of s (d000000000000000000000000000000000000000)
error: unable to read sha1 file of tullebukk
(f000000000000000000000000000000000000000)
fatal: unable to checkout working tree
warning: Clone succeeded, but checkout failed.
You can inspect what was checked out with 'git status'
and retry the checkout with 'git checkout -f HEAD'
걱정되는 점은 두 가지 경우(2,3) 아무런 경고 없이 저장소가 손상되고 세 가지 경우(1,7,8) 모든 것이 정상으로 보이지만 저장소의 내용이 예상과 다르다는 것입니다.복제 또는 풀링하는 사람의 콘텐츠는 사용자의 콘텐츠와 다릅니다.케이스 4, 5, 6, 9는 에러로 정지하기 때문에 괜찮습니다.적어도 모든 경우에서 에러와 함께 실패하는 것이 좋다고 생각합니다.
2012)(「」를 참조)shattered.io
2017 SHA1 충돌)
Linus의 오래된 답변(2006)은 여전히 관련이 있을 수 있습니다.
아니요. SHA1이 같은 경우 상대편에서 개체를 수신할 때 이미 있는 개체를 덮어쓰지 않습니다.
따라서 충돌이 발생하면 특정 저장소의 "이전" 개체가 항상 덮어쓰게 됩니다.단, git 오브젝트네트워크가 완전한 순서가 아닌 DAG를 생성한다는 점에서 "이전"은 분명히 저장소 단위라는 점에 유의하십시오.따라서 다른 저장소는 오브젝트가 직접 관련이 없는 별도의 분기를 통해 온 경우, 직계 조상의 경우 "이전"에 대해 합의합니다.두 개의 서로 다른 저장소가 두 개체를 서로 다른 순서로 가져올 수 있습니다.
단, 보안 관점에서 "이전 단계에서 덮어쓸 것"은 사용자가 원하는 것입니다. git 모델은 주로 자신의 저장소만 신뢰해야 한다는 것을 기억하십시오.
에 '어울리다를git pull
「새로운 착신 오브젝트는, 이미 가지고 있는 오브젝트보다 신뢰성이 낮기 때문에, 새로운 오브젝트가 낡은 오브젝트를 대체하도록 하는 것은 잘못입니다.두 가지 충돌 사례가 있습니다.
어떤 이유에서인지 매우 운이 나쁘고, 2개의 파일이 같은 SHA1을 갖게 되는 경우입니다.
그 「이러다를 실행), 그 파일이 커밋 됩니다.git-update-index
인덱스로 이동하지만 아직 커밋되지 않은 경우) 새 콘텐츠의 SHA1이 계산되지만 오래된 오브젝트와 일치하기 때문에 새로운 오브젝트는 생성되지 않고 commit-or-index는 오래된 오브젝트를 가리키게 됩니다.
SHA1과에) 알 수 는 (가 SHA1과 일치한다는 것을 합니다) SHA1과 같은입니다.것음git diff
체크 아웃 된 카피는 사용되지만, 트리 레벨의 diff(또는 클론, 풀, 또는 체크 아웃을 실행)를 실시했을 경우는, 그 파일이 예상과는 전혀 다른 것으로 변경되고 있는 것을 갑자기 알아차릴 수 있습니다.
이런 종류의 충돌은 일반적으로 금방 알아차릴 수 있습니다.
관련 뉴스에서 문제는 우발적인 충돌에 대해 어떻게 대처하느냐입니다.
우선, 사람들에게 의도하지 않은 충돌은 정말로 일어날 가능성이 매우 낮다는 것을 상기시켜줍니다. 그래서 우리는 우주의 전체 역사에서 결코 볼 수 없을 것입니다.
그러나 이 일이 일어난다고 해서 세상이 끝나는 것은 아닙니다.대부분의 경우 충돌한 파일을 약간 변경하고 변경된 콘텐츠로 새로운 커밋을 강제합니다.(댓글 추가:/* This line added to avoid collision */
위험한 것으로 판명된 매직 SHA1에 대해 git에게 가르쳐 주세요.
그래서 몇 백만 년 동안 우리는 아마도 git에 하나 또는 두 개의 "독이 있는" SHA1 값을 추가해야 할 것입니다.에 문제가공격자는 누군가가 SHA1을 파손(또는 무차별)했기 때문에 발생한 충돌입니다.
이것은 의도하지 않은 종류의 저장소보다 훨씬 가능성이 높지만, 정의상 항상 "원격" 저장소입니다.만약 공격자가 로컬 저장소에 접근할 수 있었다면 당신을 망칠 수 있는 훨씬 쉬운 방법이 있었을 거예요
따라서 이 경우 충돌은 전혀 문제가 되지 않습니다. 공격자가 의도한 것과 다른 "나쁜" 저장소가 생깁니다. 그러나 실제로 충돌 개체를 사용하지 않기 때문에 공격자가 충돌을 전혀 발견하지 못한 것과 다를 바 없습니다.그러나 이미 발생한 개체를 사용하는 것만으로 동일한 SHA1을 생성하는 동일한 파일의 "사소한" 충돌과 100% 동일합니다.
SHA-256의 사용에 관한 문제는 정기적으로 언급되고 있지만, 현시점에서는 대응하지 않는다(2012년).
주의: 2018 및 Git 2.19부터는 SHA-256을 사용하도록 코드가 리팩터링되고 있습니다.
주의(Humor): Brad Fitzpatrick()bradfitz
의 프로젝트 gatbrute를 사용하여 특정 SHA1 접두사에 커밋을 강제할 수 있습니다.
gitbrute brute 작성자+커밋 타임스탬프 쌍이 생성되어 git 커밋이 원하는 프레픽스를 갖도록 합니다.
예: https://github.com/bradfitz/deadbeef
Daniel Dinnyes는 7.1 Git Tools - Revision Selection에 대한 코멘트에서 다음과 같이 지적하고 있습니다.
프로그래밍 팀원 모두가 같은 날 밤 늑대에 의해 공격당해 살해될 가능성이 높아집니다.
보다 최근(2017년 2월)에도 SHA1 충돌의 가능성이 입증되었다.
(Linus Torvalds의 Google+ 투고를 포함한 다른 답변에서 더 많은 내용을 참조하십시오.)
- a/ 여전히 9,223,372,036,854,775,808 이상의 SHA1 계산이 필요합니다.이를 위해서는 6,500년의 단일 CPU 연산과 110년의 단일 GPU 연산과 동등한 처리 능력이 필요했습니다.
- b/는 (같은 SHA1을 사용하여) 하나의 파일을 위조하지만, 추가적인 제약으로 인해 그 내용과 크기가 동일한 SHA1을 생성하게 됩니다(콘텐츠만 충돌하는 것으로는 충분하지 않습니다). "git 해시는 어떻게 계산됩니까?blob SHA1은 내용 및 크기에 따라 계산됩니다.
자세한 내용은 Valerie Anita Aurora의 "암호화 해시 함수의 수명"을 참조하십시오.
는 다음과 같이적고 있습니다.
Google은 6500년의 CPU 연수와 110년의 GPU 연수를 들여 보안 크리티컬 애플리케이션에 SHA-1 사용을 중지해야 한다는 점을 모두에게 납득시켰습니다.
.
자세한 내용은 아래의 별도 답변에서 확인하십시오.
저장소의 이전 개체와 동일한 SHA-1 값으로 해시된 개체를 커밋할 경우 Git은 Git 데이터베이스에 있는 이전 개체를 보고 이미 작성되었다고 가정합니다.어느 시점에서 그 오브젝트를 다시 체크 아웃하려고 하면 항상 첫 번째 오브젝트의 데이터를 얻을 수 있습니다.
그럼 실패하지 않겠지만, 당신의 새로운 대상을 살리지도 않겠죠.
명령줄을 보면 어떻게 보일지 모르겠지만 분명 혼란스러울 거예요
조금 더 아래에서는 동일한 참조가 이러한 충돌 가능성을 설명하려고 시도합니다.
다음으로 SHA-1 충돌의 예를 제시하겠습니다.만약 지구상의 65억 명의 모든 인간이 프로그래밍을 하고 매초마다 전체 Linux 커널 역사(100만 Git 객체)에 해당하는 코드를 생성하여 하나의 거대한 Git 저장소로 밀어넣고 있다면,저장소에서 단일 SHA-1 개체 충돌 확률이 50%에 이를 정도로 충분한 개체를 포함할 때까지 5년이 걸립니다.프로그래밍 팀원 모두가 같은 날 밤 늑대에 의해 공격당해 살해될 가능성이 높아집니다.
2012년부터의 답변에 덧붙여, 현재(2017년 2월, 5년 후)에는,산산조각이 났다.io과의 실제의 SHA-1 충돌의 예로서, 2개의 충돌하는 PDF 파일을 작성할 수 있습니다.즉, 첫 번째 PDF 파일에 SHA-1 디지털 서명을 취득해, 두 번째 PDF 파일에 유효한 서명으로서도 악용할 수 있습니다.
또한 "죽음의 문에서 수년 동안 널리 사용되는 SHA1 기능은 이제 죽었다"와 이 그림을 참조하십시오.
2월 26일 갱신:Linus는 Google+의 투고에서 다음 사항을 확인하였습니다.
(1) 일단 하늘은 무너지지 않는다.보안 서명과 같은 것에 암호화 해시를 사용하는 것과 git과 같은 컨텐츠 주소 지정 가능한 시스템을 위한 "콘텐츠 식별자"를 생성하는 것에는 큰 차이가 있습니다.
(2) 둘째, 이 특정 SHA1 공격의 성질은 실제로 이를 완화하기 매우 쉽다는 것을 의미하며, 이를 완화하기 위한 패치가 이미 2세트나 게시되어 있습니다.
(3) 마지막으로, 세계를 파괴하지 않는 다른 해시나 오래된 git 저장소로의 비교적 간단한 이행이 있습니다.
그 전환에 대해서는 2018년 1분기 Git 2.16에서 해시 알고리즘을 나타내는 구조를 추가하였다.그 이행의 실행이 시작되었습니다.
Git 2.19(2018년 3분기)부터 Git은 New Hash로 SHA-256을 선택하여 코드에 통합 중입니다(SHA1이 아직 디폴트(Q2 2019, Git 2.21), SHA2가 후계자임).
원답(2월 25일) 단,
- 이렇게 하면 blob을 위조할 수 있지만, 위조 blob의 크기가 원래 blob과 같지 않을 수 있기 때문에 트리의 SHA-1은 여전히 변경됩니다. "git hash calculated?"를 참조하십시오.blob SHA1은 내용 및 크기에 따라 계산됩니다.
하지만 그것은 약간의 문제가 있다.아니면 여기 보이는 것처럼 svn 그 자체로도요 - 당초 답변에서 설명한 바와 같이 현재로선 이러한 시도 비용이 만만치 않습니다(6,500년 CPU 및 100년 GPU).「암호화 해시 함수의 수명」의 Valerie Anita Aurora도 참조해 주세요.
- 앞에서 설명한 바와 같이 이는 보안이나 신뢰에 관한 것이 아니라 현재 Linus Torvalds가 언급한 것처럼 에서 쉽게 검출할 수 있는 데이터 무결성(중복 제거 및 오류 감지)에 관한 것입니다.
git fsck
합니다.커밋 메시지 뒤에 가 숨겨져 있습니다.'아예', '아예', '아예', '아예'와 '아예'와 '아예'와 '아예'와 '아예'와 '아예'와 같은NUL
(단, 사기 파일에는 반드시 존재하는 것은 아닙니다).
모든 사람이 켜지는 것은 아니지만 GitHub는 켜집니다.부정한 형식의 오브젝트나 링크가 끊어진 경우 푸시는 중단됩니다.근데...디폴트로 활성화되지 않은 이유가 있습니다. - 데이터를 수, 수.pdf 파일에는 위조 소스.
헤드가 같고 내용이 다른 Git 저장소를 2개 만들 때 발생하는 실제 문제.그럼에도 불구하고 공격은 난해한 상태로 남아 있다. - Linus의 설명:
SCM의 요점은 일회성 이벤트가 아니라 지속적인 역사에 관한 것입니다.이는 기본적으로 공격이 성공하려면 시간이 지남에 따라 작동해야 하며 탐지할 수 없음을 의미합니다.
SCM을 한 번 속이고 코드를 삽입하면 다음 주에 검출되면 실제로는 도움이 되지 않습니다.화상을 입었을 뿐이야
Joey Hess는 이 PDF를 Git repo로 사용해 보고 다음과 같은 사실을 발견했다.
여기에는 동일한 SHA와 크기를 가진 두 개의 파일이 포함되며, git이 내용에 머리글을 추가하는 방법 때문에 다른 블럽을 얻을 수 있습니다.
joey@darkstar:~/tmp/supercollider>sha1sum bad.pdf good.pdf
d00bbe65d80f6d53d5c15da7c6b4f0a655c5a86a bad.pdf
d00bbe65d80f6d53d5c15da7c6b4f0a655c5a86a good.pdf
joey@darkstar:~/tmp/supercollider>git ls-tree HEAD
100644 blob ca44e9913faf08d625346205e228e2265dd12b65 bad.pdf
100644 blob 5f90b67523865ad5b1391cb4a1c010d541c816c1 good.pdf
이러한 충돌 파일에 동일한 데이터를 추가해도 다른 충돌이 생성되지만 데이터를 미리 추가하면 발생하지 않습니다.
따라서 공격(커밋 위조)의 주요 벡터는 다음과 같습니다.
- 일반 커밋 개체를 생성합니다.
- 선택한 프레픽스로서 커밋오브젝트 전체 + NUL을 사용합니다.
- 충돌하는 양호/불량 객체를 생성하기 위해 동일한 충돌자 충돌 공격을 사용합니다.
- ...좋은 커밋 객체와 나쁜 커밋 객체가 같은 트리를 가리키고 있기 때문에 이것은 쓸모가 없습니다!
또한 각 파일에 존재하는 SHA-1에 대한 암호화 충돌 공격을 이미 검출할 수 있습니다.
Git 자체에서 비슷한 체크를 추가하는 것은 약간의 계산 비용이 들 것입니다.
해시 변경 시 Linux 코멘트:
해시의 크기와 해시 알고리즘의 선택은 독립된 문제입니다.
256비트 해시로 전환하여 내부 및 네이티브 git 데이터베이스에서 사용하고 기본적으로는 해시를 40자 16진수 문자열로만 표시합니다(많은 상황에서 이미 생략한 것과 비슷합니다.
은 특별한"git git"이 한 을 알 수--full-hash
" " 수또 ( " )--abbrev=64
쓰는 또는기타 - 40으로 줄이다.
그러나 (SHA1에서 다른 해시함수로의) 이행계획은 여전히 복잡하지만 적극적으로 연구되고 있다.
캠페인이 진행 중입니다.
3월 20일 업데이트: GitHub은 가능한 공격과 그 보호에 대해 자세히 설명합니다.
SHA-1 이름은 다양한 메커니즘을 통해 신뢰를 할당할 수 있습니다.예를 들어 Git을 사용하면 암호로 커밋이나 태그에 서명할 수 있습니다.이렇게 하면 커밋 또는 태그 개체 자체만 서명되며, 이 개체는 SHA-1 이름을 사용하여 실제 파일 데이터를 포함하는 다른 개체를 가리킵니다.이러한 오브젝트가 충돌하면 유효한 것처럼 보이지만 서명자가 의도한 것과는 다른 데이터를 가리키는 시그니처가 생성될 수 있습니다.이러한 공격에서 서명인은 충돌의 절반만 보고 피해자는 나머지 절반을 봅니다.
보호:
최근의 공격은 특별한 기술을 사용하여 훨씬 짧은 시간에 충돌을 검출하는 SHA-1 알고리즘의 약점을 이용합니다.이러한 기술은 충돌 쌍 중 하나의 SHA-1을 계산할 때 검출할 수 있는 패턴을 바이트에 남깁니다.
이제 GitHub.com은 계산한 각 SHA-1에 대해 이 검출을 수행하고 오브젝트가 충돌 쌍의 절반이라는 증거가 있을 경우 동작을 중단합니다.이를 통해 공격자가 GitHub을 사용하여 프로젝트의 "무죄한" 충돌을 받아들이도록 설득하는 것을 방지하고 악의적인 반쪽을 호스팅하는 것을 방지합니다.
Mark Stevens의 " sha1collisiondetection
참조
다시 2018년 1분기 Git 2.16에 해시 알고리즘을 나타내는 구조가 추가됨에 따라 새로운 해시로의 이행 구현이 시작되었습니다.
위에서 설명한 바와 같이 지원되는 새로운 해시는 SHA-256이 됩니다.
암호학자들이 축하해 줄 것 같은데
SHA-1에 대한 위키피디아 기사 인용:
2005년 2월, 왕샤오윤, 이쿤 리사 인, 홍보 유에 의한 공격이 발표되었다.공격은 SHA-1 풀버전에서의 콜리젼을 검출할 수 있어 필요한 조작은 2^69 미만입니다(브릿 포스 검색에서는 2^80 조작이 필요합니다).
SHA-1과 같은 해시에는 여러 가지 다른 공격 모델이 있지만, 일반적으로 Marc Stevens의 HashClash 툴을 포함한 충돌 검색에서 논의됩니다.
사람들이 지적한 것처럼 git과 해시 충돌을 강제할 수 있지만, 그렇게 해도 다른 저장소에 있는 기존 오브젝트를 덮어쓰지는 않습니다.git push -f --no-thin
기존 개체를 덮어쓰지는 않지만 100% 확신할 수는 없습니다.
즉, 원격 저장소를 해킹하면 잘못된 개체를 오래된 개체로 만들 수 있습니다. 해킹된 코드를 github 또는 유사한 오픈 소스 프로젝트에 포함시킬 수 있습니다.만약 당신이 조심한다면 새로운 사용자들이 다운로드한 해킹된 버전을 소개 할 수 있을 것이다.
하지만 프로젝트 개발자가 할 수 있는 많은 일들이 수백만 달러짜리 해킹을 노출시키거나 실수로 파괴할 수도 있다고 생각합니다.개발자가 앞서 개발자를 git push --no-thin
을 받는 파일을 후, 「」, 「」가 경우도 .--no-thin
부수적인.
언급URL : https://stackoverflow.com/questions/9392365/how-would-git-handle-a-sha-1-collision-on-a-blob
'source' 카테고리의 다른 글
각 파일 및 디렉토리의 크기를 나열하고 Bash에서 내림차순으로 정렬하려면 어떻게 해야 합니까? (0) | 2023.04.11 |
---|---|
Swift에서 UIImageView 개체에 대한 작업을 할당하는 방법 (0) | 2023.04.11 |
NAMED 콘텐츠를 사용하여 WPF UserControl을 작성하는 방법 (0) | 2023.04.11 |
WPF가 현재 설계 모드로 실행되고 있는지 여부를 확인할 수 있는 방법이 있습니까? (0) | 2023.04.11 |
Git 저장소의 병합 충돌을 해결하려면 어떻게 해야 합니까? (0) | 2023.04.11 |