๐Ÿ“Œ 1. ์›น ํ”„๋กœ์ ํŠธ ํด๋” ๊ตฌ์กฐ - ๊ธฐ์ดˆ โ†’ ์‹ค๋ฌด โ†’ ์‹ฌํ™” โ†’ ์‹ค์ „ ์˜ˆ์‹œ


๐Ÿ  1-1. ๊ธฐ๋ณธ ๊ตฌ์กฐ (๊ธฐ์ดˆ)

/project
 โ”œโ”€โ”€ index.html       โ†’ ๋ฉ”์ธ ์„ค๊ณ„๋„ ๐Ÿ“„
 โ”œโ”€โ”€ css/
 โ”‚    โ””โ”€โ”€ style.css    โ†’ ์ธํ…Œ๋ฆฌ์–ด ๋ฒฝ์ง€ ๐ŸŽจ
 โ”œโ”€โ”€ js/
 โ”‚    โ””โ”€โ”€ main.js      โ†’ ์ „๊ธฐ, ๊ธฐ๋Šฅ ์ œ์–ด โšก
 โ””โ”€โ”€ images/
      โ””โ”€โ”€ logo.png     โ†’ ๊ฐ€๊ตฌ, ์†Œํ’ˆ ๐Ÿ›‹๏ธ

๐Ÿ“ข ๋น„์œ :


๐Ÿš€ 1-2. ์‹ค๋ฌดํ˜• ๊ตฌ์กฐ (์ค‘๋Œ€ํ˜• ํ”„๋กœ์ ํŠธ)

/project
 โ”œโ”€โ”€ public/                 โ†’ HTML, favicon, robots.txt ๋“ฑ ์ •์  ํŒŒ์ผ
 โ”œโ”€โ”€ src/
 โ”‚    โ”œโ”€โ”€ assets/            โ†’ ์ด๋ฏธ์ง€, ํฐํŠธ, ์•„์ด์ฝ˜, ์˜์ƒ ๐ŸŽจ
 โ”‚    โ”œโ”€โ”€ components/        โ†’ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ UI ์กฐ๊ฐ ๐Ÿงฉ
 โ”‚    โ”œโ”€โ”€ pages/             โ†’ ํŽ˜์ด์ง€ ๋‹จ์œ„ ๊ตฌ์„ฑ ๐Ÿ“„
 โ”‚    โ”œโ”€โ”€ styles/            โ†’ CSS, SCSS, ๋ชจ๋“ˆํ™”๋œ ์Šคํƒ€์ผ ํŒŒ์ผ ๐ŸŽ€
 โ”‚    โ”œโ”€โ”€ scripts/           โ†’ API ํ†ต์‹ , ์œ ํ‹ธ ํ•จ์ˆ˜, JS ๊ธฐ๋Šฅ ๐Ÿง 
 โ”‚    โ”œโ”€โ”€ tests/             โ†’ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ, e2e ํ…Œ์ŠคํŠธ ๐Ÿงช
 โ”‚    โ””โ”€โ”€ hooks/             โ†’ ์ปค์Šคํ…€ ํ›…, ์ƒํƒœ ๊ด€๋ฆฌ (React ๋“ฑ) ๐Ÿ”
 โ”œโ”€โ”€ dist/                   โ†’ ๋นŒ๋“œ๋œ ๋ฐฐํฌ์šฉ ํด๋” ๐Ÿ“ฆ
 โ”œโ”€โ”€ .gitignore              โ†’ ๋ถˆํ•„์š” ํŒŒ์ผ ๋ฌด์‹œ ์„ค์ • ๐Ÿšซ
 โ”œโ”€โ”€ package.json            โ†’ ํ”„๋กœ์ ํŠธ ๋ฉ”ํƒ€ ์ •๋ณด ๐Ÿ“ฆ
 โ””โ”€โ”€ README.md               โ†’ ํ”„๋กœ์ ํŠธ ์„ค๋ช…์„œ ๐Ÿ“š

โœ… ์‹ค๋ฌด ํ•ต์‹ฌ ํฌ์ธํŠธ:


๐Ÿ’Ž 1-3. ์‹ฌํ™”: ๋„ค์ด๋ฐ & ํ˜‘์—… ๊ทœ์น™

๊ทœ์น™ ์„ค๋ช…
์†Œ๋ฌธ์ž + kebab-case ๋Œ€์†Œ๋ฌธ์ž ์ถฉ๋Œ ๋ฐฉ์ง€, ํŒ€ ํ†ต์ผ์„ฑ ์œ ์ง€ ๐Ÿ“
๊ธฐ๋Šฅ๋ณ„ ํด๋” ๋ช…ํ™• ๋ถ„๋ฆฌ assets, components, pages ๋ช…ํ™• ๊ตฌ๋ถ„ โœ…
README.md & docs ํด๋” ํด๋” ๊ตฌ์กฐ, ํ™˜๊ฒฝ ๋ณ€์ˆ˜, ์„ธํŒ…๋ฒ• ํ•„์ˆ˜ ๋ฌธ์„œํ™” ๐Ÿ“–
ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๊ด€๋ฆฌ .env ํŒŒ์ผ ๋ถ„๋ฆฌ, .gitignore๋กœ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๐Ÿ”

๐Ÿ”ฅ 1-4. ์‹ค์ „ ํด๋” ์˜ˆ์‹œ (React ๊ธฐ์ค€)

/my-project
 โ”œโ”€โ”€ public/
 โ”‚    โ””โ”€โ”€ index.html  // ์ •์  HTML
 โ”œโ”€โ”€ src/
 โ”‚    โ”œโ”€โ”€ assets/     // ์ด๋ฏธ์ง€, ํฐํŠธ
 โ”‚    โ”œโ”€โ”€ components/ // Button, Navbar ๋“ฑ UI
 โ”‚    โ”œโ”€โ”€ pages/      // HomePage, AboutPage
 โ”‚    โ”œโ”€โ”€ hooks/      // useAuth, useFetch
 โ”‚    โ”œโ”€โ”€ styles/     // variables.scss, mixins.scss
 โ”‚    โ””โ”€โ”€ scripts/    // api.js, utils.js
 โ”œโ”€โ”€ dist/            // ๋นŒ๋“œ ๊ฒฐ๊ณผ
 โ”œโ”€โ”€ .env             // ํ™˜๊ฒฝ ๋ณ€์ˆ˜ (API KEY ๋“ฑ)
 โ”œโ”€โ”€ .gitignore
 โ”œโ”€โ”€ README.md
 โ””โ”€โ”€ package.json

๐ŸŽฏ 1-5. ๊ธฐ์ˆ ๋ฉด์ ‘ ๋Œ€๋น„ ์งˆ๋ฌธ

์งˆ๋ฌธ ์‹ฌํ™” ๋‹ต๋ณ€
ํด๋” ๊ตฌ์กฐ ์–ด๋–ป๊ฒŒ ์„ค๊ณ„? src/dist ๊ตฌ๋ถ„, ๊ธฐ๋Šฅ/์—ญํ• ๋ณ„๋กœ ์ฒ ์ €ํžˆ ๋‚˜๋ˆ„๊ณ , README & .env๋กœ ํ˜‘์—… ํŽธ์˜์„ฑ ํ™•๋ณด
๋„ค์ด๋ฐ ๊ทœ์น™? kebab-case, ์†Œ๋ฌธ์ž ์ผ๊ด€์„ฑ, ํŒ€ ๋‚ด ๋„ค์ด๋ฐ ๋ฃฐ ๋ฌธ์„œํ™”
ํ˜‘์—… ์‹œ ์–ด๋–ป๊ฒŒ ํด๋” ๊ตฌ์กฐ ํ†ต์ผ? docs์— ๋ช…ํ™•ํžˆ ์ •์˜, Linter์™€ CI์—์„œ ํด๋” ๊ทœ์น™ ๊ฒ€์ฆ ๊ฐ€๋Šฅ

