# CSRF(csurf 모듈)
크로스 사이트 리퀘스트 변조(cross site request forgery, CSRF)는 사이트간 요청위조를 의미 합니다.
피해자의 권한으로 피해자 모르게 해커가 요청을 수행 하도록 만드는 것을 의미 합니다.
특히 "결재"와 관련된 웹 어플리케이션에서는 필수이며 가장 강력한 수준의 조치가 요구 됩니다.
* 해커가 악성스크립트를 통하여 원치않는 결재, 결재정보노출 등을 할 수 있기 때문 입니다.
nestjs에서도 이러한 문제를 방지하기 위해 csurf 모듈을 활용하여 기능 구현을 쉽게 할 수 있도록 해줍니다.
fastify 모듈도 있지만..설명이나 사용법이 워낙 불친절하고, 제 취향이 아녔..
원리와 개념은 간단 합니다.
클라이언트가 데이터를 변경하려는 페이지에 접근한 상태라면 특정 키 값을 발행 합니다. * 예: 게시글 등록
이후에 서버에서 발행한 키 값을 가지고 클라이언트가 데이터 변경 요청을 하게되면,
서버에서는 키 값이 일치하면 올바른 요청으로 간주하고 컨트롤러에 값을 전달하여 줍니다.
그 이후에는 사용한 키값은 만료시키고 새로운 키 값을 다시 클라이언트에게 전달하여 줍니다.
기능 구현을 위해서 먼저 모듈을 추가하여 줍니다.
npm install --save cookie-parser
npm install --save csurf
CSRF설정은 어플리케이션이 동작하는 최상위 단계에서 먼저 동작해야 하므로 메인파일에서 설정을 합니다.
* 파일이름 : main.ts
import { NestFactory } from '@nestjs/core';
import { NestExpressApplication } from '@nestjs/platform-express';
import { AppModule } from './app.module';
import * as csurf from 'csurf';
import * as cookie from 'cookie-parser';
async function bootstrap() {
const app = await NestFactory.create<NestExpressApplication>(AppModule);
app.useStaticAssets('html파일이 있는경로');
app.use(cookie());
app.use(csurf({cookie:{maxAge : 1000 * 60 * 5 }})); //쿠키로 설정, 5분
app.use((req: any, res: any, next: any) => { //사용 설정
const token = req.csrfToken();
res.cookie('XSRF-TOKEN', token); //키 값 입니다
res.locals.csrfToken = token;
next();
});
await app.listen(3000);
}
bootstrap();
이제 응답을 받을 컨트롤러를 작성하여 줍니다.
* 파일이름 : app.controller.ts
import { Request, Response } from 'express';
import { Controller, All, Res, Req, HttpStatus} from '@nestjs/common';
@Controller()
export class AppController {
@All('getCsrf')
겟방식엔관대하다(@Req() req: Request, @Res() res: Response) {
res.status(HttpStatus.OK).send({ result : 'ok' });
}
}
getCsrf 요청에 대해서 ok 값을 리턴하는 메소드를 추가하였습니다.
이제 테스트를 위한 페이지가 필요 합니다.
이를 위해서는 메인 파일(main.ts)에서 useStaticAssets 함수에 html 페이지가 있는 경로를 입력하여 간단한 index.html 파일을 접근 할 수 있게 해주었습니다.
index.html 파일 내용은 아래와 같습니다.
* 파일이름 : index.html
<html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>index</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<button type="button" onclick="sendData()">sendData</button>
</body>
</html>
<script>
function getCookie(cname) {
let name = cname + "=";
let decodedCookie = decodeURIComponent(document.cookie);
let ca = decodedCookie.split(';');
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
let csrfToken
fetch('getCsrf') //토큰을 발급 받습니다.
.then((response) => {
csrfToken = getCookie('XSRF-TOKEN');
console.log(csrfToken)
});
function sendData() {
console.log('보내기위한 값',csrfToken)
fetch('getCsrf', { //토큰을 가지고 인증합니다
method: 'POST', //POST, PUT 등 데이터를 변화하는 요청에 의해 동작합니다
headers: {
'XSRF-TOKEN': csrfToken, //main.ts 파일에서 설정한 키 값 입니다!!!!
//'XSRF-TOKEN': 'hahah',
},
body: {data:1234}
}).then((res)=>console.log(res));
}
</script>
index.html 파일이 준비가 완료되고 나면 아래 적어둔 fetch함수에 의해서 getCsrf 요청이 발생 합니다.
getCsrf 요청에서는 쿠키로 CSRF 토큰값을 받을 수 있습니다.
인증받은 값이 존재하기 때 문에 이제 데이터를 변경하는 행위에 대해서 CSRF 위변조 기능이 동작할 것 입니다.
이를 위해서 index.html에 있는 버튼을 누릅니다.
해당 버튼은 해더에 키로 "XSRF-TOKEN", 값은 서버에서 발급받은 값을 가지고 POST 방식으로 요청하게 되어 있습니다.
200 코드가 받아진 것으로 보아하니 문제없이 완료가 된 것을 알 수 있습니다.
테스트를 위해서 이상한 값을 한번 보내봅니다.
index.html파일에서 sendData함수의 주석처리된 "hahah" 값을 보내면 아래처럼 오류가 발생 합니다.
간단한 설정 하나만으로 위 내용처럼 쉽게 CSRF 변조 공격을 방지할 수 있습니다!
해당 내용에 사용된 소스코드는 제 깃허브에서 받아서 확인 할 수 있습니다.
https://github.com/TaeSeungRyu/NestProject/tree/main/step9
공부하면 할 수록 재미있고 즐거운 nestjs!!!
다음 포스팅에서도 보안과 관련된 설정에 대해서 살펴보겠습니다.
궁금한점 또는 틀린부분은 언제든 연락 주세요!
* fastify는 너무 불친절하네요..좀 더 분석해 보겠습니다..ㅜ
'Node.js > Nestjs (Nest.js)' 카테고리의 다른 글
Nestjs 프레임워크 서버(websocket) -12 (0) | 2022.09.07 |
---|---|
Nestjs 프레임워크 서버(XSS 방지, Cross Site Scripting) -11 (0) | 2022.08.29 |
Nestjs 프레임워크 서버(패스포트, JWT) -9 (0) | 2022.08.22 |
Nestjs 프레임워크 서버(세션) -8 (0) | 2022.08.19 |
Nestjs 프레임워크 서버(가드와 오류 필터) -7 (0) | 2022.08.12 |
댓글