Public Source Viewer
비나래아카이브 개발자 포털
실제 서비스 구조를 살펴볼 수 있는 공개용 코드 뷰어입니다. 인증, 세션, 외부 연동, 토큰, 관리자 식별 등 보안상 민감한 구현은 파일 단위 또는 줄 단위로 검열됩니다.
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