맞아요. 다만 난독화(obfuscation)는 “복잡하게 만들기”일 뿐, 암호화/DRM처럼 완전한 보호는 아니고 의지만 있으면 결국 분석됩니다. 그래서 보통은 번들링 + 최소화(minify) + 난독화 + 서버로 로직 이동 + 배포/운영 설정을 같이 묶어서 합니다.
아래는 “웹(브라우저)에서 돌아가는 JS/TS” 기준으로, 실제로 많이 쓰는 방법들입니다.
1) 제일 기본: 번들 + 최소화(=가성비 최고)
- Webpack / Vite / Rollup / esbuild 중 하나로 번들링
- Terser로 압축/난독화(변수명 변경 포함)
(A) Vite 사용 시 (권장/간단)
Vite는 기본적으로 빌드에서 minify를 해줍니다.
import { defineConfig } from "vite";
export default defineConfig({
build: {
minify: "terser",
terserOptions: {
compress: true,
mangle: true,
format: { comments: false },
},
sourcemap: false, // 배포 시 소스맵 끄기(아래 참고)
},
});
(B) Webpack 사용 시
webpack.config.js에 TerserPlugin 설정
const TerserPlugin = require("terser-webpack-plugin");
module.exports = {
// ...
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: true,
mangle: true,
format: { comments: false },
},
extractComments: false,
}),
],
},
};
이것만 해도 소스 읽기 난이도는 확 올라가고, 용량/로딩도 좋아집니다.
2) 더 “난독화”답게: javascript-obfuscator(강도 ↑, 부작용도 ↑)
Terser보다 더 공격적으로 꼬는 방식입니다(문자열 암호화, control-flow flattening 등).
설치
npm i -D javascript-obfuscator
(A) 빌드 결과물(dist)에 후처리로 적용 (가장 안전한 편)
npx javascript-obfuscator dist --output dist-obf \
--compact true \
--control-flow-flattening true \
--control-flow-flattening-threshold 0.6 \
--string-array true \
--string-array-threshold 0.75 \
--dead-code-injection false \
--self-defending false \
--debug-protection false
추천 포인트
control-flow-flattening / string-array가 체감 난독화에 가장 큽니다.
dead-code-injection, self-defending, debug-protection는 호환성/성능/오탐 이슈가 생길 수 있어 보통은 꺼두고 시작합니다.
(B) 설정 파일로 관리(권장)
obfuscator.json
{
"compact": true,
"controlFlowFlattening": true,
"controlFlowFlatteningThreshold": 0.6,
"stringArray": true,
"stringArrayThreshold": 0.75,
"simplify": true,
"deadCodeInjection": false,
"selfDefending": false,
"debugProtection": false,
"renameGlobals": false
}
실행:
npx javascript-obfuscator dist --output dist-obf --config obfuscator.json
3) 소스노출 관점에서 “진짜 중요한 것” 3가지
1) 소스맵(sourcemap) 관리
2) “보호하고 싶은 로직”은 가능하면 서버로
브라우저에 내려가는 순간, 결국은 노출됩니다.
- 가격정책/정책판정/치트방지/검증 로직 등은 서버에서 최종 판정 구조로.
3) 비밀값(키/토큰)을 프론트에 넣지 않기
난독화로 숨길 수 없습니다.
- API Key는 서버 프록시 또는 권한이 제한된 공개키(도메인 제한 등)만 사용.
4) 상용 보호 쪽에서 많이 같이 하는 것들(현실적인 조합)
-
라이선스/구독 기반이면:
- 서버에서 라이선스 검증 → 기능 토글/만료 처리
- 빌드에 워터마크(고객사별 식별자) 삽입
-
배포 보안:
- 코드 서명/무결성 체크(가능한 범위 내)
- CDN 캐시/헤더 설정(맵 파일 차단 등)
5) 추천 “출발점” (성능/안정/보호 밸런스)
- 번들링 + Terser 최소화로 먼저 배포
- 그래도 부족하면 빌드 산출물에 javascript-obfuscator를 “후처리”로 추가
- 문제 생기면 옵션을 조금씩 켜고 끄며 튜닝 (특히 flattening/threshold)
원하는 방향이 (1) 프론트 웹앱, (2) 라이브러리/SDK 배포, (3) Node 서버 코드, (4) 모바일(React Native 등) 중에 어디에 더 가까워요? 그거에 맞춰 권장 툴체인(Vite/webpack) + 옵션 세트(성능/호환성 중심 vs 난이도 중심)로 딱 맞게 구성 예시를 더 구체적으로 잡아줄게요.