๐Ÿ“Œ ์‹ค์ „ TIP!

๋Œ€ํ˜• ํ”„๋กœ์ ํŠธ ์‹œ์ž‘ ์ „:

  • ๐Ÿ“– README์— ํด๋” ๊ตฌ์กฐ, ๋ธŒ๋žœ์น˜ ์ „๋žต, ํ™˜๊ฒฝ ์„ธํŒ… ๊ผญ ์ž‘์„ฑ
  • .env.example ํ…œํ”Œ๋ฆฟ ์ œ๊ณต
  • Prettier, ESLint ์„ค์ • ๊ณต์œ 

โ†’ ํ˜‘์—… ์†๋„๐Ÿš€, ์œ ์ง€๋ณด์ˆ˜์„ฑ๐Ÿ“ˆ

๐Ÿš€ 2. ๋ฒ„์ „ ๊ด€๋ฆฌ (Git & GitHub) - ๊ธฐ์ดˆ โ†’ ์‹ค๋ฌด โ†’ ์‹ฌํ™” โ†’ ์‹ค์ „ ์˜ˆ์‹œ


โœ… 2-1. Git ๊ธฐ๋ณธ ๋ช…๋ น์–ด (๊ธฐ์ดˆ)

๋ช…๋ น์–ด ์—ญํ•  ์„ค๋ช…
git init ์ดˆ๊ธฐํ™” ํ˜„์žฌ ํด๋”๋ฅผ Git ๊ด€๋ฆฌ ํด๋”๋กœ ์„ค์ •
git add . ์Šคํ…Œ์ด์ง€ ์ถ”๊ฐ€ ์ˆ˜์ •๋œ ํŒŒ์ผ๋“ค ์ค€๋น„ (์Šค๋ƒ…์ƒท ์ „ ๋‹จ๊ณ„)
git commit -m "msg" ์ปค๋ฐ‹ ํ˜„์žฌ ์ƒํƒœ ์ €์žฅ (๋ณ€๊ฒฝ ํžˆ์Šคํ† ๋ฆฌ ์ƒ์„ฑ)
git log ์ปค๋ฐ‹ ๋‚ด์—ญ ๊ณผ๊ฑฐ ์ปค๋ฐ‹ ๊ธฐ๋ก ํ™•์ธ
git status ์ƒํƒœ ํ™•์ธ ๋ณ€๊ฒฝ๋œ ํŒŒ์ผ, ์Šคํ…Œ์ด์ง• ์—ฌ๋ถ€ ํ™•์ธ
git push/pull ์›๊ฒฉ ์—ฐ๋™ ์›๊ฒฉ ์ €์žฅ์†Œ์— ์—…๋กœ๋“œ/๋‹ค์šด๋กœ๋“œ

๐Ÿ“ข ๋น„์œ :


๐Ÿš€ 2-2. GitHub ์‹ค๋ฌด ํ˜‘์—… ๊ตฌ์กฐ

ํ•ญ๋ชฉ ์‹ค๋ฌด ์ „๋žต
Branch ์ „๋žต main(๋ฐฐํฌ), develop(ํ†ตํ•ฉ), feature/, hotfix/ ์‚ฌ์šฉ
PR (Pull Request) ๊ธฐ๋Šฅ ์™„๋ฃŒ โ†’ ๋ฆฌ๋ทฐ ์š”์ฒญ โ†’ ํŒ€์› ์Šน์ธ โ†’ Merge
.gitignore node_modules, .env, dist ๋“ฑ ๋ฌด์‹œ
README.md ์„ค์น˜ ๋ฐฉ๋ฒ•, ๋ธŒ๋žœ์น˜ ์ „๋žต, ํด๋” ๊ตฌ์กฐ ํ•„์ˆ˜ ์„ค๋ช…
Issue ๊ด€๋ฆฌ ์ž‘์—… ๋‹จ์œ„๋กœ ํ•  ์ผ ๊ด€๋ฆฌ (GitHub Issue ํ™œ์šฉ)

๐Ÿ’Ž 2-3. ์‹ฌํ™”: Rebase, ์ถฉ๋Œ ํ•ด๊ฒฐ, Stash

๐Ÿ”ฅ Git Rebase & Merge ์ฐจ์ด

๋น„๊ต Merge Rebase
์ปค๋ฐ‹ ํžˆ์Šคํ† ๋ฆฌ ๋ถ„๊ธฐ์  ์œ ์ง€, ๋ณต์žกํ•  ์ˆ˜ ์žˆ์Œ ์„ ํ˜•, ๊น”๋”, ๋ธŒ๋žœ์น˜ ์ค„๊ธฐ ํ•˜๋‚˜๋กœ
ํ˜‘์—…์‹œ ๋‹ค์ˆ˜๊ฐ€ ์ž‘์—…ํ•  ๋• Merge ์•ˆ์ „ Rebase โ†’ ์ปค๋ฐ‹ ๋ฎ์–ด์“ฐ๊ธฐ ์ฃผ์˜
์‚ฌ์šฉ์ฒ˜ ์ผ๋ฐ˜์  PR Merge ๋‚ด ๋กœ์ปฌ ๋ธŒ๋žœ์น˜ ์ •๋ฆฌํ•  ๋•Œ ์œ ์šฉ

โœ… Rebase ์‹ค์ „ ์˜ˆ์‹œ

# feature ๋ธŒ๋žœ์น˜๋กœ ์ด๋™
git checkout feature/login

# ์ตœ์‹  develop๊ณผ ๋‚ด feature๋ฅผ ๊น”๋”ํžˆ ํ•ฉ์น˜๊ธฐ
git rebase develop

# ์ถฉ๋Œ ๋ฐœ์ƒ ์‹œ:
# 1๏ธโƒฃ ์ถฉ๋Œ ํŒŒ์ผ ์ˆ˜์ •
git add .

# 2๏ธโƒฃ Rebase ์žฌ๊ฐœ
git rebase --continue

๐Ÿ’ก ์ถฉ๋Œ ํ•ด๊ฒฐ ์‹œ ํŒ

<<<<<<< HEAD
ํ˜„์žฌ ๋ธŒ๋žœ์น˜ ์ฝ”๋“œ
=======
๋‹ค๋ฅธ ๋ธŒ๋žœ์น˜ ์ฝ”๋“œ
>>>>>>> develop

โœ… โ†’ ๋‘˜ ์ค‘ ํ•„์š”ํ•œ ๋ถ€๋ถ„๋งŒ ๋‚จ๊ธฐ๊ณ  ์‚ญ์ œ!


๐Ÿงณ Stash ํ™œ์šฉ ์˜ˆ์‹œ

# ์ž„์‹œ๋กœ ํ˜„์žฌ ๋ณ€๊ฒฝ์‚ฌํ•ญ ์ €์žฅ (๋ธŒ๋žœ์น˜ ์ „ํ™˜ ์ „)
git stash

# ๋‹ค์‹œ ์ ์šฉ
git stash apply

๐ŸŒ 2-4. ์‹ค์ „ ์˜ˆ์‹œ (ํ˜‘์—… ์ƒํ™ฉ)

# 1๏ธโƒฃ ์ž‘์—… ์‹œ์ž‘: develop์—์„œ ์ตœ์‹ ํ™” --------------------------------------

