flawopen.com/참고/Next.js Server Actions CSRF
Next.js Server Actions CSRF: Origin 검사와 안전한 설정
Next.js Server Actions는 POST를 사용하고 Origin의 호스트를 x-forwarded-host 또는 host와 비교합니다. 방문자 초대장에 적힌 장소가 서버가 예상한 장소와 같은지 확인하는 것과 같습니다. 이 검사는 교차 사이트 제출을 막는 데 도움이 되지만 권한을 부여하지 않습니다. 각 액션은 사용자를 인증하고 입력과 권한을 확인해야 합니다.
중요한 한계가 있습니다. 현재 Next.js 문서는 Origin이 없는 요청은 경고와 함께 통과시킨다고 설명합니다. 역방향 프록시도 비교 대상 호스트에 영향을 줍니다. 이 검사를 여러 방어 계층 중 하나로 보고, 프록시가 신뢰할 호스트 값을 설정하게 하세요.
- Origin
- 브라우저가 전달하는 시작 페이지의 출처이며, Next.js는 그 호스트를 앱 호스트와 비교합니다.
- Host / X-Forwarded-Host
- 비교에 사용하는 호스트 값입니다. 프록시가 전달 정보를 설정하거나 검증해야 합니다.
- allowedOrigins
- Server Actions가 허용하는 추가 Origin 호스트 목록입니다. 정확한 호스트와 와일드카드 패턴을 지원합니다.
- Authorization
- 인증된 사용자가 이 특정 객체에서 해당 작업을 수행할 수 있는지 액션별로 판단합니다.
Server Actions의 기본 CSRF 검사 방식
브라우저가 Server Action을 제출
Server Action은 HTTP POST로 호출됩니다. SameSite 쿠키 동작은 많은 교차 사이트 제출을 기본 차단하지만 POST만으로 완전한 CSRF 방어가 되지는 않습니다.
Next.js가 호스트를 비교
Origin이 있으면 Next.js는 해당 호스트를 x-forwarded-host 또는 host와 비교합니다. 다르고 serverActions.allowedOrigins에도 없으면 거부합니다.
액션은 자체 정책도 적용
요청 검사 후 액션은 사용자를 인증하고 각 인자를 검증하며 작업 권한을 확인해야 합니다. 액션 ID와 숨겨진 폼 필드는 접근 제어가 아닙니다.
중요한 한계: Origin 누락과 allowedOrigins
현재 문서는 Origin이 없는 요청을 경고와 함께 계속 처리한다고 설명합니다. 모든 요청이 Origin 비교를 통과했다고 가정하지 마세요. 누락 원인을 조사하고 액션 안에서 인증, 권한 확인, 입력 검증을 수행하세요.
allowedOrigins는 정확한 호스트와 와일드카드를 허용합니다. *는 레이블 하나, **는 하나 이상과 일치합니다. 조직이 관리하고 필요한 도메인과 하위 도메인만 허용하세요. 사용자 제어 하위 도메인까지 포함하면 통제할 수 없는 출처를 신뢰할 수 있습니다.
역방향 프록시를 보안 경계로 설정
Next.js는 x-forwarded-host 또는 host를 비교에 사용합니다. 엣지 프록시는 클라이언트가 보낸 전달 헤더를 제거하고 검증된 공개 호스트 이름으로 값을 설정해야 합니다. 앱은 신뢰할 프록시를 통해서만 접근 가능해야 합니다. 프록시가 내부 호스트를 전달한다면 필요한 공개 출처만 allowedOrigins에 추가하세요. 임의의 호스트를 신뢰해 불일치를 해결하지 마세요.
// Every subdomain, including delegated or tenant-controlled names, is trusted.
module.exports = {
experimental: {
serverActions: {
allowedOrigins: ['**.example.com'],
},
},
};
// Add only the public host that this deployment requires. module.exports = { experimental: { serverActions: { allowedOrigins: ['admin.example.com'], }, }, }; // Configure the edge to overwrite X-Forwarded-Host // with the validated public hostname.
Host 권고문: CSRF와 구분되는 관련 위험
Host 신뢰 문제는 Server Actions의 SSRF 취약점으로 이어진 사례가 있습니다. CVE-2024-34351은 Host를 변경할 수 있고 액션이 /로 시작하는 상대 리디렉션을 수행하는 조건에서 14.1.1 이전 자체 호스팅 버전에 영향을 줬습니다. 별도의 2026년 7월 Vercel 권고문은 사용자 지정 서버에서 클라이언트가 호스트 관련 헤더를 제어할 때 SSRF와 내부 값 노출 가능성을 설명하며 수정 버전은 15.5.21과 16.2.11입니다. 이는 호스트 신뢰 취약점이지 Origin CSRF 검사 우회 증거가 아닙니다.
2026년 권고문 문제에는 수정 버전으로 업그레이드하세요. 그 전에는 엣지나 프록시에서 Host와 X-Forwarded-Host를 고정하거나 검증하세요. 권고문은 14.2.0 이상에서 추가 대안으로 __NEXT_PRIVATE_ORIGIN도 제시합니다. 적용 전 권고문에서 영향 및 지원 버전을 확인하세요.
모든 Server Action에서 권한 확인과 검증
Next.js 문서는 Server Action 인자를 신뢰할 수 없는 값으로 취급하고 현재 사용자가 실행 권한이 있는지 확인하라고 안내합니다. 취약한 예는 호출자가 전달한 객체 ID를 신뢰합니다. 수정 패턴은 인증과 ID 검증을 수행하고 데이터베이스 변경 자체에 소유자 조건을 포함합니다.
"use server";
export async function deleteInvoice(invoiceId: string) {
await db.invoice.delete({ where: { id: invoiceId } });
}
"use server";
import { z } from "zod";
import { requireUser } from "@/auth";
const invoiceIdSchema = z.string().uuid();
export async function deleteInvoice(rawId: unknown) {
const user = await requireUser();
const invoiceId = invoiceIdSchema.parse(rawId);
const result = await db.invoice.deleteMany({
where: { id: invoiceId, ownerId: user.id },
});
if (result.count !== 1) throw new Error("Forbidden");
}
Server Actions CSRF 및 권한 확인 체크리스트
- ✓프록시에서 알 수 없는 공개 호스트를 거부하고 클라이언트의
Host/X-Forwarded-Host를 검증된 값으로 덮어쓰세요. - ✓프록시나 다중 출처 배포에 꼭 필요하지 않으면
allowedOrigins를 비우고 관리 가능한 호스트만 가장 좁은 패턴으로 허용하세요. - ✓각 Server Action에서 사용자를 인증하고 인자를 런타임 검증하며 특정 객체 또는 작업의 권한을 확인하세요.
- ✓
Origin누락은 조사해야 할 로그 이상으로 취급하세요. 프레임워크 경고는 권한 결정이 아닙니다. - ✓사용자 지정 Route Handler는 별도 감사하세요. Server Actions의 Origin 검사를 상속하지 않으므로 쿠키 인증 변경 요청에 적절한 CSRF 방어를 구현하고 테스트하세요.
- ✓Next.js 보안 권고를 확인하고 영향받는 배포를 업데이트하세요. 특히 클라이언트 제공 호스트 헤더를 받는 사용자 지정 서버를 점검하세요.