코드 속 투명 망토: '글래스웜' 유니코드 공격, 개발자를 위협하는 보이지 않는 그림자


요즘 개발 커뮤니티에서 ‘글래스웜(Glassworm)‘이라는 이름이 심심치 않게 들려옵니다. 처음 이 단어를 접했을 때, 대체 뭘까 싶어서 자세히 찾아보게 됐는데요. 내용을 들여다보니, 이건 단순히 보안 뉴스 한 토막으로 치부할 문제가 아니더라고요. 개발자로서 우리 모두가 경각심을 가져야 할, 정말 무서운 공격 방식이거든요.

저는 이 글을 통해 글래스웜 공격이 정확히 무엇인지, 그리고 왜 이 문제가 심각하며 우리가 어떻게 대응해야 할지 제 생각을 공유해볼까 합니다. 복잡한 기술 용어보다는 핵심적인 개념과 그것이 우리 일상에 미치는 영향에 집중해서 이야기해볼게요.

글래스웜, 대체 뭘까요? 눈에 보이지 않는 코드의 위협

핵심은 이겁니다. 글래스웜 공격은 ‘유니코드’의 특성을 악용해서 사람의 눈에는 보이지 않는, 혹은 매우 미묘하게 보이는 문자를 코드에 심어 공격을 감행하는 방식입니다. 여기서 유니코드는 전 세계의 모든 문자를 컴퓨터에서 표현하기 위한 국제 표준인데요, 이 표준 안에는 우리가 일반적으로 보지 못하는 특수 문자들도 많이 포함되어 있습니다. 예를 들면, ‘오른쪽에서 왼쪽으로 쓰기(Right-to-Left Override)’ 같은 문자 방향 제어 코드나, ‘폭이 없는 공백(Zero Width Joiner)’ 같은 문자들 말이죠.

문제는 이런 문자들을 코드 사이에 끼워 넣으면, 우리 눈에는 일반적인 코드처럼 보이지만 실제로는 컴파일러나 인터프리터가 다르게 해석하게 만들 수 있다는 거예요. 예를 들어, if (isAdmin)이라는 조건문 사이에 눈에 보이지 않는 유니코드 문자를 넣어 if (isNotAdmin)처럼 작동하게 만들거나, 혹은 특정 함수 호출을 교묘하게 숨겨서 악성 코드를 실행하게 할 수도 있습니다.

image

이게 왜 위험하냐면요, 우리는 코드를 읽을 때 당연히 눈으로 보이는 대로 해석합니다. GitHub 같은 코드 저장소나 VS Code 같은 IDE에서 코드를 볼 때도 마찬가지죠. 하지만 글래스웜 공격은 이 ‘보이는 것’과 ‘실제 작동하는 것’ 사이에 괴리를 만들어냅니다. 개발자가 아무리 꼼꼼하게 코드를 리뷰해도, 눈에 보이지 않는 글자 때문에 공격을 발견하기가 거의 불가능한 수준이에요.

그래서 이게 왜 개발자에게 심각한 문제인가요?

여기서 중요한 게 하나 있거든요. 바로 소프트웨어 공급망(Software Supply Chain) 문제입니다. 요즘 소프트웨어 개발은 혼자 모든 코드를 다 짜는 방식이 아니잖아요. 수많은 오픈소스 라이브러리와 패키지를 가져다 쓰고, 의존성을 엮어서 사용하죠. NPM, PyPI, Maven Central 같은 레지스트리에서 수많은 패키지를 다운로드받아 쓰고요.

글래스웜 공격은 이런 공급망의 취약점을 노립니다. 만약 인기 있는 오픈소스 라이브러리나 패키지에 글래스웜 기법이 적용된 코드가 숨겨져 있다면 어떨까요? 해당 라이브러리를 사용하는 수많은 프로젝트들이 자신도 모르는 사이에 악성 코드에 노출될 수 있습니다. 우리가 npm install이나 pip install 한 번 하는 순간, 프로젝트 전체가 감염될 가능성이 생기는 거죠.

더군다나 이 공격은 코드 리뷰를 무력화시킵니다. 팀원과 코드를 공유하고 Pull Request(PR)를 통해 변경사항을 검토하는 과정은 소프트웨어 품질과 보안을 유지하는 핵심 단계잖아요. 그런데 글래스웜 공격은 PR에서 변경사항을 확인해도 눈에 보이지 않기 때문에, 악성 코드를 승인해버리는 상황이 발생할 수 있습니다. 저는 이 부분이 가장 충격적이면서도 무서웠어요. 우리가 의존하는 코드 검토 시스템 자체가 속수무책이 될 수 있다는 뜻이니까요.

GitHub나 VS Code 같은 플랫폼에서도 이 문제를 인지하고 있지만, 유니코드의 모든 특수 문자를 시각적으로 표시하거나 경고하는 건 또 다른 복잡성을 야기합니다. 예를 들어, 특정 유니코드 문자는 정말 ‘정상적인’ 국제화(i18n) 작업에 사용될 수도 있거든요. 이런 딜레마 속에서 공격자들은 계속해서 빈틈을 찾아내고 있는 상황입니다.

제 경험을 비춰본 글래스웜의 그림자

제가 실제로 여러 프로젝트에 참여하면서 느꼈던 점은, 개발자들이 코드의 ‘가독성’과 ‘직관성’에 얼마나 많이 의존하고 있는지였습니다. 우리는 코드를 눈으로 보고, 머릿속으로 시뮬레이션하며 이해하죠. 변수명, 함수명, 들여쓰기, 주석 등 모든 시각적 요소가 코드를 파악하는 데 결정적인 역할을 하고요.