git checkout develop        # develop ๋ธŒ๋žœ์น˜๋กœ ์ด๋™ (ํ˜„์žฌ ์ž‘์—… ์‹œ์ž‘์ )
git pull origin develop     # ์›๊ฒฉ(origin)์˜ develop ๋ธŒ๋žœ์น˜ ์ตœ์‹  ๋‚ด์šฉ ๊ฐ€์ ธ์™€์„œ ๋กœ์ปฌ์— ๋ฐ˜์˜
# โ†’ ํ•ญ์ƒ ์ž‘์—… ์ „ ์ตœ์‹  ์ฝ”๋“œ๋กœ ๋งž์ถฐ์ค˜์•ผ ์ถฉ๋Œ ์ตœ์†Œํ™”!

# 2๏ธโƒฃ feature ๋ธŒ๋žœ์น˜ ์ƒ์„ฑ ---------------------------------------------

git checkout -b feature/signup
# feature/signup์ด๋ผ๋Š” ์ƒˆ๋กœ์šด ๋ธŒ๋žœ์น˜ ์ƒ์„ฑ + ์ž๋™์œผ๋กœ ๊ทธ ๋ธŒ๋žœ์น˜๋กœ ์ด๋™
# ๋ธŒ๋žœ์น˜ ์ด๋ฆ„ ๊ทœ์น™: ๋ณดํ†ต feature/๊ธฐ๋Šฅ๋ช… ํ˜•ํƒœ๋กœ ์‚ฌ์šฉ (๊ฐ€๋…์„ฑ & ๊ด€๋ฆฌ์šฉ์ด)

# 3๏ธโƒฃ ์ž‘์—… ํ›„ ์ปค๋ฐ‹ -----------------------------------------------------

git add .
# ๋ณ€๊ฒฝ๋œ ๋ชจ๋“  ํŒŒ์ผ ์Šคํ…Œ์ด์ง• ์˜์—ญ์— ์ถ”๊ฐ€ (์ปค๋ฐ‹ ์ค€๋น„)

git commit -m "Add signup page"
# ๋ณ€๊ฒฝ ๋‚ด์šฉ์„ ์ปค๋ฐ‹ โ†’ ๋ฉ”์‹œ์ง€์—๋Š” **๋ฌด์—‡์„ ํ–ˆ๋Š”์ง€ ๋ช…ํ™•ํžˆ** ์ž‘์„ฑ ("Signup ํŽ˜์ด์ง€ ์ถ”๊ฐ€")

# 4๏ธโƒฃ ์›๊ฒฉ feature ๋ธŒ๋žœ์น˜ ์˜ฌ๋ฆฌ๊ธฐ --------------------------------------

git push origin feature/signup
# ๋ฐฉ๊ธˆ ๋งŒ๋“  feature/signup ๋ธŒ๋žœ์น˜๋ฅผ ์›๊ฒฉ(origin) ์ €์žฅ์†Œ๋กœ push
# โ†’ ํŒ€์›๋“ค๊ณผ ํ˜‘์—…์„ ์œ„ํ•ด ์›๊ฒฉ ๋ธŒ๋žœ์น˜๋กœ ์˜ฌ๋ฆฌ๋Š” ๋‹จ๊ณ„

# 5๏ธโƒฃ PR (Pull Request) โ†’ ๋ฆฌ๋ทฐ ์š”์ฒญ & ๋จธ์ง€ ----------------------------

# GitHub, GitLab, Bitbucket ๋“ฑ์—์„œ
# feature/signup ๋ธŒ๋žœ์น˜๋ฅผ develop ๋ธŒ๋žœ์น˜๋กœ ๋ณ‘ํ•ฉ(Merge) ์š”์ฒญ (Pull Request)
# โ†’ ํŒ€์›์—๊ฒŒ ์ฝ”๋“œ ๋ฆฌ๋ทฐ ์š”์ฒญ, ์Šน์ธ๋˜๋ฉด develop์— ๋จธ์ง€!

๐ŸŽฏ 2-5. ๊ธฐ์ˆ ๋ฉด์ ‘ ๋Œ€๋น„ ์งˆ๋ฌธ

์งˆ๋ฌธ ์‹ฌํ™” ๋‹ต๋ณ€
ํ˜‘์—… ์‹œ ๋ธŒ๋žœ์น˜ ์ „๋žต? main, develop, feature/, hotfix/ ๋ช…ํ™•ํžˆ ๊ด€๋ฆฌ + PR ํ”„๋กœ์„ธ์Šค
Merge์™€ Rebase ์ฐจ์ด? Merge๋Š” ๋ถ„๊ธฐ์  ์œ ์ง€, Rebase๋Š” ๊น”๋”ํ•œ ํžˆ์Šคํ† ๋ฆฌ โ†’ ํ˜‘์—… ๋• Merge ์•ˆ์ „
.gitignore ์—ญํ• ? ๋นŒ๋“œ ๊ฒฐ๊ณผ๋ฌผ, ํ™˜๊ฒฝ ๋ณ€์ˆ˜, ๊ฐœ์ธ ์„ค์ • ํŒŒ์ผ ๋ฌด์กฐ๊ฑด ์ œ์™ธ โ†’ ์ถฉ๋Œ ๋ฐฉ์ง€
Stash ์–ธ์ œ ์‚ฌ์šฉ? ๊ธด๊ธ‰ ๋ธŒ๋žœ์น˜ ์ „ํ™˜, ์ž„์‹œ ๋ณ€๊ฒฝ ์ €์žฅ ํ›„ ๋‹ค์‹œ ์ ์šฉํ•  ๋•Œ ์œ ์šฉ

๐Ÿ“Œ ์‹ค๋ฌด ํฌ์ธํŠธ

์ƒํ™ฉ ์‹ค๋ฌด ํŒ
ํ˜‘์—… ์‹œ ์ถฉ๋Œ ๋นˆ๋ฐœ PR โ†’ ๋ฆฌ๋ทฐ โ†’ Merge ํ™•์‹คํžˆ ๊ด€๋ฆฌ + ์ถฉ๋Œ ๋• ์ฃผ์„ ํ™œ์šฉ
๋ธŒ๋žœ์น˜ ๊ด€๋ฆฌ Issue ๋ฒˆํ˜ธ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ธŒ๋žœ์น˜ ๋„ค์ด๋ฐ โ†’ ์ถ”์ ์„ฑ โ†‘
์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€ ๊ทœ์น™ feat:, fix:, chore: Prefix ์‚ฌ์šฉ์œผ๋กœ ๊ธฐ๋ก ๊ด€๋ฆฌ


๐ŸŒŸ ์ •๋ฆฌ ์š”์•ฝ

ํ•ญ๋ชฉ ์‹ค๋ฌด ์Šคํ‚ฌ ๋ฉด์ ‘ ์‹ฌํ™”
Branch ์ „๋žต main/develop/feature ๊ด€๋ฆฌ ๋ธŒ๋žœ์น˜ ์ถฉ๋Œ ์‹œ ํ•ด๊ฒฐ ์ „๋žต
Rebase vs Merge ์ƒํ™ฉ ๋งž๊ฒŒ ๊ตฌ๋ถ„ ํžˆ์Šคํ† ๋ฆฌ ๊ด€๋ฆฌ ์›๋ฆฌ, ํ˜‘์—… ์‹œ ์ฃผ์˜
PR ํ”„๋กœ์„ธ์Šค ๋ฆฌ๋ทฐ & ๋จธ์ง€ ํ•„์ˆ˜ ๋ฆฌ๋ทฐ ํ”„๋กœ์„ธ์Šค ์ค‘์š”์„ฑ
.gitignore ๋ถˆํ•„์š” ํŒŒ์ผ ์ œ์™ธ ์ถฉ๋Œ ๋ฐฉ์ง€ & ๋ณด์•ˆ
Stash ์ž„์‹œ ์ €์žฅ ์Šคํ‚ฌ ๊ธด๊ธ‰ ๋Œ€์‘ ์ „๋žต

