이번 프로젝트에서 API보안에 특히 신경쓰면서 이것 저것 외부 공격에 대해 알아 보았는데, 우리가 개발자가 되기 이전에도 웹사이트를 이용하면서 자주 접할 수 있었던 공격 이름이 DOS공격이다. D-DOS공격에 의해 서버가 죽었다는 뉴스나 페이지 다운 등을 격어 봤을 것이다.
실제 XSS공격이나 Injection공격 같은 부분은 일반인이 듣기 쉬운 이름은 아니지만 dos공격은 흔하게 들을 수 있는 용어였다.
그렇다면 일단 DOS공격이 무엇인지 부터 알아보자.
DOS(Denial of Service)공격 이란 '서비스 거부 공격'이다 특정 시스템이나 사이트에 대해 해커가 과도한 요청을 보내서 트래픽 발생을 유도하여 정상적인 서비스 운영이 불가능하게 만드는 공격이다.
그럼 이 DOS공격을 방어하기 위해서는 어떤 조치를 해줘야 할까?
DOS공격에 방어를 하기 위해서 DOS공격이 요청과다로 인한 트래픽 유도라는 것을 유념하고 과다한 요청에 대한 처리를 하는 것이 필요하다.
일반적으로 CDN측 서버단에서 limit를 걸어서 처리하는 방법을 주로 사용하는데, 이번에는 API자체적으로 요청수에 제한을 걸어서 방어하는 방법에 대해 알아보자
API요청 자체에 제한을 걸기위한 라이브러이가 여럿 존재하는데 그 중에 필자는 express-rate-limit 라이브러리를 사용하였다.
Javascript 및 Typescript 프로젝트 모두에서 작동하는 요청 속도 제한 라이브러리이다.
npm install express-rate-limit
npm을 통해서 간단하게 설치할 수 있으며 사용법도 간단하다.
보통 미들웨어로 사용되며 서버전체에 각 요청에 대한 제한을 걸 수도 있고, API별로 따로 따로 제한을 걸 수도 있다.
필자는 조회에 비해서 당연히 생성, 수정, 삭제가 더 적게 일어날 것이라 판단하고 R(read)과 CUD(craete, update, delete)에 대해 속도 제한을 따로 만들어서 적용하였다.
const rateLimite = require('express-rate-limit');
exports.postCUDApiLimiter = rateLimite({
windowMs: 60 * 1000,
max: 10,
handler(req, res, next, option) {
res.status(option.statusCode).json({ errorMsg: '요청 많음' });
},
});
exports.getApiLimiter = rateLimite({
windowMs: 1 * 1000,
max: 10,
handler(req, res, next, option) {
res.status(option.statusCode).json({ errorMsg: '조회 요청 많음' });
},
});
CUD는 1분에 최대 10번의 요청까지 이 요청횟수를 넘어가게 되면, 에러를 발생시킨다. R은 1초에 10번 까지, 무한스크롤에 있어 스크롤을 한번에 내렸을 때에 요청이 과도하게 발생하여 어쩔 수 없이 10번으로 제한하였지만, 각 상황에 맞춰서 요청제한의 시간이나 횟수는 본인의 프로젝트에 맞게 설정해 나가자.
API보안을 위해서 각 API에 요청제한기를 적용하였지만, 보통은 CDN서버측에서 요청을 제한하기 때문에 한번쯤 경험을 위한 방식으로 작성해 보는것도 좋고, 만약 정말 DOS공격이 일어나거나 예상되어 취약하다고 생각한다면 서버측과 API측 모두 적용하여 2중방어를 하는 것도 좋을 것 같다.