Public Source Viewer

비나래아카이브 개발자 포털

실제 서비스 구조를 살펴볼 수 있는 공개용 코드 뷰어입니다. 인증, 세션, 외부 연동, 토큰, 관리자 식별 등 보안상 민감한 구현은 파일 단위 또는 줄 단위로 검열됩니다.

Redacted View
src/middleware/csrf.middleware.ts
공개 가능
1 import { Application, Request, Response, NextFunction } from 'express';
2 import csrf from 'csurf';
3
4 const csrfProtection = csrf({
5 cookie: false,
6 value: (req) =>
7 (req.body && req.body._csrf)
8 [SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
9 [SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
10 [SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
11 || ''
12 });
13
14 function isSameOriginRequest(req: Request): boolean {
15 const source = req.get('origin') || req.get('referer');
16 if (!source) return true;
17 try {
18 const url = new URL(source);
19 return url.host === req.get('host');
20 } catch {
21 return false;
22 }
23 }
24
25 export function setupCsrfMiddleware(app: Application): void {
26 app.use((req: Request, res: Response, next: NextFunction) => {
27 const unsafeMethod = ['POST', 'PUT', 'PATCH', 'DELETE'].includes(req.method);
28 if (unsafeMethod && !isSameOriginRequest(req)) {
29 return res.status(403).send('출처가 올바르지 않습니다.');
30 }
31
32 if (req.method === 'GET') {
33 return csrfProtection(req, res, (err: any) => {
34 if (err) return next(err);
35 [SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
36 [SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
37 [SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
38 httpOnly: false,
39 sameSite: 'lax',
40 [SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
41 });
42 return next();
43 });
44 }
45
46 if (unsafeMethod) {
47 return csrfProtection(req, res, next);
48 }
49
50 return next();
51 });
52
53 app.use((req: Request, res: Response, next: NextFunction) => {
54 res.locals.theme = req.session.theme || 'light';
55
56 [SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
57 [SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
58 }
59
60 next();
61 });
62 }
63
64 export function csrfErrorHandler(err: any, req: Request, res: Response, next: NextFunction): any {
65 [SECURITY REDACTED] 민감한 설정/인증/토큰 관련 코드입니다.
66 return next(err);
67 }
68
69 console.warn('CSRF 검증 실패:', req.method, req.path, err.message);
70
71 if (req.path === '/chat-gpt' || req.path === '/share-discord' || req.path === '/api/exhibition/review') {
72 return res.status(403).json({ error: 'CSRF 토큰이 유효하지 않습니다. 페이지를 새로고침 해주세요.' });
73 }
74
75 return res.status(403).send('CSRF 검증 실패. 페이지를 새로고침 후 다시 시도해주세요.');
76 }
77