โšก 3. ์›น ์„ฑ๋Šฅ ์ตœ์ ํ™” - ๊ธฐ์ดˆ โ†’ ์‹ค๋ฌด โ†’ ์‹ฌํ™” โ†’ ์‹ค์ „ ์˜ˆ์‹œ


๐ŸŽ๏ธ 3-1. ๊ธฐ๋ณธ ์ตœ์ ํ™” ๋ฐฉ๋ฒ• (๊ธฐ์ดˆ)

๊ธฐ๋ฒ• ์„ค๋ช…
Minify HTML, CSS, JS ๊ณต๋ฐฑ, ์ฃผ์„ ์ œ๊ฑฐ (ํŒŒ์ผ ์‚ฌ์ด์ฆˆโ†“)
ํŒŒ์ผ ๋ณ‘ํ•ฉ JS/CSS ์—ฌ๋Ÿฌ ํŒŒ์ผ โ†’ 1~2๊ฐœ๋กœ ํ•ฉ์ณ HTTP ์š”์ฒญ ์ˆ˜ โ†“
Lazy Loading ์ด๋ฏธ์ง€, iframe ์Šคํฌ๋กค ์‹œ์ ์— ๋กœ๋”ฉ
Gzip/Brotli ์„œ๋ฒ„์—์„œ ํŒŒ์ผ ์••์ถ•ํ•ด ์ „์†ก (๋Œ€์—ญํญ ์ ˆ์•ฝ)

โœ… ์‹ค์ „ ์ ์šฉ ์˜ˆ์‹œ:

<!-- HTML/CSS/JS Minify: ๋ถˆํ•„์š”ํ•œ ๊ณต๋ฐฑ, ์ค„๋ฐ”๊ฟˆ, ์ฃผ์„ ๋“ฑ์„ ์ œ๊ฑฐํ•ด ํŒŒ์ผ ์šฉ๋Ÿ‰ โ†“, ๋กœ๋”ฉ ์†๋„ โ†‘ -->

<!-- ์••์ถ•(minify)๋œ CSS ํŒŒ์ผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ -->
<link rel="stylesheet" href="style.min.css">

<!-- ์••์ถ•(minify)๋œ JS ํŒŒ์ผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ -->
<script src="main.min.js"></script>

<!-- ์ด๋ฏธ์ง€ Lazy Loading: ์‚ฌ์šฉ์ž๊ฐ€ ํ•ด๋‹น ์ด๋ฏธ์ง€๊ฐ€ ๋ณด์ผ ๋•Œ๋งŒ ๋กœ๋”ฉ (์ดˆ๊ธฐ ๋กœ๋”ฉ ์†๋„ โ†‘, ์„ฑ๋Šฅ ์ตœ์ ํ™”) -->
<img src="product.jpg" loading="lazy" alt="Product Image">
<!-- alt ์†์„ฑ: ์ด๋ฏธ์ง€ ๋Œ€์ฒด ํ…์ŠคํŠธ (์ ‘๊ทผ์„ฑ, SEO ํ–ฅ์ƒ) -->

๐Ÿ“ข ๋น„์œ :


๐Ÿš€ 3-2. ์‹ค๋ฌด ์ตœ์ ํ™” ์Šคํ‚ฌ

๊ธฐ๋ฒ• ๋„๊ตฌ/๋ฐฉ๋ฒ•
Tree Shaking Webpack, ES6 ๋ชจ๋“ˆ โ†’ ์•ˆ์“ฐ๋Š” JS ์ œ๊ฑฐ
Code Splitting Dynamic Import๋กœ ํŽ˜์ด์ง€๋ณ„ JS ๋ถ„๋ฆฌ
Critical CSS ์œ„์ชฝ CSS๋งŒ ๋จผ์ € ๋กœ๋”ฉ, ๋‚˜๋จธ์ง€ ์ง€์—ฐ ์ฒ˜๋ฆฌ
CDN ํ™œ์šฉ Cloudflare, AWS CloudFront๋กœ ์ •์  ์ž์› ์ „์„ธ๊ณ„ ๋ฐฐํฌ

โœ… Tree Shaking ์‹ค์ „ ์˜ˆ์‹œ

// utils.js

// add ํ•จ์ˆ˜: ๋‘ ์ˆ˜๋ฅผ ๋”ํ•ด์„œ ๋ฐ˜ํ™˜
export const add = (a, b) => a + b;

// subtract ํ•จ์ˆ˜: ๋‘ ์ˆ˜๋ฅผ ๋นผ์„œ ๋ฐ˜ํ™˜
export const subtract = (a, b) => a - b;

// ๋‘ ํ•จ์ˆ˜ ๋ชจ๋‘ ES6 ๋ชจ๋“ˆ ๋ฐฉ์‹์œผ๋กœ export (๊ฐœ๋ณ„ ๋‚ด๋ณด๋‚ด๊ธฐ)
// ์ค‘์š”ํ•œ ํฌ์ธํŠธ: ES6 ๋ชจ๋“ˆ์€ ์ •์  ๊ตฌ์กฐ โ†’ Webpack์ด ์‚ฌ์šฉ ์—ฌ๋ถ€ ์‰ฝ๊ฒŒ ๋ถ„์„ ๊ฐ€๋Šฅ (Tree Shaking ๊ฐ€๋Šฅ)

โœ… Code Splitting ์‹ค์ „ ์˜ˆ์‹œ (React ๊ธฐ์ค€)

// routes.js
// React์—์„œ lazy loading ๊ธฐ๋Šฅ๊ณผ Suspense ์ปดํฌ๋„ŒํŠธ ๊ฐ€์ ธ์˜ค๊ธฐ
import React, { lazy, Suspense } from 'react';

// ---------------------------
// ์ปดํฌ๋„ŒํŠธ "์ง€์—ฐ ๋กœ๋”ฉ(lazy loading)" ์„ค์ •
// Home ์ปดํฌ๋„ŒํŠธ: ํ•„์š”ํ•  ๋•Œ ๋น„๋™๊ธฐ๋กœ ๋ถˆ๋Ÿฌ์˜ด โ†’ ๋ฒˆ๋“ค ์ดˆ๊ธฐ ํฌ๊ธฐ โ†“
const Home = lazy(() => import('./pages/Home'));

// About ์ปดํฌ๋„ŒํŠธ: ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํ•„์š”ํ•  ๋•Œ๋งŒ ๋น„๋™๊ธฐ๋กœ ๋ถˆ๋Ÿฌ์˜ด
const About = lazy(() => import('./pages/About'));

