
Next.js의 SSRF(서버 측 요청 위조) 취약점(CVE-2024-34351)에 대한 교육용 데모로, 단계별 악용 및 완화 예제가 포함됩니다.
이 저장소는 하나 이상의 미트업을 발표하기 위한 자료로 사용될 수 있습니다. 과정은 다음과 같습니다...
이 작업은 주로 두 가지 출처에 기반합니다:
1-csr-load-data vanilla react SPA loading data[!IMPORTANT] CSR(Client-Side Rendering): React 코드가 브라우저로 전달되어 DOM에 삽입될 콘텐츠를 생성합니다.

cd 1-csr-load-data
npm start

2-csr-router vanilla react SPA routing[!IMPORTANT] 페이지가 처음 로드된 후, 동일한 웹사이트 내에서 다른 페이지로 이동할 때 JavaScript를 사용하여 전체 페이지를 새로 고치지 않고 페이지의 일부를 다시 렌더링합니다.
cd 2-csr-router
npm start

3-rsc-load-data React Server Components (Next.js impl) loading data[!IMPORTANT] 브라우저가 아닌 서버에서 만 실행되도록 작성된 React 컴포넌트.

cd 3-rsc-load-data
npm run build
npm run start

4-rsc-router React Server Components (Next.js impl) routing[!IMPORTANT] 컴포넌트가 서버에서만 실행됩니다. 기본 동작은 정적 렌더링입니다: 컴포넌트가 빌드 시점에 실행됩니다.
cd 4-rsc-router
npm run build
npm run start

5-SSR SSR Server Side Rendering[!IMPORTANT] SSR은 클라이언트 컴포넌트를 서버에서 사전 렌더링하는 것을 의미합니다. React 코드가 요청 시점에 실행됩니다. 결과는 향후 요청을 위해 캐시될 수 있습니다.
모범 사례: 가능한 한 컴포넌트 트리 아래쪽에 'use client'; 컴포넌트를 정의하세요.
[!IMPORTANT] "React에서 'hydration'은 React가 서버 환경에서 이미 렌더링된 기존 HTML에 '연결'되는 방식입니다. hydration 중에 React는 기존 마크업에 이벤트 리스너를 연결하고 클라이언트에서 앱 렌더링을 인계받으려고 시도합니다. 완전히 React로 구축된 앱에서는 일반적으로 시작 시 전체 앱에 대해 하나의 '루트'만 한 번 hydration합니다."
cd 5-ssr
npm run build
npm run start

6-pages-router-ssg (Next.js impl)[!IMPORTANT] pages 라우터를 사용한 SSG(Static Site Generation): 애플리케이션을 빌드할 때 React 코드가 실행되며, 생성된 출력은 정적입니다.
cd 6-pages-router-ssg
npm run build
npm run start
7-pages-router-isr (Next.js impl)[!IMPORTANT] ISR(pages 라우터 사용): "Next.js를 사용하면 사이트를 구축한 후 정적 페이지를 생성하거나 업데이트할 수 있습니다. ISR(Incremental Static Regeneration)을 사용하면 전체 사이트를 다시 빌드할 필요 없이 페이지 단위로 정적 생성을 사용할 수 있습니다. ISR을 사용하면 수백만 개의 페이지로 확장하면서도 정적의 이점을 유지할 수 있습니다."
cd 7-pages-router-isr
npm run build
npm run start
"요청 시 데이터가 오래될(stale) 수 있습니다"
...
8-ssrf-14.1.014.1.1 미만 버전의 Next.JS 기반 애플리케이션redirect(/blog/${inputValue});Next.JS는 서버 측에서 요청을 실행한 후 결과를 브라우저에 반환합니다:
redirect('/blog/123'); 함수는 URL http://207.154.209.99/blog/123을 구성합니다.
이 URL을 구성하기 위해 Next.JS는 초기 요청의 HTTP 헤더에서 호스트 207.154.209.99를 가져옵니다.Content-Type: text/x-component 헤더를 반환하면 Next.JS는 URL을 HTTP GET으로 요청합니다.대상 서버에서 SSRF를 발생시키려면 다른 서버를 실행해야 합니다:
Content-Type: text/x-component 헤더 반환
8-ssrf-14.1.0의 취약점 수정/etc/nginx/sites-available/nextjs에서
이전:
server {
listen 80 default_server;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
이후:
server {
listen 80;
server_name 207.154.209.99;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host 207.154.209.99;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
부작용 위험...

app 디렉토리의 페이지는 기본적으로 서버 컴포넌트입니다. 이는 페이지가 클라이언트 컴포넌트인 pages 디렉토리와 다릅니다.
Next.js 13으로 업그레이드할 때 새 App Router를 사용할 필요는 없습니다. 두 디렉토리에서 모두 작동하는 새 기능과 함께 pages를 계속 사용할 수 있습니다.
다양한 솔루션의 로딩 성능을 비교하려면 console.log에 웹 코어 바이탈 메트릭을 추가할 수 있습니다.
App 라우터를 사용하는 ISR?
Next.js App Router에서는 가져온 모든 데이터가 기본적으로 정적이며, 빌드 시점에 렌더링됩니다. 그러나 이는 쉽게 변경할 수 있습니다. Next.js는 캐싱 및 재검증 규칙에 유연성을 제공하기 위해 fetch 옵션 객체를 확장합니다. fetch 요청에
{next: {revalidate: number}}옵션을 사용하여 설정된 간격이나 백엔드 변경 시 정적 데이터를 새로 고칠 수 있으며(Incremental Static Regeneration), 동적 데이터(서버 측 렌더링)를 위해서는{cache: 'no-store'}옵션을 전달할 수 있습니다.