Node.js 교과서 2018년도 책 기준이라 개정된 책이랑 코드가 다릅니다.
들어가기 전
당분간 진행할 블로그 내용은 zeroCho 님께서 쓰신 책인 Node.js 교과서라는 책에 나오는 Node.Auction 코드를 여러 방면으로 수정, 개선하는 과정을 블로그와 깃허브에 정리하고자 합니다.
zeroCho님 블로그에 방문해 보시면 다른 알찬 내용들도 많으니 확인해보세요.
ZeroCho Blog
ZeroCho의 Javascript와 Node.js 그리고 Web 이야기
www.zerocho.com
입력값 검증
IT서적 대부분이 기능 구현에 집중된 책이다보니 입력값에 대한 검증은 빠져있는 편입니다. 사용자로부터 입력받는 값은 항상 신뢰할 수 없기 때문에 검증과정은 반드시 해주셔야 합니다.
필요한 라이브러리
npm i joi xss
* joi : 입력값 검증에 있어 훌륭한 라이브러리.
* xss : xss 공격 방어를 위한 라이브러리
joi의 사용법은 아래와 같습니다. .
소스코드 : 입력값 검증(joi) 예시
const joi = require('joi')
router.post('/login', async (req, res, next) => {
const body = req.body;
const schema = joi.object().keys({
email : joi.string().email({
minDomainSegments : 1, tlds : { allow : [ "com" ] }
}).required(),
password : joi.string()
.regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,32}$/).required(),
})
try{
await schema.validateAsync(body)
... 생략 ...
}catch(err){
next(err)
}
})
* email : 이메일 문자열이며, com 으로 끝나는 이메일만 허용합니다.
* password : 문자열이며 최소 대문자, 소문자, 특수문자, 영어가 모두 포함되어야 하며 최소 8자리에서 32자리까지 받습니다.
둘 다 required()가 설정되어 있기 때문에 필수값입니다.
자세한 내용은 아래 공식문서를 방문해 보시면 알기 쉽게 설명되어 있습니다.
joi.dev
joi.dev
저는 입력값 검증이 많기 때문에 매번 입력값검증과 xss검증을 라우터마다 작성하기에는 다소 복잡하기 때문에 validate 모듈을 따로 만들었습니다.
소스코드 : joi + xss 검증 예시
경로 : utils/validate.js
const xss = require('xss')
const xssOptions = {
stripignoreTag : true,
stripignoreTagBody : [ 'script' ]
}
/**
* 입력값 검증
* xss 방어 모듈
*
* @param {joi.objectShema<any>} schema
* @param {Object} obj
*/
exports.userInputObjectValidateAsync = async (schema, obj) => {
try{
await schema.validateAsync(obj)
await Promise.all(
Object.entries(obj).map(([key, val]) => xss(val, xssOptions))
)
}catch(err){
throw err;
}
}
CSRF 방어
session Id는 cookie에 저장되어 사용자에게 전달이 됩니다. 사용자가 서버에 접근할 때마다 위의 session Id를 확인하고 사용자를 식별합니다. CSRF 공격은 해당 부분에서 발생합니다.
session Id를 발급받은 사용자가 악성 스크립트가 포함된 링크나 이미지를 클릭하는 순간 인증된 사용자의 session Id로 서버에 요청해 악성 스크립트를 실행시킵니다..
해당 공격을 방어하기 위해 일회성 토큰인 CSRF Token을 발급하고 사용자는 요청을 보낼 때 CSRF Token을 같이 서버로 보내줍니다. 서버는 발급한 CSRF Token과 일치하지 않으면 미들웨어에서 요청을 무시하도록 만들겠습니다.
필요 라이브러리
npm install csurf
소스 코드 : csurf 사용 예시
const csurf = require('csurf')
... 생략 ...
const csurfProtection = csurf({
cookie : {
httpOnly : true,
sameSite : 'strict'
}
})
router.get('/join', csrfProtection, (req, res, next) => {
const csrfToken = req.csrfToken()
... 생략 ...
res.cookie('csrfToken', csrfToken, {
httpOnly : true,
secure : false,
sameSite : 'strict'
})
res.render('join', {
title : '회원가입 - NodeAuction',
_csrf : csrfToken,
joinError: req.flash('joinError'),
});
})
router.post('/join', csrfProtection, async (req, res, next) => {
const body = req.body;
const schema = joi.object().keys({
email : joi.string().email({
minDomainSegments : 1, tlds : { allow : [ "com" ] }
}).required(),
password : joi.string().regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,32}$/).required(),
_csrf : joi.string().required()
})
... 생략 ...
})
POST /join 쪽 입력값 검증을 보시면 body를 통해 _csrf 토큰이 넘어오는 것을 확인하실 수 있습니다.
만약 해당 토큰이 없으면 403 코드를 반환하며 요청을 거절합니다.
아래는 테스트 코드를 실행한 결과입니다.
전체 코드 (GitHub)
GitHub - dotredbee/NodeAuction_update: Node.js교과서 ch12 코드에서 추가로 업데이트한 서버입니다.
Node.js교과서 ch12 코드에서 추가로 업데이트한 서버입니다. Contribute to dotredbee/NodeAuction_update development by creating an account on GitHub.
github.com
'Backend > Node.js' 카테고리의 다른 글
[Node.js 교과서] ch12. NodeAuction 개선하기 3 : 스스로 해보기 풀이 (0) | 2023.04.09 |
---|---|
[Node.js 교과서] ch12. NodeAuction 개선하기 2 : 서비스 분할 (0) | 2023.04.05 |
[Node.js] web token(jwt) 인증 + Redis(In memory) + 최소한의 보안 (0) | 2023.04.01 |
[Node.js] 캐시, LRU 캐시 (0) | 2023.03.05 |
[Node.js 개발자 되기] 7. Token 기반 인증에 대하여 (0) | 2023.02.28 |