// ---------------------------
// ๋ฉ”์ธ App ์ปดํฌ๋„ŒํŠธ ์ •์˜
function App() {
  return (
    // Suspense: lazy๋กœ ๋กœ๋”ฉ ์ค‘์ผ ๋•Œ ๋ณด์—ฌ์ค„ fallback UI ์„ค์ •
    <Suspense fallback={<div>Loading...</div>}>
      {/* Home ์ปดํฌ๋„ŒํŠธ๋Š” ์‹ค์ œ๋กœ ํ•„์š”ํ•  ๋•Œ ๋ถˆ๋Ÿฌ์™€ ๋ Œ๋”๋ง๋จ */}
      <Home />

      {/* About ์ปดํฌ๋„ŒํŠธ๋„ ํ•„์š” ์‹œ ๋น„๋™๊ธฐ ๋กœ๋”ฉ๋จ */}
      <About />
    </Suspense>
  );
}
// ---------------------------
// ๊ฒฐ๊ณผ:
// - Home & About ์ปดํฌ๋„ŒํŠธ๋Š” ์ดˆ๊ธฐ ๋ฒˆ๋“ค์— ํฌํ•จ๋˜์ง€ ์•Š๊ณ , ํ•„์š”ํ•  ๋•Œ ๊ฐœ๋ณ„์ ์œผ๋กœ ๋กœ๋“œ
// - ๋กœ๋”ฉ ์ค‘์—” "Loading..." ๋ฉ”์‹œ์ง€๊ฐ€ ์ž ๊น ํ‘œ์‹œ
// - **React์˜ ์ฝ”๋“œ ์Šคํ”Œ๋ฆฌํŒ… + ์„ฑ๋Šฅ ์ตœ์ ํ™” ํ•ต์‹ฌ ํŒจํ„ด!**

โ†’ ํ•„์š”ํ•œ ํŽ˜์ด์ง€์—์„œ๋งŒ JS ๋ถˆ๋Ÿฌ์˜ด โ†’ ์ดˆ๊ธฐ ๋กœ๋”ฉ ์†๋„โ†‘


โœ… Critical CSS ์ ์šฉ

<style>
  /* ๐ŸŸข Critical CSS: ์ฒซ ํ™”๋ฉด์—์„œ ๋ฐ”๋กœ ๋ณด์—ฌ์•ผ ํ•˜๋Š” ํ•ต์‹ฌ ์Šคํƒ€์ผ๋งŒ ์ธ๋ผ์ธ์œผ๋กœ ๋„ฃ๊ธฐ */
  header {
    background: #fff;       /* ํ—ค๋” ๋ฐฐ๊ฒฝ ํฐ์ƒ‰ */
    position: fixed;        /* ์Šคํฌ๋กคํ•ด๋„ ๊ณ ์ • */
    top: 0;                 /* ํ™”๋ฉด ๋งจ ์œ„์— ์œ„์น˜ */
  }
  /* โ†’ Critical CSS๋Š” ๋ Œ๋”๋ง ์ง€์—ฐ ์—†์ด ๋ฐ”๋กœ ์ ์šฉ๋˜๋ฏ€๋กœ LCP(์ตœ๋Œ€ ์ฝ˜ํ…์ธ  ํ‘œ์‹œ ์‹œ๊ฐ„) ๊ฐœ์„ ! */
</style>

<!-- ๐ŸŒ ์™ธ๋ถ€ CSS ๋น„๋™๊ธฐ ๋กœ๋”ฉ -->
<link rel="stylesheet" href="style.css" media="print" onload="this.media='all'">
<!-- 
1๏ธโƒฃ media="print": ์ดˆ๊ธฐ์—” print ์ „์šฉ์œผ๋กœ ์„ค์ • โ†’ ํ™”๋ฉด ๋ Œ๋”๋ง์— ์˜ํ–ฅ X
2๏ธโƒฃ onload="this.media='all'": CSS ํŒŒ์ผ์ด ๋‹ค ๋กœ๋“œ๋œ ํ›„์— media๋ฅผ 'all'๋กœ ๋ฐ”๊ฟ” ์ ์šฉ
3๏ธโƒฃ ๊ฒฐ๊ณผ: ์™ธ๋ถ€ CSS๊ฐ€ ๋น„๋™๊ธฐ๋กœ ๋กœ๋“œ โ†’ ํŽ˜์ด์ง€ ๋ Œ๋”๋ง ๋ธ”๋กœํ‚น ๋ฐฉ์ง€ โ†’ ์„ฑ๋Šฅ ์ตœ์ ํ™” ๐Ÿš€
-->

๐Ÿ’Ž 3-3. ์‹ฌํ™”: Critical Rendering Path ์ตœ์ ํ™”

๋‹จ๊ณ„ ์„ค๋ช…
HTML ํŒŒ์‹ฑ DOM Tree ์ƒ์„ฑ ๐Ÿ“„
CSSOM ํŒŒ์‹ฑ CSS ํŒŒ์‹ฑ ํ›„ CSSOM Tree ์ƒ์„ฑ ๐ŸŽจ
JS ํŒŒ์‹ฑ JS๋Š” Blocking โ†’ defer/async ํ•„์ˆ˜
Render & Paint ๋ Œ๋”๋ง ์™„๋ฃŒ โ†’ ํ™”๋ฉด ํ‘œ์‹œ

โœ… JS ๋น„๋™๊ธฐ ๋กœ๋”ฉ ์˜ˆ์‹œ

<!-- ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋˜๋Š” ๊ณตํ†ต ์Šคํฌ๋ฆฝํŠธ (๋ฒค๋” ์Šคํฌ๋ฆฝํŠธ) ๋ถˆ๋Ÿฌ์˜ค๊ธฐ -->
<script src="vendor.js" defer></script>
<!-- 
  โœ… defer ์†์„ฑ: HTML ํŒŒ์‹ฑ์ด ๋๋‚œ ํ›„์— ์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰
  โœ… HTML ๋ฌธ์„œ ๊ตฌ์กฐ๊ฐ€ ๋ชจ๋‘ ์ค€๋น„๋œ ํ›„ ์‹คํ–‰ โ†’ DOM ์ฐจ๋‹จ X โ†’ ํŽ˜์ด์ง€ ๋กœ๋”ฉ ์†๋„ ๊ฐœ์„ 
-->

<!-- ๋ฉ”์ธ ์Šคํฌ๋ฆฝํŠธ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ -->
<script src="main.js" defer></script>
<!-- 
  โœ… main.js: ํŽ˜์ด์ง€ ๊ธฐ๋Šฅ ๋‹ด๋‹นํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ
  โœ… defer๋กœ ์ธํ•ด vendor.js โ†’ main.js ์ˆœ์„œ **๋ณด์žฅ**
  โœ… ๋‘˜ ๋‹ค defer โ†’ HTML ํŒŒ์‹ฑ๊ณผ ๋ณ‘๋ ฌ๋กœ ๋‹ค์šด๋กœ๋“œ, ํŒŒ์‹ฑ ๋๋‚œ ํ›„ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰
-->

๐ŸŒ 3-4. ์‹ค๋ฌด ์‹ค์ „ ์ตœ์ ํ™” ๋ ˆ์‹œํ”ผ

๐Ÿ› ๏ธ Webpack + ์‹ค์ „ ์„ค์ • ์˜ˆ์‹œ:

