요즘 나는 npm 명령어를 Docker 컨테이너 안에서 실행하도록 alias를 걸어둠
이렇게 하면 내 환경 변수를 노출하지 않고, 현재 디렉토리 외부 파일에도 접근하지 않으며, .bashrc 같은 설정 파일에도 접근하지 못하게 됨
참고: Run tools inside Docker
그건 너무 과한 샌드박싱 같음. 어차피 npm은 바로 실행될 임의 코드를 다운로드하니까
대신 pnpm을 추천함. 기본적으로 lifecycle 스크립트를 실행하지 않고, 허용할 스크립트를 화이트리스트로 지정할 수 있음
post-install 스크립트를 악마화하는 건 잘못된 안전 환상을 줄 뿐임
진짜 보호를 원한다면 설치뿐 아니라 실행 전체를 샌드박스 안에서 돌려야 함
지금처럼 post-install만 막는 건 절반짜리 대책에 불과함. 공급망 공격은 점점 더 위험해지고 있음
공격 벡터는 너무 많음. 악의적인 의도를 가진다면 인기 있는 플러그인이나 LSP 이름을 오타 스쿼팅해서 에디터 실행 시 자동으로 코드가 실행되게 만들 수 있음 neovim이나 vscode가 감염되면 이미 사용자 권한으로 충분히 위험한 일들을 할 수 있음
나는 sandbox-run을 사용함
단순 alias는 node/npm에는 통하지만, 다른 프로그램들에는 적용하기 어려움. 컨테이너에 필요한 리소스를 마운트해야 하니까
그래도 결국 악성 패키지를 다운로드할 수 있지 않음? 의존성 자체가 감염되어 있을 수도 있음
예전부터 궁금했음. 왜 사람들은 아무렇지 않게 npm을 시스템에서 돌리는지 make처럼 재현 가능한 빌드에 익숙한 입장에서는, npm이 매번 다른 걸 다운로드하고 다른 결과를 내는 게 충격이었음
CSS 생성조차 npm 의존성으로 묶는 게 이상했음. 그래서 Docker 안에 npm 환경을 통째로 고정(freeze) 시켜봤지만, 결국 지는 싸움 같음
요즘 모든 패키지 매니저가 그런 식으로 동작함. maven, nuget, pip, npm 모두 마찬가지임
과거처럼 배포판 패키지 매니저에 의존하면 지금 같은 빠른 생태계는 불가능했을 것임
다만 보안이 강화된 새 패키지 매니저들이 등장하고 있음. 이유를 이해하지 못한 채 수단만 비난하는 건 옳지 않음
프론트엔드 개발은 마치 “믿어줘 브로”식 와일드 웨스트 같음. 브라우저 진화 과정상 어쩔 수 없이 덕트테이프처럼 이어붙인 느낌임
npm을 Docker로 고정했다면, 매번 의존성 업데이트 후 그 환경을 검증했는지 묻고 싶음
사실 npm과 pnpm은 이미 기본적으로 lock 파일로 의존성을 고정함
“npm install thing”이 너무 쉽고 싸서 생긴 문제임
많은 오픈소스가 품질보다 이력서용 코드로 채워지고, 결국 거대 기업의 광고 추적기나 지갑 앱 같은 걸 만드는 데 쓰임
npm install은 단순히 패키지를 다운로드하는 게 아니라 코드를 실행함 package.json의 preinstall, install, postinstall 훅이 실제로 실행됨
합법적으로 설치 과정에서 임의 명령을 실행해야 할 이유가 뭘까?
관련 보고서: PhantomRaven npm malware
또 다른 사례: Socket.dev 블로그
사실 이런 구조는 오래된 패키지 매니저(DEB, RPM)에도 있었음
예를 들어 리눅스 커널 패키지는 설치 후 initramfs 재생성, GRUB 업데이트 등을 위해 post-install 스크립트를 실행함
대부분의 DEB/RPM 패키지에 이런 스크립트가 포함되어 있음. 즉, 설계 자체의 문제임
문제는 npm은 아무나 패키지를 올릴 수 있다는 점임
리눅스 배포판은 신뢰할 수 있는 메인테이너 체계가 있고, PGP 기반의 루트 트러스트를 직접 구축하기도 함
반면 npm, pip, rubygems, cargo 등은 사실상 “curl | bash”의 세련된 버전일 뿐임
예를 들어 Mediasoup 프로젝트는 C++로 작성된 스트리밍 라이브러리인데, 설치 시 소스를 직접 컴파일함
유지보수 부담을 줄이기 위해 이런 post-install 빌드가 필요했음
Swift Package Manager도 Package.swift 파일을 실제로 실행함
다만 강하게 샌드박싱되어 있어서 악용은 어렵다고 들음
참고: SwiftPM 문서, PackageDescription
참고로 pnpm v10은 기본적으로 모든 lifecycle 스크립트를 비활성화하고, 사용자가 직접 허용해야 함 관련 논의
최근 npm 공격들을 보면, 이제는 npm으로 개발하는 게 안전한가 싶음
React 프로젝트를 시작할 때마다 수백 개의 패키지가 깔리는데, 뭘 하는지도 모름
백엔드에서는 필요한 패키지만 명시적으로 설치하지만, 프론트엔드는 취약점의 판도라 상자 같음
사실 모든 언어 생태계가 비슷함. 단지 npm이 제일 크고 뉴스에 많이 나올 뿐임
Rust의 jj를 설치했더니 470개, Python의 wan2gp는 211개 패키지가 깔렸음. 다 거기서 거기임
JavaScript 생태계는 구조적으로 공격에 취약함 xz 사건처럼, 각 의존성이 무작위 개인에게 달려 있고, 그들이 사회공학 공격에 당하지 않을 거라 믿어야 함
의존성이 적을수록 좋음. 0개면 완벽임. 그게 진짜 승리임
참고로 PyPI도 안전하지 않음. GitHub Actions 해킹으로 정상 패키지에 악성 코드가 삽입된 사례도 있음
Angular, Vue 같은 프레임워크로 개발할 때마다 불안함 node_modules 안의 수천 개 의존성을 보면 재앙의 예고처럼 느껴짐
오픈소스 개발자 한 명이 피싱당하면 바로 감염될 수도 있음
JavaScript 생태계는 근본적으로 깨져 있음. 오타 한 번으로 공급망 공격에 노출됨
NuGet이나 Maven도 가능은 하지만, 그쪽은 표준 라이브러리가 커서 의존성이 적고 통제감이 있음
Go는 패키지 이름 대신 repo URL을 사용해서 오타 스쿼팅을 줄임
완벽하진 않지만 그래도 한 단계 나음
Deno는 이런 문제를 해결함. Node.js / npm의 구조적 문제임
86,000회 다운로드 중 대부분은 실제 사용자가 아니라 자동화된 스캐너나 봇일 가능성이 큼
새 버전을 올리면 하루이틀 만에 수백 번 다운로드되지만, 실제 사람은 아닐 수도 있음
즉, 감염된 사용자는 거의 없을 수도 있음
나도 라이브러리를 올렸을 때 초반엔 주당 300회, 이후엔 100회 정도 다운로드됐음
AI 챗봇이 환각으로 만들어낸 패키지 이름을 노린 공격도 많음. 단순한 통계 이상임
혹은 누군가의 좀비 CI가 계속 다운로드하는 걸 수도 있음
하지만 LLM이 만들어낸 가짜 패키지 이름을 노린 공격이라면, 실제로 많은 개발자가 감염됐을 수도 있음
Hacker News 의견
요즘 나는
npm명령어를 Docker 컨테이너 안에서 실행하도록 alias를 걸어둠이렇게 하면 내 환경 변수를 노출하지 않고, 현재 디렉토리 외부 파일에도 접근하지 않으며,
.bashrc같은 설정 파일에도 접근하지 못하게 됨참고: Run tools inside Docker
npm은 바로 실행될 임의 코드를 다운로드하니까대신
pnpm을 추천함. 기본적으로 lifecycle 스크립트를 실행하지 않고, 허용할 스크립트를 화이트리스트로 지정할 수 있음진짜 보호를 원한다면 설치뿐 아니라 실행 전체를 샌드박스 안에서 돌려야 함
지금처럼 post-install만 막는 건 절반짜리 대책에 불과함. 공급망 공격은 점점 더 위험해지고 있음
neovim이나vscode가 감염되면 이미 사용자 권한으로 충분히 위험한 일들을 할 수 있음단순 alias는
node/npm에는 통하지만, 다른 프로그램들에는 적용하기 어려움. 컨테이너에 필요한 리소스를 마운트해야 하니까예전부터 궁금했음. 왜 사람들은 아무렇지 않게
npm을 시스템에서 돌리는지make처럼 재현 가능한 빌드에 익숙한 입장에서는,npm이 매번 다른 걸 다운로드하고 다른 결과를 내는 게 충격이었음CSS 생성조차 npm 의존성으로 묶는 게 이상했음. 그래서 Docker 안에 npm 환경을 통째로 고정(freeze) 시켜봤지만, 결국 지는 싸움 같음
maven,nuget,pip,npm모두 마찬가지임과거처럼 배포판 패키지 매니저에 의존하면 지금 같은 빠른 생태계는 불가능했을 것임
다만 보안이 강화된 새 패키지 매니저들이 등장하고 있음. 이유를 이해하지 못한 채 수단만 비난하는 건 옳지 않음
npm을 Docker로 고정했다면, 매번 의존성 업데이트 후 그 환경을 검증했는지 묻고 싶음사실
npm과pnpm은 이미 기본적으로 lock 파일로 의존성을 고정함npm install thing”이 너무 쉽고 싸서 생긴 문제임많은 오픈소스가 품질보다 이력서용 코드로 채워지고, 결국 거대 기업의 광고 추적기나 지갑 앱 같은 걸 만드는 데 쓰임
npm install은 단순히 패키지를 다운로드하는 게 아니라 코드를 실행함package.json의 preinstall, install, postinstall 훅이 실제로 실행됨합법적으로 설치 과정에서 임의 명령을 실행해야 할 이유가 뭘까?
관련 보고서: PhantomRaven npm malware
또 다른 사례: Socket.dev 블로그
예를 들어 리눅스 커널 패키지는 설치 후 initramfs 재생성, GRUB 업데이트 등을 위해 post-install 스크립트를 실행함
대부분의 DEB/RPM 패키지에 이런 스크립트가 포함되어 있음. 즉, 설계 자체의 문제임
npm은 아무나 패키지를 올릴 수 있다는 점임리눅스 배포판은 신뢰할 수 있는 메인테이너 체계가 있고, PGP 기반의 루트 트러스트를 직접 구축하기도 함
반면
npm,pip,rubygems,cargo등은 사실상 “curl | bash”의 세련된 버전일 뿐임유지보수 부담을 줄이기 위해 이런 post-install 빌드가 필요했음
Package.swift파일을 실제로 실행함다만 강하게 샌드박싱되어 있어서 악용은 어렵다고 들음
참고: SwiftPM 문서, PackageDescription
pnpm v10은 기본적으로 모든 lifecycle 스크립트를 비활성화하고, 사용자가 직접 허용해야 함관련 논의
최근
npm공격들을 보면, 이제는npm으로 개발하는 게 안전한가 싶음React 프로젝트를 시작할 때마다 수백 개의 패키지가 깔리는데, 뭘 하는지도 모름
백엔드에서는 필요한 패키지만 명시적으로 설치하지만, 프론트엔드는 취약점의 판도라 상자 같음
npm이 제일 크고 뉴스에 많이 나올 뿐임jj를 설치했더니 470개, Python의wan2gp는 211개 패키지가 깔렸음. 다 거기서 거기임xz사건처럼, 각 의존성이 무작위 개인에게 달려 있고, 그들이 사회공학 공격에 당하지 않을 거라 믿어야 함PyPI도 안전하지 않음. GitHub Actions 해킹으로 정상 패키지에 악성 코드가 삽입된 사례도 있음Angular, Vue 같은 프레임워크로 개발할 때마다 불안함
node_modules안의 수천 개 의존성을 보면 재앙의 예고처럼 느껴짐오픈소스 개발자 한 명이 피싱당하면 바로 감염될 수도 있음
JavaScript 생태계는 근본적으로 깨져 있음. 오타 한 번으로 공급망 공격에 노출됨
NuGet이나 Maven도 가능은 하지만, 그쪽은 표준 라이브러리가 커서 의존성이 적고 통제감이 있음
완벽하진 않지만 그래도 한 단계 나음
86,000회 다운로드 중 대부분은 실제 사용자가 아니라 자동화된 스캐너나 봇일 가능성이 큼
새 버전을 올리면 하루이틀 만에 수백 번 다운로드되지만, 실제 사람은 아닐 수도 있음
즉, 감염된 사용자는 거의 없을 수도 있음
AI 챗봇이 환각으로 만들어낸 패키지 이름을 노린 공격도 많음. 단순한 통계 이상임
더 자세한 공격 설명은 BleepingComputer 기사 참고
npm install중 HTTP URL을 의존성으로 사용하는 패키지를 탐지하거나 필터링할 방법이 있을까 궁금함요청자별로 다른 페이로드를 보낼 수 있어서 일반적인 스캐너로는 탐지가 어려움
취미 개발자로서 이런 공급망 공격에 대비하려면 어떻게 해야 할지 고민임
유명한 튜토리얼을 따라가며 의존성을 설치하다 보면, 어느새 보안에 무심해짐
내 홈랩에도 여러 서비스를 돌리는데, 혹시라도 봇이 침투할까 걱정임. 어디서부터 시작해야 할까?
완벽한 보장은 아니지만, 전체 서버가 뚫리는 것보단 훨씬 낫음
필요한 코드만 직접 복사해 쓰는 것도 좋은 학습이자 안전한 방법임
이런 구조라면 수백만 사용자가 직접 검증할 필요 없이 배포판 수준에서 신뢰성 확보가 가능함
예: Hono, Zod
나는 최근 Bun으로 전환했는데, 기본적으로 DB 드라이버나 S3 클라이언트 같은 게 내장되어 있어 추가 다운로드가 줄어듦
lifecycle 훅에서 의존성을 가져오는 구조는 언제든 공격 전환점이 될 수 있음
지금은 정상이라도, 나중에 소유자가 해킹당하거나 마음을 바꾸면 악성 코드로 바뀔 수 있음
이런 형태의 설치 훅은 결국 지속 불가능한 설계임