그런데 글래스웜은 바로 이 ‘시각적 이해’를 정면으로 배신하는 공격입니다. 예전부터 비슷한 개념으로 ‘타이포스쿼팅(Typosquatting)’ 공격이나 의존성 혼동(Dependency Confusion) 같은 것들이 있었잖아요. 이름만 살짝 바꿔서 악성 패키지를 배포하는 방식이요. 그런 공격들은 그래도 ‘이름’이라는 시각적인 단서가 있었죠. 뭔가 이상하다고 느낄 여지라도 있었다는 겁니다.

하지만 글래스웜은 그마저도 없습니다. 마치 코드에 투명 망토를 두른 악당 같다고 할까요? 우리는 코드를 볼 때 무의식적으로 ‘믿음’을 가집니다. 눈에 보이는 대로가 전부라고 믿는 거죠. 이 믿음이 깨졌을 때 오는 혼란은 생각보다 훨씬 클 수 있습니다. 제가 평소에 코드 리뷰를 할 때도, 복잡한 로직이나 새로운 라이브러리 도입에 집중했지, ‘눈에 보이지 않는 문자’가 숨어있을 가능성까지 염두에 두진 않았거든요. 이런 제 무지함이 문득 섬뜩하게 느껴지기도 했습니다.

image

저는 개발자로서 매일 새로운 라이브러리를 탐색하고, 동료의 코드를 검토하며, 오픈소스에 기여하기도 합니다. 이 모든 활동이 ‘신뢰’를 기반으로 이루어지죠. 글래스웜 공격은 이런 신뢰의 기반 자체를 흔들 수 있다는 점에서 단순히 기술적인 취약점을 넘어, 개발 문화 전반에 대한 우리의 인식을 바꿔야 한다는 강력한 메시지를 던지고 있다고 생각해요.

그럼 우리는 어떻게 대응해야 할까요?

이런 공격에 완전히 면역이 되는 것은 불가능에 가깝겠지만, 그래도 우리가 할 수 있는 일들은 있습니다.

첫째, 인식과 교육이 가장 중요합니다. 글래스웜 같은 공격 방식이 존재한다는 사실을 아는 것만으로도 큰 방어막이 됩니다. 내 코드, 내가 사용하는 라이브러리에 이런 눈에 보이지 않는 위협이 숨어 있을 수 있다는 가능성을 늘 염두에 두는 자세가 필요하죠.

둘째, 도구의 도움을 받아야 합니다. 사람이 눈으로 찾아내기 어려운 문제인 만큼, 이를 탐지할 수 있는 정적 분석 도구(Static Analysis Tool)나 린터(Linter)의 역할을 강화해야 합니다. 이미 몇몇 도구들은 특정 유니코드 문자열 패턴을 탐지하거나 경고하는 기능을 제공하고 있어요. 우리가 사용하는 IDE나 코드 에디터에서도 이런 특수 문자를 시각적으로 강조하거나 경고하는 기능이 점차 강화되어야 하고요. GitHub 같은 코드 호스팅 플랫폼에서도 뷰어에서 이런 문자를 더 명확하게 표시하거나, 아예 경고 메시지를 띄워주는 방향으로 개선이 이루어져야 합니다.

셋째, 의존성 관리에 더욱 신중해야 합니다. 항상 최신 버전의 패키지를 사용하는 것이 좋지만, 맹목적인 업데이트보다는 변경 로그를 꼼꼼히 확인하고, 평판이 좋고 활발히 관리되는 프로젝트의 의존성만 사용하는 것이 좋습니다. 그리고 너무 많은 불필요한 의존성을 줄이는 것도 하나의 방법이 될 수 있고요.

마지막으로, 보안 업데이트와 패치에 대한 빠른 대응입니다. 공격자들은 계속해서 새로운 방법을 찾아내고, 방어자들은 이를 막기 위해 노력합니다. 관련 도구의 업데이트나 플랫폼의 보안 패치가 나오면, 최대한 빠르게 적용해서 잠재적인 위협에 대비하는 것이 중요합니다.

개발자의 숙명, 보이지 않는 위협과 싸우는 일

정리하자면, 글래스웜 공격은 단순히 뉴스거리가 아니라 실제로 우리한테 영향을 줄 수 있는, 매우 정교하고 위험한 공급망 공격의 일종입니다. 보이지 않는 코드로 개발자의 눈을 속이고, 우리가 구축한 신뢰 시스템을 무너뜨리려는 시도죠.

저는 이 공격을 보면서, 개발자의 숙명이란 끊임없이 보이지 않는 위협과 싸우는 일이라는 생각을 다시금 하게 됐습니다. 코드는 눈에 보이는 대로 작동하지 않을 수 있고, 우리가 당연하게 믿었던 것들이 언제든 깨질 수 있다는 경고음으로 들리기도 합니다.

결론적으로, 글래스웜 같은 공격은 우리에게 더 깊은 경각심과 함께, 보안에 대한 근본적인 접근 방식의 변화를 요구합니다. 단순히 기능 구현에만 집중할 것이 아니라, 우리가 작성하고 사용하는 모든 코드에 대해 한 번 더 의심하고, 끊임없이 검증하려는 노력이 필요할 것 같습니다. 이 글이 여러분의 개발 환경을 다시 한번 돌아보는 계기가 되었으면 좋겠습니다.