// webpack.config.js
module.exports = {
  // ๐Ÿ”ฅ ํ”„๋กœ๋•์…˜ ๋ชจ๋“œ ์„ค์ •
  mode: 'production', 
  // โ†’ ์ž๋™์œผ๋กœ JavaScript, CSS ๋“ฑ ํŒŒ์ผ์„ **Minify(์••์ถ•)** ํ•ด์คŒ
  // โ†’ ์ฝ˜์†” ๋กœ๊ทธ ์ œ๊ฑฐ, ์ตœ์ ํ™” ์ ์šฉ (ํŒŒ์ผ ํฌ๊ธฐ โ†“, ์„ฑ๋Šฅ โ†‘)

  optimization: {
    // โœ… ์ฝ”๋“œ ์Šคํ”Œ๋ฆฌํŒ… ์„ค์ •
    splitChunks: { chunks: 'all' }, 
    /* 
      โ†’ ์—ฌ๋Ÿฌ JS ํŒŒ์ผ ๊ฐ„์— ๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ์ฝ”๋“œ๋ฅผ ๋ณ„๋„์˜ ํŒŒ์ผ๋กœ ๋ถ„๋ฆฌ
      โ†’ ๊ฒฐ๊ณผ:
         - ์ค‘๋ณต ์ฝ”๋“œ ์ œ๊ฑฐ
         - ์บ์‹ฑ ํšจ์œจ โ†‘
         - ์ดˆ๊ธฐ ๋กœ๋”ฉ ์†๋„ ๊ฐœ์„ 
    */
    // โœ… Tree Shaking ํ™œ์„ฑํ™”
    usedExports: true 
    /* 
      โ†’ ES6 ๋ชจ๋“ˆ์—์„œ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” export ์ฝ”๋“œ๋ฅผ ์ž๋™์œผ๋กœ ์ œ๊ฑฐ
      โ†’ ๊ฒฐ๊ณผ:
         - ๋ถˆํ•„์š”ํ•œ ์ฝ”๋“œ ์ค„์ด๊ณ  ๋ฒˆ๋“ค ํฌ๊ธฐ โ†“
         - **import๋œ ์ฝ”๋“œ ์ค‘ ์‹ค์ œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋งŒ ๋‚จ๊น€**
    */
  }
};

๐ŸŒ CDN ์„ค์ • ๊ฐ„๋‹จ ์˜ˆ์‹œ:


๐ŸŽฏ 3-5. ๊ธฐ์ˆ ๋ฉด์ ‘ ๋Œ€๋น„ ์งˆ๋ฌธ

์งˆ๋ฌธ ์‹ฌํ™” ๋‹ต๋ณ€
์›น ์„ฑ๋Šฅ ์ตœ์ ํ™” ๋ฐฉ๋ฒ•? Minify, Lazy Loading, Tree Shaking, Code Splitting, Critical CSS, CDN
Critical Rendering Path๋ž€? DOMโ†’CSSOMโ†’JS ํŒŒ์‹ฑโ†’Paint, ๋ถˆํ•„์š”ํ•œ Blocking ์ตœ์†Œํ™”
Tree Shaking ์›๋ฆฌ? ES6 ๋ชจ๋“ˆ export ๊ธฐ์ค€, ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ํ•จ์ˆ˜/๋ณ€์ˆ˜ ์ œ๊ฑฐ
Code Splitting ์–ธ์ œ ํ•„์š”? ์ดˆ๊ธฐ ๋กœ๋”ฉ ์ตœ์ ํ™”, ํŽ˜์ด์ง€๋ณ„ ๊ธฐ๋Šฅ ๋ณ„๋„ ๋กœ๋”ฉ

๐Ÿ“Œ ์‹ค๋ฌด ํฌ์ธํŠธ ์ •๋ฆฌ

์ƒํ™ฉ ์‹ค์ „ ์ ์šฉ
ํŽ˜์ด์ง€ ์ดˆ๊ธฐ ๋กœ๋”ฉ ๋А๋ฆผ Code Splitting + Critical CSS + Lazy Load
JS ๋ฒˆ๋“ค ์šฉ๋Ÿ‰ โ†‘ Tree Shaking + Minify
์ „์„ธ๊ณ„ ์œ ์ € CDN ํ™œ์šฉ ํ•„์ˆ˜
๋ Œ๋”๋ง ์ง€์—ฐ defer, async + ์ด๋ฏธ์ง€ ์ตœ์ ํ™”


๐Ÿš€ ์ •๋ฆฌ ์š”์•ฝ

๐ŸŒŸ ์ฃผ์ œ ์‹ค๋ฌด ์Šคํ‚ฌ ๋ฉด์ ‘ ์‹ฌํ™”
Minify HTML/CSS/JS ๊ณต๋ฐฑ ์ฃผ์„ ์ œ๊ฑฐ ๋นŒ๋“œ ์„ค์ •์— ํฌํ•จ ์—ฌ๋ถ€
Lazy Load ์ด๋ฏธ์ง€ ์ง€์—ฐ ๋กœ๋”ฉ loading=โ€lazyโ€ ์ ์šฉ ์กฐ๊ฑด
Tree Shaking Webpack, ES6 ๋ชจ๋“ˆ ๊ธฐ๋ฐ˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” export ์ œ๊ฑฐ ์›๋ฆฌ
Code Splitting Dynamic Import ํŽ˜์ด์ง€๋ณ„ JS ๋‚˜๋ˆ„๊ธฐ
Critical CSS ์œ„์ชฝ CSS ๋จผ์ € ๋ Œ๋” ์Šคํƒ€์ผ ์ถฉ๋Œ ์ตœ์†Œํ™”
CDN ์ •์  ์ž์› ์ „์„ธ๊ณ„ ๋ฐฐํฌ ์บ์‹œ ์ „๋žต, DNS ์„ค์ •

๐Ÿ”’ 4. ์›น ๋ณด์•ˆ ๊ฐœ๋…


๐Ÿ›ก๏ธ 4-1. XSS (Cross-Site Scripting)

๐Ÿšจ XSS๋ž€?


๐ŸŽฏ XSS ๋ฐœ์ƒ ์›์ธ

์›์ธ ์„ค๋ช…
๐Ÿ”‘ ์ž…๋ ฅ๊ฐ’ ๊ฒ€์ฆ ๋ฏธํก <script> ๊ฐ™์€ ํƒœ๊ทธ๊ฐ€ ๊ทธ๋Œ€๋กœ ๋ฐ˜์˜๋จ
๐Ÿ“ innerHTML ๋“ฑ ์ง์ ‘ DOM ์‚ฝ์ž… ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ ๊ทธ๋Œ€๋กœ DOM ์‚ฝ์ž… โ†’ ์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰
๐Ÿ”„ ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ API, ๋Œ“๊ธ€, ๊ฒŒ์‹œํŒ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ๊ฒ€์ฆ ๋ถ€์žฌ

โœ… XSS ๋ฐฉ์–ด๋ฒ•

๋ฐฉ๋ฒ• ์„ค๋ช…
โœ‚๏ธ ์ž…๋ ฅ๊ฐ’ Escape ์ฒ˜๋ฆฌ <, >, ', " โ†’ &lt;, &gt; ๋“ฑ์œผ๋กœ ๋ณ€ํ™˜ํ•ด ๋ฌด๋ ฅํ™”
๐Ÿ” CSP(Content Security Policy) ์‹ ๋ขฐ๋œ ์ถœ์ฒ˜๋งŒ ์Šคํฌ๋ฆฝํŠธ ํ—ˆ์šฉ (ex. ์™ธ๋ถ€ ์Šคํฌ๋ฆฝํŠธ ์ฐจ๋‹จ)
๐Ÿงผ DOM ์‚ฝ์ž… ์‹œ textContent ์‚ฌ์šฉ innerHTML ์‚ฌ์šฉ ์ž์ œ โ†’ textContent, createTextNode ํ™œ์šฉ
๐Ÿšซ HttpOnly ์ฟ ํ‚ค ์‚ฌ์šฉ ์„ธ์…˜ ์ฟ ํ‚ค๋ฅผ JavaScript๋กœ ์ ‘๊ทผ ๋ถˆ๊ฐ€ํ•˜๊ฒŒ ์„ค์ •
โœ… ์ž…๋ ฅ๊ฐ’ Validation & Length ์ œํ•œ ์ž…๋ ฅ ๊ฐ€๋Šฅ ๊ธธ์ด์™€ ํฌ๋งท์„ ์—„๊ฒฉํžˆ ์ œํ•œ

๐Ÿ’ป ์‹ค์ „ ๋ฐฉ์–ด ์˜ˆ์‹œ (์ฃผ์„ ํฌํ•จ)

// โŒ ์ทจ์•ฝํ•œ ์ฝ”๋“œ: ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๊ทธ๋Œ€๋กœ ์‹คํ–‰๋  ์ˆ˜ ์žˆ์Œ
div.innerHTML = userInput;

// โœ… ์•ˆ์ „ํ•œ ๋ฐฉ๋ฒ• 1: textContent ์‚ฌ์šฉ
div.textContent = userInput; // ์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰ ๋ถˆ๊ฐ€, ๋‹จ์ˆœ ํ…์ŠคํŠธ ์ฒ˜๋ฆฌ

// โœ… ์•ˆ์ „ํ•œ ๋ฐฉ๋ฒ• 2: Escape ์ฒ˜๋ฆฌ ํ•จ์ˆ˜ ์‚ฌ์šฉ
function escapeHTML(str) {
  return str
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#039;');
}
div.innerHTML = escapeHTML(userInput);
<!-- โœ… CSP ์ ์šฉ: ์™ธ๋ถ€ ์Šคํฌ๋ฆฝํŠธ ์ฐจ๋‹จ, ์ธ๋ผ์ธ ์Šคํฌ๋ฆฝํŠธ ์ฐจ๋‹จ -->
<meta http-equiv="Content-Security-Policy" content="
  default-src 'self';
  script-src 'self';
  object-src 'none';
  frame-ancestors 'none';">

๐Ÿ“ข ๋น„์œ :



๐Ÿ” 4-2. CSRF (Cross-Site Request Forgery)

๐Ÿšจ CSRF๋ž€?


๐ŸŽฏ CSRF ๋ฐœ์ƒ ์›์ธ

์›์ธ ์„ค๋ช…
๐Ÿช ์ž๋™์œผ๋กœ ์ „์†ก๋˜๋Š” ์„ธ์…˜ ์ฟ ํ‚ค ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์š”์ฒญ๋งˆ๋‹ค ์ฟ ํ‚ค ์ž๋™ ์ฒจ๋ถ€
๐ŸŽฏ ์š”์ฒญ ์ถœ์ฒ˜ ๊ฒ€์ฆ ๋ฏธ๋น„ ์š”์ฒญ์ด ์–ด๋””์„œ ์™”๋Š”์ง€ ํ™•์ธ ์•ˆ ํ•จ

โœ… CSRF ๋ฐฉ์–ด๋ฒ•

๋ฐฉ๋ฒ• ์„ค๋ช…
๐Ÿท๏ธ CSRF Token ๋ฐœ๊ธ‰ ์š”์ฒญ๋งˆ๋‹ค ๊ณ ์œ  ํ† ํฐ ํฌํ•จ โ†’ ์„œ๋ฒ„์—์„œ ๊ฒ€์ฆ
๐ŸŒ SameSite ์ฟ ํ‚ค ์„ค์ • ์™ธ๋ถ€ ์‚ฌ์ดํŠธ ์š”์ฒญ ์‹œ ์ฟ ํ‚ค ์ „์†ก ์ œํ•œ
๐Ÿ” Referer/Origin ๊ฒ€์ฆ ์š”์ฒญ ์ถœ์ฒ˜๊ฐ€ ์ •์ƒ ๋„๋ฉ”์ธ์ธ์ง€ ํ™•์ธ
๐Ÿ“ฎ POST ์š”์ฒญ๋งŒ ํ—ˆ์šฉ ๋ฏผ๊ฐํ•œ ์ž‘์—…์€ GET ๊ธˆ์ง€, POST/PUT๋งŒ ์‚ฌ์šฉ

๐Ÿ’ป ์‹ค์ „ ๋ฐฉ์–ด ์˜ˆ์‹œ (์ฃผ์„ ํฌํ•จ)

<!-- โœ… CSRF Token ํฌํ•จ -->
<form action="/updateProfile" method="POST">
  <input type="hidden" name="csrfToken" value="secureRandomToken123">
  <button type="submit">Update</button>
</form>

# โœ… SameSite + Secure + HttpOnly ์„ค์ •
Set-Cookie: sessionId=abc123;
             SameSite=Strict;  /* ์™ธ๋ถ€ ์‚ฌ์ดํŠธ์—์„œ ์ฟ ํ‚ค ์ „์†ก ๋ถˆ๊ฐ€ */
             Secure;           /* HTTPS์—์„œ๋งŒ */
             HttpOnly;         /* JS์—์„œ ์ ‘๊ทผ ๋ถˆ๊ฐ€ */

๐Ÿ“ข ๋น„์œ :



๐Ÿ”’ 4-3. HTTPS ์ ์šฉ (SSL/TLS)

๐Ÿšจ HTTPS๋ž€?


โœ… HTTPS ํšจ๊ณผ

ํšจ๊ณผ ์„ค๋ช…
๐Ÿ”’ ๋ฐ์ดํ„ฐ ์•”ํ˜ธํ™” ํ†ต์‹  ๋‚ด์šฉ ๋…ธ์ถœ ๋ฐฉ์ง€
๐Ÿข ์„œ๋ฒ„ ์‹ ์› ์ธ์ฆ ํ”ผ์‹ฑ, ์ค‘๊ฐ„์ž ๊ณต๊ฒฉ ๋ฐฉ์ง€
๐Ÿ“ˆ SEO & ๋ธŒ๋ผ์šฐ์ € ๊ฒฝ๊ณ  ์ œ๊ฑฐ HTTPS ๋ฏธ์ ์šฉ ์‹œ ๋ธŒ๋ผ์šฐ์ € ๊ฒฝ๊ณ , ์‹ ๋ขฐ๋„โ†“

๐Ÿ’ป ์‹ค์ „ ์ ์šฉ ์˜ˆ์‹œ (์ฃผ์„ ํฌํ•จ)

# โœ… Nginx HTTPS ์„ค์ • (Let's Encrypt ์ธ์ฆ์„œ)
server {
  listen 443 ssl;

  # SSL ์ธ์ฆ์„œ ์œ„์น˜
  ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem;

  # HSTS: HTTPS ๊ฐ•์ œ
  add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}

๐Ÿ“ข ๋น„์œ :



๐Ÿช 4-4. ์ฟ ํ‚ค ๋ณด์•ˆ ์†์„ฑ ์‹ฌํ™”

์†์„ฑ ์—ญํ•  ์‹ฌํ™” ์„ค๋ช…
๐Ÿ”’ Secure HTTPS ํ™˜๊ฒฝ์—์„œ๋งŒ ์ฟ ํ‚ค ์ „์†ก ์ค‘๊ฐ„์ž ๊ณต๊ฒฉ ์‹œ ๋…ธ์ถœ ๋ฐฉ์ง€
๐Ÿ›‘ HttpOnly JS ์ ‘๊ทผ ๋ถˆ๊ฐ€ โ†’ XSS ๋ฐฉ์–ด document.cookie ์ฐจ๋‹จ
๐ŸŒ SameSite ๋‹ค๋ฅธ ์‚ฌ์ดํŠธ ์š”์ฒญ ์‹œ ์ฟ ํ‚ค ์ œํ•œ Strict, Lax, None ์„ธ๋ถ€ ๊ตฌ๋ถ„ ํ•„์š”

๐Ÿ’ป ์‹ค์ „ ์˜ˆ์‹œ (์ฃผ์„ ํฌํ•จ)

Set-Cookie: sessionId=abc123;
             Secure;          /* HTTPS ํ•„์ˆ˜ */
             HttpOnly;        /* JS ์ ‘๊ทผ ๋ถˆ๊ฐ€ */
             SameSite=Strict; /* ๋‹ค๋ฅธ ์‚ฌ์ดํŠธ์—์„œ ์ „์†ก ๋ถˆ๊ฐ€ */

๐Ÿ“ข SameSite ์˜ต์…˜ ์ •๋ฆฌ:

์˜ต์…˜ ํŠน์ง• ์‚ฌ์šฉ ์˜ˆ
Strict ์ฒ ์ € ์ฐจ๋‹จ (์™ธ๋ถ€ ์š”์ฒญ ์ฟ ํ‚ค ๋ฌด์กฐ๊ฑด X) ๋กœ๊ทธ์ธ, ๊ฒฐ์ œ ๋“ฑ ๋ฏผ๊ฐ ์ž‘์—…
Lax GET์€ ํ—ˆ์šฉ, POST๋Š” ์ฐจ๋‹จ ๋ธ”๋กœ๊ทธ ๋Œ“๊ธ€ ๋“ฑ
None ์ œ์•ฝ ์—†์Œ, Secure ํ•„์ˆ˜ ์ œ3์ž ์„œ๋น„์Šค ํ•„์š”์‹œ (ex. OAuth)


๐Ÿ›ก๏ธ 4-5. ๊ธฐํƒ€ ๋ณด์•ˆ ํ—ค๋” (์‹ฌํ™”)

ํ—ค๋” ์—ญํ•  ์„ค๋ช…
๐Ÿ–ผ๏ธ X-Frame-Options: DENY ํด๋ฆญ์žฌํ‚น ๋ฐฉ์ง€ iframe์— ๋‚ด ํŽ˜์ด์ง€ ์‚ฝ์ž… ์ฐจ๋‹จ
๐Ÿ”Ž X-Content-Type-Options: nosniff MIME ํƒ€์ž… ์Šค๋‹ˆํ•‘ ๋ฐฉ์ง€ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํƒ€์ž… ์ž๋™ ์ถ”์ธก ๋ชปํ•˜๊ฒŒ
๐Ÿš€ Strict-Transport-Security HTTPS ๊ฐ•์ œ ์ ์šฉ ๋ชจ๋“  ์š”์ฒญ HTTPS๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ

๐Ÿ’ป ์‹ค์ „ ์„ค์ • ์˜ˆ์‹œ

# ํด๋ฆญ์žฌํ‚น ๋ฐฉ์ง€
X-Frame-Options: DENY

# MIME ํƒ€์ž… ์Šค๋‹ˆํ•‘ ๋ฐฉ์ง€
X-Content-Type-Options: nosniff

# HSTS
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

๐Ÿ“ข ๋น„์œ :



๐ŸŽฏ 4-6. ๊ธฐ์ˆ ๋ฉด์ ‘ ๋Œ€๋น„ ์‹ฌํ™” ์งˆ๋ฌธ

์งˆ๋ฌธ ์‹ฌํ™” ๋‹ต๋ณ€
XSS ๋ฐฉ์ง€ ๋ฐฉ๋ฒ•์€? Escape ์ฒ˜๋ฆฌ, CSP, textContent ์‚ฌ์šฉ, HttpOnly, ์ž…๋ ฅ Validation, ์™ธ๋ถ€ ์Šคํฌ๋ฆฝํŠธ ์ถœ์ฒ˜ ์ œํ•œ
CSRF ๋ฐฉ์ง€๋ฒ•์€? CSRF Token, SameSite ์ฟ ํ‚ค, Referer ๊ฒ€์ฆ, GET ์š”์ฒญ ์ œํ•œ, Token ์ฃผ๊ธฐ์  ๊ฐฑ์‹ 
HTTPS ์ ์šฉ ์ด์œ ๋Š”? ๋ฐ์ดํ„ฐ ์•”ํ˜ธํ™”, ์„œ๋ฒ„ ์ธ์ฆ์„œ๋กœ ์‹ ๋ขฐ์„ฑ ํ™•๋ณด, SEO, ์ค‘๊ฐ„์ž ๊ณต๊ฒฉ ๋ฐฉ์–ด
์ฟ ํ‚ค ๋ณด์•ˆ ์†์„ฑ์€? Secure โ†’ HTTPS ์ „์†ก, HttpOnly โ†’ JS ์ ‘๊ทผ ์ฐจ๋‹จ, SameSite โ†’ CSRF ๋ฐฉ์–ด (Strict, Lax, None ์ฐจ์ด ์„ค๋ช…)
๊ธฐํƒ€ ํ—ค๋” ์ ์šฉ ์ด์œ ๋Š”? ํด๋ฆญ์žฌํ‚น(X-Frame), ํƒ€์ž… ์Šค๋‹ˆํ•‘(nosniff), HTTPS ๊ฐ•์ œ(HSTS) ๋“ฑ ๋‹ค์ธต ๋ณด์•ˆ ์ œ๊ณต


๐Ÿšจ ์‹ค๋ฌด ๋ณด์•ˆ TIP ์ •๋ฆฌ

์ƒํ™ฉ ์‹ค์ „ ์ ์šฉ
ํผ ์ž…๋ ฅ ์ฒ˜๋ฆฌ Escape + Validation + ๊ธธ์ด ์ œํ•œ
์ธ์ฆ/์„ธ์…˜ ๊ด€๋ฆฌ SameSite=Strict + Secure + HttpOnly ์ฟ ํ‚ค ํ•„์ˆ˜
์„œ๋ฒ„ ๋ฐฐํฌ HTTPS + HSTS + ๋ณด์•ˆ ํ—ค๋”
์™ธ๋ถ€ ์Šคํฌ๋ฆฝํŠธ CSP๋กœ ์ถœ์ฒ˜ ์ œํ•œ, ์ธ๋ผ์ธ ์Šคํฌ๋ฆฝํŠธ ์ตœ์†Œํ™”
์ฝ”๋“œ ๋ฆฌ๋ทฐ XSS, CSRF, HTTPS, ๋ณด์•ˆ ํ—ค๋” ์ ๊ฒ€ ํฌํ•จ

๐Ÿ“Œ ์ตœ์ข… ์š”์•ฝ

๐ŸŒŸ ์ฃผ์ œ ์‹ค๋ฌด ํฌ์ธํŠธ ๋ฉด์ ‘ ์‹ฌํ™”
XSS Escape, CSP, textContent ์‚ฌ์šฉ, HttpOnly DOM XSS, Reflected XSS, Stored XSS ์ฐจ์ด๊นŒ์ง€
CSRF Token, SameSite, Referer ๊ฒ€์ฆ ์ฟ ํ‚ค ์ž๋™ ์ „์†ก ์›๋ฆฌ, Token ๋ฐฉ์‹ ์žฅ๋‹จ์ 
HTTPS ์ธ์ฆ์„œ ์ž๋™ ๊ฐฑ์‹ , HSTS TLS ํ•ธ๋“œ์…ฐ์ดํฌ ๊ณผ์ •๊นŒ์ง€
์ฟ ํ‚ค ๋ณด์•ˆ Secure, HttpOnly, SameSite ์„ค์ • ์„ธ๋ถ€ ์˜ต์…˜ ๋ฐ ๋ณด์•ˆ ํšจ๊ณผ ์„ค๋ช…
๋ณด์•ˆ ํ—ค๋” Frame, Content-Type, HSTS ํด๋ฆญ์žฌํ‚น, MIME ์Šค๋‹ˆํ•‘ ๊ณต๊ฒฉ ์›๋ฆฌ๊นŒ์ง€