보안

[번역] NodeJS 보안 사항 및 시큐어 코딩 BY OWASP

JohnnyDeveloper 2024. 6. 4. 15:02

NodeJS Security Cheat Sheet NodeJS 보안 치트 시트

원본: https://cheatsheetseries.owasp.org/cheatsheets/Nodejs_Security_Cheat_Sheet.html#nodejs-security-cheat-sheet

 

Nodejs Security - OWASP Cheat Sheet Series

NodeJS Security Cheat Sheet Introduction This cheat sheet lists actions developers can take to develop secure Node.js applications. Each item has a brief explanation and solution that is specific to the Node.js environment. Context Node.js applications are

cheatsheetseries.owasp.org

해당 포스팅은 OWASP NodeJs 자료를 번역했습니다.

Introduction 소개

이 치트 시트에는 개발자가 안전한 Node.js 애플리케이션을 개발하기 위해 수행할 수 있는 작업이 나열되어 있습니다. 각 항목에는 Node.js 환경과 관련된 간단한 설명과 솔루션이 있습니다.

Context 문맥

응용 프로그램의 수가 증가하고 있으며 다른 프레임워크 및 프로그래밍 언어와 다르지 않습니다. Node.js 애플리케이션은 모든 종류의 웹 애플리케이션 취약점에 취약합니다.

Objective 목표

이 치트 시트는 Node.js 응용 프로그램을 개발하는 동안 따라야 할 모범 사례 목록을 제공하는 것을 목표로 합니다.

Recommendations 권장 사항

애플리케이션의 보안을 강화하기 위한 몇 가지 권장 사항이 있습니다. 이들은 다음과 같이 분류됩니다.

  • Application Security 애플리케이션 보안
  • Error & Exception Handling 오류 및 예외 처리
  • Server Security 서버 보안
  • Platform Security 플랫폼 보안

Application Security 애플리케이션 보안

Use flat Promise chains 플랫 Promise 체인 사용

비동기 콜백 함수는 Node.js의 가장 강력한 기능 중 하나입니다. 그러나 콜백 함수 내에서 중첩 계층을 늘리면 문제가 될 수 있습니다. 모든 다단계 프로세스는 10개 이상의 수준 깊이로 중첩될 수 있습니다. 이 문제를 "파멸의 피라미드" 또는 "콜백 지옥"이라고 합니다. 이러한 코드에서는 콜백 내에서 오류와 결과가 손실됩니다. Promise는 중첩 피라미드에 들어가지 않고 비동기 코드를 작성하는 좋은 방법입니다. Promise는 하향식 실행을 제공하는 동시에 오류와 결과를 다음 .then 함수에 전달하여 비동기적입니다.

Promise의 또 다른 장점은 Promise가 오류를 처리하는 방식입니다. Promise 클래스에서 오류가 발생하면 .then 함수를 건너뛰고 찾은 첫 번째 .catch 함수를 호출합니다. 이러한 방식으로 Promise는 오류를 캡처하고 처리하는 데 더 높은 보증을 제공합니다. 원칙적으로, 모든 비동기 코드(이미터를 제외하고)가 promise를 반환하도록 할 수 있습니다. Promise 호출도 피라미드가 될 수 있습니다. "콜백 지옥"에서 완전히 벗어나기 위해서는 플랫 프라미스 체인을 사용해야 합니다. 사용중인 모듈이 Promises를 지원하지 않는 경우 function을 사용하여 Promise.promisifyAll() 기본 객체를 Promise로 변환 할 수 있습니다.

다음 코드 스니펫은 "콜백 지옥"의 예시입니다:

function func1(name, callback) {
  // operations that takes a bit of time and then calls the callback
}
function func2(name, callback) {
  // operations that takes a bit of time and then calls the callback
}
function func3(name, callback) {
  // operations that takes a bit of time and then calls the callback
}
function func4(name, callback) {
  // operations that takes a bit of time and then calls the callback
}

func1("input1", function(err, result1){
   if(err){
      // error operations
   }
   else {
      //some operations
      func2("input2", function(err, result2){
         if(err){
            //error operations
         }
         else{
            //some operations
            func3("input3", function(err, result3){
               if(err){
                  //error operations
               }
               else{
                  // some operations
                  func4("input 4", function(err, result4){
                     if(err){
                        // error operations
                     }
                     else {
                        // some operations
                     }
                  });
               }
            });
         }
      });
   }
});

위의 코드는 플랫 Promise 체인을 사용하여 다음과 같이 안전하게 작성할 수 있습니다.

function func1(name) {
  // operations that takes a bit of time and then resolves the promise
}
function func2(name) {
  // operations that takes a bit of time and then resolves the promise
}
function func3(name) {
  // operations that takes a bit of time and then resolves the promise
}
function func4(name) {
  // operations that takes a bit of time and then resolves the promise
}

func1("input1")
   .then(function (result){
      return func2("input2");
   })
   .then(function (result){
      return func3("input3");
   })
   .then(function (result){
      return func4("input4");
   })
   .catch(function (error) {
      // error operations
   });

그리고 async / await 사용 :

function async func1(name) {
  // operations that takes a bit of time and then resolves the promise
}
function async func2(name) {
  // operations that takes a bit of time and then resolves the promise
}
function async func3(name) {
  // operations that takes a bit of time and then resolves the promise
}
function async func4(name) {
  // operations that takes a bit of time and then resolves the promise
}

(async() => {
  try {
    let res1 = await func1("input1");
    let res2 = await func2("input2");
    let res3 = await func3("input2");
    let res4 = await func4("input2");
  } catch(err) {
    // error operations
  }
})();

Set request size limits 요청 크기 제한 설정

요청 본문의 버퍼링 및 구문 분석은 리소스를 많이 사용하는 작업일 수 있습니다. 요청 크기에 제한이 없는 경우 공격자는 서버 메모리를 소모하거나 디스크 공간을 채울 수 있는 큰 요청 본문이 있는 요청을 보낼 수 있습니다. raw-body를 사용하여 모든 요청에 대한 요청 본문 크기를 제한할 수 있습니다.

const contentType = require('content-type')
const express = require('express')
const getRawBody = require('raw-body')

const app = express()

app.use(function (req, res, next) {
  if (!['POST', 'PUT', 'DELETE'].includes(req.method)) {
    next()
    return
  }

  getRawBody(req, {
    length: req.headers['content-length'],
    limit: '1kb',
    encoding: contentType.parse(req).parameters.charset
  }, function (err, string) {
    if (err) return next(err)
    req.text = string
    next()
  })
})

그러나 파일을 업로드할 때와 같이 일부 요청에는 요청 본문에 큰 페이로드가 있을 수 있으므로 모든 요청에 대한 요청 크기 제한을 수정하는 것은 올바른 동작이 아닐 수 있습니다. 또한 JSON 구문 분석은 차단 작업이므로 JSON 형식의 입력은 멀티파트 입력보다 더 위험합니다. 따라서 다양한 콘텐츠 형식에 대한 요청 크기 제한을 설정해야 합니다. 다음과 같이 express 미들웨어를 사용하여 이 작업을 매우 쉽게 수행할 수 있습니다.

app.use(express.urlencoded({ extended: true, limit: "1kb" }));
app.use(express.json({ limit: "1kb" }));

공격자는 요청의 Content-Type 헤더를 변경하여 요청 크기 제한을 우회할 수 있다는 점에 유의해야 합니다. 따라서 요청을 처리하기 전에 요청 헤더에 명시된 콘텐츠 유형에 대해 요청에 포함된 데이터의 유효성을 검사해야 합니다. 각 요청에 대한 콘텐츠 유형 유효성 검사가 성능에 심각한 영향을 미치는 경우 특정 콘텐츠 유형이나 미리 정해진 크기보다 큰 요청만 유효성 검사할 수 있습니다.

Do not block the event loop 이벤트 루프를 차단하지 마세요.

Node.js는 스레드를 사용하는 일반적인 애플리케이션 플랫폼과 매우 다릅니다. Node.js에는 단일 스레드 이벤트 기반 아키텍처가 있습니다. 이 아키텍처를 통해 처리량이 높아지고 프로그래밍 모델이 더 단순해집니다. Node.js는 비차단 I/O 이벤트 루프를 중심으로 구현됩니다. 이 이벤트 루프를 사용하면 I/O 또는 컨텍스트 전환을 기다리지 않습니다. 이벤트 루프는 이벤트를 찾아 핸들러 함수에 전달합니다. 이로 인해 CPU 집약적인 JavaScript 작업이 실행될 때 이벤트 루프는 해당 작업이 완료될 때까지 기다립니다. 이것이 바로 이러한 작업을 "차단"이라고 부르는 이유입니다. 이 문제를 극복하기 위해 Node.js에서는 IO 차단 이벤트에 콜백을 할당할 수 있습니다. 이렇게 하면 기본 애플리케이션이 차단되지 않고 콜백이 비동기적으로 실행됩니다. 따라서 일반적인 원칙으로 모든 차단 작업은 이벤트 루프가 차단되지 않도록 비동기식으로 수행되어야 합니다.

차단 작업을 비동기적으로 수행하더라도 애플리케이션이 여전히 예상대로 작동하지 않을 수 있습니다. 이는 콜백 내의 코드를 사용하여 먼저 실행되는 콜백 외부의 코드가 있는 경우에 발생합니다. 예를 들어, 다음 코드를 고려하십시오.

const fs = require('fs');
fs.readFile('/file.txt', (err, data) => {
  // perform actions on file content
});
fs.unlinkSync('/file.txt');

위의 예에서 unlinkSync 함수는 콜백 전에 실행될 수 있으며, 파일 내용에 대한 원하는 작업이 완료되기 전에 파일을 삭제합니다. 이러한 경합 상태는 응용 프로그램의 보안에도 영향을 줄 수 있습니다. 예를 들어 인증이 콜백에서 수행되고 인증된 작업이 동기적으로 실행되는 시나리오가 있습니다. 이러한 경합 상태를 제거하기 위해 단일 비차단 함수에서 서로 의존하는 모든 작업을 작성할 수 있습니다. 이렇게 하면 모든 작업이 올바른 순서로 실행되도록 할 수 있습니다. 예를 들어, 위의 코드 예제는 다음과 같이 비 차단 방식으로 작성할 수 있습니다.

설명하다const fs = require('fs');
fs.readFile('/file.txt', (err, data) => {
  // perform actions on file content
  fs.unlink('/file.txt', (err) => {
    if (err) throw err;
  });
});

위 코드에서는 파일 링크를 해제하는 호출과 기타 파일 작업이 동일한 콜백 내에 있습니다. 이는 올바른 작업 순서를 제공합니다.

Perform input validation 입력 검증 수행 

입력 유효성 검사는 애플리케이션 보안의 중요한 부분입니다. 입력 유효성 검사에 실패하면 다양한 유형의 애플리케이션 공격이 발생할 수 있습니다. 여기에는 SQL 삽입, 사이트 간 스크립팅, 명령 삽입, 로컬/원격 파일 포함, 서비스 거부, 디렉터리 탐색, LDAP 삽입 및 기타 여러 삽입 공격이 포함됩니다. 이러한 공격을 방지하려면 먼저 애플리케이션에 대한 입력을 삭제해야 합니다. 가장 좋은 입력 유효성 검사 기술은 허용된 입력 목록을 사용하는 것입니다. 그러나 이것이 가능하지 않은 경우 먼저 예상 입력 방식과 비교하여 입력을 확인하고 위험한 입력을 피해야 합니다. Node.js 애플리케이션에서 입력 유효성 검사를 쉽게 하기 위해 validator 및 express-mongo-sanitize와 같은 몇 가지 모듈이 있습니다. 입력 유효성 검사에 대한 자세한 내용은 입력 유효성 검사 치트 시트를 참조하세요.

JavaScript는 동적 언어이며 프레임워크가 URL을 구문 분석하는 방법에 따라 애플리케이션 코드에서 볼 수 있는 데이터는 다양한 형식을 취할 수 있습니다. 다음은 express.js에서 쿼리 문자열을 구문 분석한 후의 몇 가지 예입니다.

URL URL Content of request.query.foo in code코드의 request.query.foo 내용

?foo=bar 'bar' (string) 'bar'(문자열)
?foo=bar&foo=baz ['bar', 'baz'] (array of string) ['bar', 'baz'](문자열 배열)
?foo[]=bar ['bar'] (array of string) ['bar'](문자열 배열)
?foo[]=bar&foo[]=baz ['bar', 'baz'] (array of string) ['bar', 'baz'](문자열 배열)
?foo[bar]=baz { bar : 'baz' } (object with a key) { bar : 'baz' }(키가 있는 객체)
?foo[]=bar ['bar'] (array of string) ['bar'](문자열 배열)
?foo[]baz=bar ['bar'] (array of string - postfix is lost)['bar'] (문자열 배열 - 접미사가 손실됨)
?foo[][baz]=bar [ { baz: 'bar' } ] (array of object) [ { baz: 'bar' } ] (객체 배열)
?foo[bar][baz]=bar { foo: { bar: { baz: 'bar' } } } (object tree) { foo: { bar: { baz: 'bar' } } }(객체 트리)
?foo[10]=bar&foo[9]=baz [ 'baz', 'bar' ] (array of string - notice order)[ 'baz', 'bar' ] (문자열 배열 - 공지 순서)
?foo[toString]=bar {} (object where calling toString() will fail){}(toString() 호출이 실패하는 개체)

Perform output escaping 출력 이스케이프 수행

입력 유효성 검사 외에도 XSS(교차 사이트 스크립팅) 공격을 방지하려면 애플리케이션을 통해 사용자에게 표시되는 모든 HTML 및 JavaScript 콘텐츠를 이스케이프해야 합니다. escape-html 또는 node-esapi 라이브러리를 사용하여 출력 이스케이프를 수행할 수 있습니다.

Perform application activity logging 애플리케이션 활동 로깅 수행

애플리케이션 활동을 로깅하는 것이 좋습니다. 이를 통해 애플리케이션 런타임 중에 발생한 오류를 더 쉽게 디버그할 수 있습니다. 사고 대응 시 활용이 가능해 보안 문제에도 유용하다. 또한 이러한 로그는 침입 탐지/방지 시스템(IDS/IPS)을 제공하는 데 사용될 수 있습니다. Node.js에는 애플리케이션 활동 로깅을 수행하는 Winston, Bunyan 또는 Pino와 같은 모듈이 있습니다. 이러한 모듈을 사용하면 로그 스트리밍 및 쿼리가 가능하며 포착되지 않은 예외를 처리하는 방법을 제공합니다.

다음 코드를 사용하면 콘솔과 원하는 로그 파일 모두에 애플리케이션 활동을 기록할 수 있습니다.

const logger = new (Winston.Logger) ({
    transports: [
        new (winston.transports.Console)(),
        new (winston.transports.File)({ filename: 'application.log' })
    ],
    level: 'verbose'
});

오류를 별도의 로그 파일에 저장하고 일반 애플리케이션 로그를 다른 로그 파일에 저장할 수 있도록 다양한 전송을 제공할 수 있습니다. 보안 로깅에 대한 추가 정보는  Logging Cheat Sheet에서 확인할 수 있습니다.

Monitor the event loop 이벤트 루프 모니터링

애플리케이션 서버에 네트워크 트래픽이 많으면 사용자에게 서비스를 제공하지 못할 수도 있습니다. 이는 본질적으로  Denial of Service (DoS) 공격입니다.  toobusy-js 모듈을 사용하면 이벤트 루프를 모니터링할 수 있습니다. 응답 시간을 추적하고, 특정 임계값을 초과하면 이 모듈은 서버가 너무 바쁨을 나타낼 수 있습니다. 이 경우 수신 요청 처리를 중지하고 503 Server Too Busy 메시지를 보내 애플리케이션이 계속 응답하도록 할 수 있습니다.  toobusy-js 모듈의 사용 예는 다음과 같습니다.

const toobusy = require('toobusy-js');
const express = require('express');
const app = express();
app.use(function(req, res, next) {
    if (toobusy()) {
        // log if you see necessary
        res.status(503).send("Server Too Busy");
    } else {
    next();
    }
});

Take precautions against brute-forcing무차별 대입에 대비하세요

무차별 대입Brute-forcing은 모든 웹 애플리케이션에 대한 일반적인 위협입니다. 공격자는 계정 비밀번호를 얻기 위해 비밀번호 추측 공격으로 무차별 대입 공격을 사용할 수 있습니다. 따라서 애플리케이션 개발자는 특히 로그인 페이지에서 무차별 대입 공격에 대해 예방 조치를 취해야 합니다. Node.js에는 이러한 목적으로 사용할 수 있는 여러 모듈이 있습니다. Express-bouncerexpress-bruterate-limiter는 단지 일부 예일 뿐입니다. 귀하의 필요와 요구 사항에 따라 이러한 모듈 중 하나 이상을 선택하고 그에 따라 사용해야 합니다. Express-bouncer and express-brute 모듈은 비슷하게 작동합니다. 실패한 각 요청에 대한 지연 시간을 늘리고 특정 경로에 맞게 조정될 수 있습니다. 이러한 모듈은 다음과 같이 사용할 수 있습니다.

const bouncer = require('express-bouncer');
bouncer.whitelist.push('127.0.0.1'); // allow an IP address
// give a custom error message
bouncer.blocked = function (req, res, next, remaining) {
    res.status(429).send("Too many requests have been made. Please wait " + remaining/1000 + " seconds.");
};
// route to protect
app.post("/login", bouncer.block, function(req, res) {
    if (LoginFailed){  }
    else {
        bouncer.reset( req );
    }
});
const ExpressBrute = require('express-brute');

const store = new ExpressBrute.MemoryStore(); // stores state locally, don't use this in production
const bruteforce = new ExpressBrute(store);

app.post('/auth',
    bruteforce.prevent, // error 429 if we hit this route too often
    function (req, res, next) {
        res.send('Success!');
    }
);

express-bouncer 및 express-brute 외에도 속도 제한기 모듈은 무차별 대입 공격을 방지하는 데 도움이 될 수 있습니다. 특정 기간 동안 특정 IP 주소가 만들 수 있는 요청 수를 지정할 수 있습니다.

const limiter = new RateLimiter();
limiter.addLimit('/login', 'GET', 5, 500); // login page can be requested 5 times at max within 500 seconds

CAPTCHA 사용은 무차별 대입에 사용되는 또 다른 일반적인 메커니즘이기도 합니다. Node.js CAPTCHA용으로 개발된 모듈이 있습니다. Node.js 애플리케이션에 사용되는 일반적인 모듈은 svg-captcha입니다. 다음과 같이 사용할 수 있습니다.

const svgCaptcha = require('svg-captcha');
app.get('/captcha', function (req, res) {
    const captcha = svgCaptcha.create();
    req.session.captcha = captcha.text;
    res.type('svg');
    res.status(200).send(captcha.data);
});

Account lockout은 공격자가 유효한 사용자로부터 접근하지 못하도록 하기 위해 권장되는 솔루션입니다.  mongoose와 같은 많은 모듈에서는 계정 잠금이 가능합니다. 이 블로그 게시물을(this blog post) 참조하여 몽구스에서 계정 잠금이 구현되는 방법을 확인할 수 있습니다.

Use Anti-CSRF tokens Anti-CSRF 토큰 사용

Cross-Site Request Forgery (CSRF) aims to perform authorized actions on behalf of an authenticated user, while the user is unaware of this action. CSRF attacks are generally performed for state-changing requests like changing a password, adding users or placing orders. Csurf is an express middleware that has been used to mitigate CSRF attacks. But a security hole in this package has been recently discovered. The team behind the package has not fixed the discovered vulnerability and they have marked the package as deprecated, recommending using any other CSRF protection package.

CSRF(Cross-Site Request Forgery)는 인증된 사용자를 대신하여 승인된 작업을 수행하는 것을 목표로 하지만 사용자는 이 작업을 인식하지 못합니다. CSRF 공격은 일반적으로 비밀번호 변경, 사용자 추가 또는 주문과 같은 상태 변경 요청에 대해 수행됩니다. Csurf는 CSRF 공격을 완화하는 데 사용되는 Express 미들웨어입니다. 하지만 최근 이 패키지의 보안 허점이 발견되었습니다. 패키지 팀은 발견된 취약점을 수정하지 않았으며 해당 패키지를 더 이상 사용되지 않는 것으로 표시하여 다른 CSRF 보호 패키지를 사용할 것을 권장했습니다.

For detailed information on cross-site request forgery (CSRF) attacks and prevention methods, you can refer to Cross-Site Request Forgery Prevention.

크로스 사이트 요청 위조(CSRF) 공격 및 방지 방법에 대한 자세한 내용은 크로스 사이트 요청 위조 방지를 참조하세요.

Remove unnecessary routes 불필요한 경로 제거

A web application should not contain any page that is not used by users, as it may increase the attack surface of the application. Therefore, all unused API routes should be disabled in Node.js applications. This occurs especially in frameworks like Sails and Feathers, as they automatically generate REST API endpoints. For example, in Sails, if a URL does not match a custom route, it may match one of the automatic routes and still generate a response. This situation may lead to results ranging from information leakage to arbitrary command execution. Therefore, before using such frameworks and modules, it is important to know the routes they automatically generate and remove or disable these routes.

웹 애플리케이션에는 사용자가 사용하지 않는 페이지가 포함되어서는 안 됩니다. 애플리케이션의 공격 표면이 증가할 수 있기 때문입니다. 따라서 사용되지 않는 모든 API 경로는 Node.js 애플리케이션에서 비활성화되어야 합니다. 이는 특히 Sails 및 Feathers와 같은 프레임워크에서 REST API 엔드포인트를 자동으로 생성하므로 발생합니다. 예를 들어 Sails에서 URL이 사용자 지정 경로와 일치하지 않으면 자동 경로 중 하나와 일치하고 여전히 응답을 생성할 수 있습니다. 이러한 상황은 정보 유출부터 임의 명령 실행까지 다양한 결과를 초래할 수 있습니다. 따라서 이러한 프레임워크와 모듈을 사용하기 전에 자동으로 생성되는 경로를 알고 이러한 경로를 제거하거나 비활성화하는 것이 중요합니다.

Prevent HTTP Parameter PollutionHTTP 매개변수 오염 방지

HTTP Parameter Pollution(HPP) is an attack in which attackers send multiple HTTP parameters with the same name and this causes your application to interpret them unpredictably. When multiple parameter values are sent, Express populates them in an array. In order to solve this issue, you can use hpp module. When used, this module will ignore all values submitted for a parameter in req.query and/or req.body and just select the last parameter value submitted. You can use it as follows:

HTTP 매개변수 오염(HPP)은 공격자가 동일한 이름으로 여러 HTTP 매개변수를 전송하여 애플리케이션이 이를 예측할 수 없게 해석하게 만드는 공격입니다. 여러 매개변수 값이 전송되면 Express는 이를 배열에 채웁니다. 이 문제를 해결하기 위해 hpp 모듈을 사용할 수 있습니다. 이 모듈을 사용하면 req.query 및/또는 req.body의 매개변수에 대해 제출된 모든 값을 무시하고 제출된 마지막 매개변수 값만 선택합니다. 다음과 같이 사용할 수 있습니다.

const hpp = require('hpp');
app.use(hpp());

Only return what is necessary 필요한 것만 반환

Information about the users of an application is among the most critical information about the application. User tables generally include fields like id, username, full name, email address, birth date, password and in some cases social security numbers. Therefore, when querying and using user objects, you need to return only needed fields as it may be vulnerable to personal information disclosure. This is also correct for other objects stored on the database. If you just need a certain field of an object, you should only return the specific fields required. As an example, you can use a function like the following whenever you need to get information on a user. By doing so, you can only return the fields that are needed for your specific operation. In other words, if you only need to list names of the users available, you are not returning their email addresses or credit card numbers in addition to their full names.

애플리케이션 사용자에 대한 정보는 애플리케이션에 대한 가장 중요한 정보 중 하나입니다. 사용자 테이블에는 일반적으로 ID, 사용자 이름, 전체 이름, 이메일 주소, 생년월일, 비밀번호 및 경우에 따라 주민등록번호와 같은 필드가 포함됩니다. 따라서 사용자 객체를 조회하여 사용할 경우에는 개인정보 유출에 취약할 수 있으므로 꼭 필요한 필드만 반환해 주셔야 합니다. 이는 데이터베이스에 저장된 다른 개체에도 적용됩니다. 객체의 특정 필드만 필요한 경우 필요한 특정 필드만 반환해야 합니다. 예를 들어, 사용자에 대한 정보를 얻어야 할 때마다 다음과 같은 함수를 사용할 수 있습니다. 이렇게 하면 특정 작업에 필요한 필드만 반환할 수 있습니다. 즉, 사용 가능한 사용자의 이름만 나열하면 전체 이름 외에 이메일 주소나 신용 카드 번호가 반환되지 않습니다.

exports.sanitizeUser = function(user) {
  return {
    id: user.id,
    username: user.username,
    fullName: user.fullName
  };
};

Use object property descriptors 객체 속성 설명자 사용

Object properties include three hidden attributes: writable (if false, property value cannot be changed), enumerable (if false, property cannot be used in for loops) and configurable (if false, property cannot be deleted). When defining an object property through assignment, these three hidden attributes are set to true by default. These properties can be set as follows:

객체 속성에는 세 가지 숨겨진 속성이 포함됩니다: writable(false인 경우 속성 값을 변경할 수 없음), enumerable(false인 경우 for 루프에서 속성을 사용할 수 없음) 및 (false인 경우 속성을 삭제할 수 없습니다). 할당을 통해 객체 속성을 정의할 때 이러한 세 가지 숨겨진 속성은 기본적으로 true로 설정됩니다. 이러한 속성은 다음과 같이 설정할 수 있습니다.

const o = {};
Object.defineProperty(o, "a", {
    writable: true,
    enumerable: true,
    configurable: true,
    value: "A"
});

Apart from these, there are some special functions for object attributes. Object.preventExtensions() prevents new properties from being added to the object.

이 외에도 객체 속성에 대한 몇 가지 특수 기능이 있습니다. Object.preventExtensions()은 새 속성이 개체에 추가되는 것을 방지합니다.

Use access control lists 액세스 제어 목록 사용

Authorization prevents users from acting outside of their intended permissions. In order to do so, users and their roles should be determined with consideration of the principle of least privilege. Each user role should only have access to the resources they must use. For your Node.js applications, you can use the acl module to provide ACL (access control list) implementation. With this module, you can create roles and assign users to these roles.

권한 부여는 사용자가 의도한 권한을 벗어나는 행위를 방지합니다. 그러기 위해서는 최소 권한의 원칙을 고려하여 사용자와 역할을 결정해야 합니다. 각 사용자 역할은 사용해야 하는 리소스에만 액세스할 수 있어야 합니다. Node.js 애플리케이션의 경우 acl 모듈을 사용하여 ACL(액세스 제어 목록) 구현을 제공할 수 있습니다. 이 모듈을 사용하면 역할을 생성하고 이러한 역할에 사용자를 할당할 수 있습니다.

Error & Exception Handling 오류 및 예외 처리

Handle uncaughtException uncaughtException 처리

Node.js behavior for uncaught exceptions is to print current stack trace and then terminate the thread. However, Node.js allows customization of this behavior. It provides a global object named process that is available to all Node.js applications. It is an EventEmitter object and in case of an uncaught exception, uncaughtException event is emitted and it is brought up to the main event loop. In order to provide a custom behavior for uncaught exceptions, you can bind to this event. However, resuming the application after such an uncaught exception can lead to further problems. Therefore, if you do not want to miss any uncaught exception, you should bind to uncaughtException event and cleanup any allocated resources like file descriptors, handles and similar before shutting down the process. Resuming the application is strongly discouraged as the application will be in an unknown state. It is important to note that when displaying error messages to the user in case of an uncaught exception, detailed information like stack traces should not be revealed to the user. Instead, custom error messages should be shown to the users in order not to cause any information leakage.

catch되지 않은 예외에 대한 Node.js 동작은 현재 스택 추적을 인쇄한 다음 스레드를 종료하는 것입니다. 그러나 Node.js에서는 이 동작을 사용자 지정할 수 있습니다. 모든 Node.js 응용 프로그램에서 사용할 수 있는 process라는 전역 개체를 제공합니다. EventEmitter 객체이며 포착되지 않은 예외의 경우 uncaughtException 이벤트가 발생하고 메인 이벤트 루프로 가져옵니다. catch되지 않은 예외에 대한 사용자 지정 동작을 제공하려면 이 이벤트에 바인딩할 수 있습니다. 그러나 이러한 포착되지 않은 예외 후에 응용 프로그램을 다시 시작하면 추가 문제가 발생할 수 있습니다. 따라서 잡히지 않은 예외를 놓치지 않으려면 프로세스를 종료하기 전에 uncaughtException 이벤트에 바인딩하고 파일 설명자, 핸들 등과 같은 할당된 리소스를 정리해야 합니다. 응용 프로그램이 알 수 없는 상태가 되므로 응용 프로그램을 다시 시작하지 않는 것이 좋습니다. catch되지 않은 예외가 발생한 경우 사용자에게 오류 메시지를 표시할 때 스택 추적과 같은 자세한 정보가 사용자에게 공개되어서는 안 됩니다. 대신 정보 유출을 방지하기 위해 사용자 지정 오류 메시지를 사용자에게 표시해야 합니다.

process.on("uncaughtException", function(err) {
    // clean up allocated resources
    // log necessary error details to log files
    process.exit(); // exit the process to avoid unknown state
});

Listen to errors when using EventEmitter EventEmitter 사용 시 오류 듣기

When using EventEmitter, errors can occur anywhere in the event chain. Normally, if an error occurs in an EventEmitter object, an error event that has an Error object as an argument is called. However, if there are no attached listeners to that error event, the Error object that is sent as an argument is thrown and becomes an uncaught exception. In short, if you do not handle errors within an EventEmitter object properly, these unhandled errors may crash your application. Therefore, you should always listen to error events when using EventEmitter objects.

EventEmitter를 사용하면 이벤트 체인 어디에서나 오류가 발생할 수 있습니다. 일반적으로 EventEmitter 객체에 오류가 발생하면 Error 객체를 인수로 갖는 오류 이벤트가 호출됩니다. 그러나 해당 오류 이벤트에 연결된 리스너가 없으면 인수로 전송된 Error 개체가 발생하고 포착되지 않는 예외가 됩니다. 즉, EventEmitter 객체 내에서 오류를 적절하게 처리하지 않으면 처리되지 않은 오류로 인해 애플리케이션이 중단될 수 있습니다. 따라서 EventEmitter 객체를 사용할 때는 항상 오류 이벤트를 수신해야 합니다.

const events = require('events');
const myEventEmitter = function(){
    events.EventEmitter.call(this);
}
require('util').inherits(myEventEmitter, events.EventEmitter);
myEventEmitter.prototype.someFunction = function(param1, param2) {
    //in case of an error
    this.emit('error', err);
}
const emitter = new myEventEmitter();
emitter.on('error', function(err){
    //Perform necessary error handling here
});

Handle errors in asynchronous calls 비동기 호출의 오류 처리

Errors that occur within asynchronous callbacks are easy to miss. Therefore, as a general principle first argument to the asynchronous calls should be an Error object. Also, express routes handle errors itself, but it should be always remembered that errors occurred in asynchronous calls made within express routes are not handled, unless an Error object is sent as a first argument.

비동기 콜백 내에서 발생하는 오류는 놓치기 쉽습니다. 따라서 일반적으로 비동기 호출에 대한 첫 번째 인수는 Error 개체여야 합니다. 또한 Express Route는 오류 자체를 처리하지만, Error 개체가 첫 번째 인수로 전송되지 않는 한 Express Route 내에서 이루어진 비동기 호출에서 발생한 오류는 처리되지 않는다는 점을 항상 기억해야 합니다.

Errors in these callbacks can be propagated as many times as possible. Each callback that the error has been propagated to can ignore, handle or propagate the error.

이러한 콜백의 오류는 가능한 한 많이 전파될 수 있습니다. 오류가 전파된 각 콜백은 오류를 무시, 처리 또는 전파할 수 있습니다.

Server Security 서버 보안

Set cookie flags appropriately 쿠키 플래그를 적절하게 설정하십시오.

Generally, session information is sent using cookies in web applications. However, improper use of HTTP cookies can render an application to several session management vulnerabilities. Some flags can be set for each cookie to prevent these kinds of attacks. httpOnly, Secure and SameSite flags are very important for session cookies. httpOnly flag prevents the cookie from being accessed by client-side JavaScript. This is an effective counter-measure for XSS attacks. Secure flag lets the cookie to be sent only if the communication is over HTTPS. SameSite flag can prevent cookies from being sent in cross-site requests that helps protect against Cross-Site Request Forgery (CSRF) attacks. Apart from these, there are other flags like domain, path and expires. Setting these flags appropriately is encouraged, but they are mostly related to cookie scope not the cookie security. Sample usage of these flags is given in the following example:

일반적으로 세션 정보는 웹 애플리케이션에서 쿠키를 사용하여 전송됩니다. 그러나 HTTP 쿠키를 부적절하게 사용하면 애플리케이션이 여러 세션 관리 취약점에 노출될 수 있습니다. 이러한 종류의 공격을 방지하기 위해 각 쿠키에 일부 플래그를 설정할 수 있습니다. httpOnly, Secure 및 SameSite 플래그는 세션 쿠키에 매우 중요합니다. httpOnly 플래그는 클라이언트 측 JavaScript가 쿠키에 액세스하는 것을 방지합니다. 이는 XSS 공격에 대한 효과적인 대응책입니다. Secure 플래그를 사용하면 통신이 HTTPS를 통해 이루어지는 경우에만 쿠키가 전송됩니다. SameSite 플래그는 교차 사이트 요청 위조(CSRF) 공격으로부터 보호하는 데 도움이 되는 교차 사이트 요청에서 쿠키가 전송되는 것을 방지할 수 있습니다. 이 외에도 도메인, 경로 및 만료와 같은 다른 플래그가 있습니다. 이러한 플래그를 적절하게 설정하는 것이 좋지만 대부분 쿠키 보안이 아닌 쿠키 범위와 관련이 있습니다. 다음 예에서는 이러한 플래그의 샘플 사용법을 제공합니다.

const session = require('express-session');
app.use(session({
    secret: 'your-secret-key',
    name: 'cookieName',
    cookie: { secure: true, httpOnly: true, path: '/user', sameSite: true}
}));

Use appropriate security headers 적절한 보안 헤더 사용

There are several HTTP security headers that can help you prevent some common attack vectors. The helmet package can help to set those headers:

몇 가지 일반적인 공격 벡터를 방지하는 데 도움이 되는 몇 가지 HTTP 보안 헤더가 있습니다. 헬멧 패키지는 이러한 헤더를 설정하는 데 도움이 될 수 있습니다.

const express = require("express");
const helmet = require("helmet");

const app = express();

app.use(helmet()); // Add various HTTP headers

The top-level helmet function is a wrapper around 14 smaller middlewares. Bellow is a list of HTTP security headers covered by helmet middlewares:

최상위 helmet 함수는 14개의 작은 미들웨어를 둘러싼 래퍼입니다. Bellow는 미들웨어에서 helmet 다루는 HTTP 보안 헤더 목록입니다.

  • Strict-Transport-SecurityHTTP Strict Transport Security (HSTS) dictates browsers that the application can only be accessed via HTTPS connections. In order to use it in your application, add the following codes:Strict-Transport-Security:
  • HTTP Strict Transport Security(HSTS)는 HTTPS 연결을 통해서만 애플리케이션에 액세스할 수 있도록 브라우저에 지시합니다. 응용 프로그램에서 사용하려면 다음 코드를 추가합니다.
app.use(helmet.hsts()); // default configuration
app.use(
  helmet.hsts({
    maxAge: 123456,
    includeSubDomains: false,
  })
); // custom configuration
  • **X-Frame-Options:** determines if a page can be loaded via a <frame> or an <iframe> element. Allowing the page to be framed may result in Clickjacking attacks.X-Frame-Options:
  • <frame> 또는 <iframe> 요소를 통해 페이지를 로드할 수 있는지 여부를 결정합니다. 페이지를 프레이밍하도록 허용하면 클릭재킹 공격이 발생할 수 있습니다.
app.use(helmet.frameguard()); // default behavior (SAMEORIGIN)
  • **X-XSS-Protection:** stops pages from loading when they detect reflected cross-site scripting (XSS) attacks. This header has been deprecated by modern browsers and its use can introduce additional security issues on the client side. As such, it is recommended to set the header as X-XSS-Protection: 0 in order to disable the XSS Auditor, and not allow it to take the default behavior of the browser handling the response.X-XSS-Protection:
  • 반사된 XSS(교차 사이트 스크립팅) 공격을 감지하면 페이지 로드를 중지합니다. 이 헤더는 최신 브라우저에서 더 이상 사용되지 않으며 사용하면 클라이언트 측에서 추가 보안 문제가 발생할 수 있습니다. 따라서 XSS Auditor를 비활성화하고 응답을 처리하는 브라우저의 기본 동작을 사용하지 않도록 하려면 헤더를 X-XSS-Protection: 0으로 설정하는 것이 좋습니다.
app.use(helmet.xssFilter()); // sets "X-XSS-Protection: 0"

For moderns browsers, it is recommended to implement a strong Content-Security-Policy policy, as detailed in the next section.

최신 브라우저의 경우 다음 섹션에 설명된 대로 강력한 Content-Security-Policy 정책을 구현하는 것이 좋습니다.

  • **Content-Security-Policy:** Content Security Policy is developed to reduce the risk of attacks like Cross-Site Scripting (XSS) and Clickjacking. It allows content from a list that you decide. It has several directives each of which prohibits loading specific type of a content. You can refer to Content Security Policy Cheat Sheet for detailed explanation of each directive and how to use it. You can implement these settings in your application as follows:
  • Content-Security-Policy: Content Security Policy는 XSS(Cross-Site Scripting) 및 클릭재킹과 같은 공격의 위험을 줄이기 위해 개발되었습니다. 결정한 목록의 콘텐츠를 허용합니다. 여기에는 여러 지시문이 있으며, 각 지시문은 특정 유형의 콘텐츠를로드하는 것을 금지합니다. 각 지시문 및 사용 방법에 대한 자세한 설명은 Content Security Policy Cheat Sheet를 참조하십시오. 다음과 같이 응용 프로그램에서 이러한 설정을 구현할 수 있습니다.
app.use(
  helmet.contentSecurityPolicy({
    // the following directives will be merged into the default helmet CSP policy
    directives: {
      defaultSrc: ["'self'"],  // default value for all directives that are absent
      scriptSrc: ["'self'"],   // helps prevent XSS attacks
      frameAncestors: ["'none'"],  // helps prevent Clickjacking attacks
      imgSrc: ["'self'", "'<http://imgexample.com>'"],
      styleSrc: ["'none'"]
    }
  })
);

As this middleware performs very little validation, it is recommended to rely on CSP checkers like CSP Evaluator instead.

이 미들웨어는 유효성 검사를 거의 수행하지 않으므로 CSP Evaluator와 같은 CSP 검사기를 사용하는 것이 좋습니다.

  • **X-Content-Type-Options:** Even if the server sets a valid Content-Type header in the response, browsers may try to sniff the MIME type of the requested resource. This header is a way to stop this behavior and tell the browser not to change MIME types specified in Content-Type header. It can be configured in the following way:X-Content-Type-Options: 서버가 응답에 유효한 Content-Type 헤더를 설정하더라도 브라우저는 요청된 리소스의 MIME 유형을 스니핑하려고 시도할 수 있습니다. 이 헤더는 이 동작을 중지하고 header에 지정된 MIME 유형을 변경하지 않도록 브라우저에 지시하는 Content-Type 방법입니다. 다음과 같은 방법으로 구성할 수 있습니다.
app.use(helmet.noSniff());
  • **Cache-Control and Pragma:** Cache-Control header can be used to prevent browsers from caching the given responses. This should be done for pages that contain sensitive information about either the user or the application. However, disabling caching for pages that do not contain sensitive information may seriously affect the performance of the application. Therefore, caching should only be disabled for pages that return sensitive information. Appropriate caching controls and headers can be set easily using the nocache package:
  • Cache-Control 및 Pragma: Cache-Control 헤더를 사용하여 브라우저가 주어진 응답을 캐싱하지 못하도록 할 수 있습니다. 사용자 또는 응용 프로그램에 대한 중요한 정보가 포함된 페이지에 대해 이 작업을 수행해야 합니다. 그러나 중요한 정보가 포함되지 않은 페이지에 대해 캐싱을 사용하지 않도록 설정하면 응용 프로그램의 성능에 심각한 영향을 줄 수 있습니다. 따라서 중요한 정보를 반환하는 페이지에 대해서만 캐싱을 사용하지 않도록 설정해야 합니다. 적절한 캐싱 컨트롤과 헤더는 nocache 패키지를 사용하여 쉽게 설정할 수 있습니다.
const nocache = require("nocache");

app.use(nocache());

The above code sets Cache-Control, Surrogate-Control, Pragma and Expires headers accordingly.

위의 코드는 그에 따라 Cache-Control, Surrogate-Control, Pragma 및 Expires 헤더를 설정합니다.

  • X-Download-Options: This header prevents Internet Explorer from executing downloaded files in the site's context. This is achieved with noopen directive. You can do so with the following piece of code:X-Download-Options:
  • 이 헤더는 Internet Explorer가 사이트의 컨텍스트에서 다운로드된 파일을 실행하지 못하도록 합니다. 이것은 noopen 지시문을 사용하여 달성됩니다. 다음 코드를 사용하여 이 작업을 수행할 수 있습니다.
app.use(helmet.ieNoOpen());
  • **Expect-CT:** Certificate Transparency is a new mechanism developed to fix some structural problems regarding current SSL infrastructure. Expect-CT header may enforce certificate transparency requirements. It can be implemented in your application as follows:Expect-CT: 인증서 투명성은 현재 SSL 인프라와 관련된 몇 가지 구조적 문제를 해결하기 위해 개발된 새로운 메커니즘입니다. Expect-CT 헤더는 인증서 투명성 요구 사항을 적용할 수 있습니다. 응용 프로그램에서 다음과 같이 구현할 수 있습니다.
const expectCt = require('expect-ct');
app.use(expectCt({ maxAge: 123 }));
app.use(expectCt({ enforce: true, maxAge: 123 }));
app.use(expectCt({ enforce: true, maxAge: 123, reportUri: '<http://example.com>'}));
  • X-Powered-By: X-Powered-By header is used to inform what technology is used in the server side. This is an unnecessary header causing information leakage, so it should be removed from your application. To do so, you can use the hidePoweredBy as follows:X-Powered-By: X-Powered-By 헤더는 서버 측에서 어떤 기술이 사용되는지 알려주는 데 사용됩니다. 이 헤더는 정보 유출을 유발하는 불필요한 헤더이므로 애플리케이션에서 제거해야 합니다. 이를 위해 다음과 같이 hidePoweredBy을 사용할 수 있습니다:
app.use(helmet.hidePoweredBy());

Also, you can lie about the technologies used with this header. For example, even if your application does not use PHP, you can set X-Powered-By header to seem so.또한 이 헤더에 사용된 기술에 대해 거짓말을 할 수도 있습니다. 예를 들어 애플리케이션에서 PHP를 사용하지 않더라도 X-Powered-By 헤더를 그렇게 보이도록 설정할 수 있습니다.

app.use(helmet.hidePoweredBy({ setTo: 'PHP 4.2.0' }));

Platform Security 플랫폼 보안

Keep your packages up-to-date 패키지를 최신 상태로 유지

Security of your application depends directly on how secure the third-party packages you use in your application are. Therefore, it is important to keep your packages up-to-date. It should be noted that Using Components with Known Vulnerabilities is still in the OWASP Top 10. You can use OWASP Dependency-Check to see if any of the packages used in the project has a known vulnerability. Also, you can use Retire.js to check JavaScript libraries with known vulnerabilities.애플리케이션의 보안은 애플리케이션에서 사용하는 타사 패키지의 보안 수준에 따라 직접적으로 달라집니다. 따라서 패키지를 최신 상태로 유지하는 것이 중요합니다. 알려진 취약점이 있는 구성 요소 사용은 여전히 OWASP 상위 10위 안에 있다는 점에 유의해야 합니다. 프로젝트에 사용된 패키지 중 알려진 취약점이 있는지 확인하려면 OWASP Dependency-Check를 사용할 수 있습니다. 또한 Retire.js를 사용하여 알려진 취약점이 있는 JavaScript 라이브러리를 확인할 수 있습니다.

Starting with version 6, npm introduced audit, which will warn about vulnerable packages:버전 6부터 npm에 취약한 패키지에 대해 경고하는 audit이 도입되었습니다:

npm audit

npm also introduced a simple way to upgrade the affected packages:

npm에서는 영향을 받는 패키지를 업그레이드하는 간단한 방법도 소개했습니다:

npm audit fix

There are several other tools you can use to check your dependencies. A more comprehensive list can be found in Vulnerable Dependency Management CS.

종속성을 확인하는 데 사용할 수 있는 몇 가지 다른 도구가 있습니다. 보다 포괄적인 목록은 취약한 종속성 관리 CS에서 확인할 수 있습니다.

Do not use dangerous functions위험한 기능을 사용하지 마세요

There are some JavaScript functions that are dangerous and should only be used where necessary or unavoidable. The first example is the eval() function. This function takes a string argument and executes it as any other JavaScript source code. Combined with user input, this behavior inherently leads to remote code execution vulnerability. Similarly, calls to child_process.exec are also very dangerous. This function acts as a bash interpreter and sends its arguments to /bin/sh. By injecting input to this function, attackers can execute arbitrary commands on the server.위험하고 필요하거나 불가피한 경우에만 사용해야 하는 일부 JavaScript 함수가 있습니다. 첫 번째 예는 함수입니다eval(). 이 함수는 문자열 인수를 가져와서 다른 JavaScript 소스 코드처럼 실행합니다. 사용자 입력과 결합된 이 동작은 본질적으로 원격 코드 실행 취약성으로 이어집니다. 마찬가지로, 전화 통화 child_process.exec 도 매우 위험합니다. 이 함수는 bash 인터프리터 역할을 하며 인수를 /bin/sh로 보냅니다. 공격자는 이 함수에 입력을 삽입하여 서버에서 임의의 명령을 실행할 수 있습니다.

In addition to these functions, some modules require special care when being used. As an example, fs module handles filesystem operations. However, if improperly sanitized user input is fed into this module, your application may become vulnerable to file inclusion and directory traversal vulnerabilities. Similarly, vm module provides APIs for compiling and running code within V8 Virtual Machine contexts. Since it can perform dangerous actions by nature, it should be used within a sandbox.이러한 기능 외에도 일부 모듈은 사용할 때 특별한 주의가 필요합니다. 예를 들어, module은 fs 파일 시스템 작업을 처리합니다. 그러나 부적절하게 삭제된 사용자 입력이 이 모듈에 공급되면 애플리케이션이 파일 포함 및 디렉터리 통과 취약성에 취약해질 수 있습니다. 마찬가지로 module은 vm V8 가상 머신 컨텍스트 내에서 코드를 컴파일하고 실행하기 위한 API를 제공합니다. 본질적으로 위험한 작업을 수행할 수 있으므로 샌드박스 내에서 사용해야 합니다.

It would not be fair to say that these functions and modules should not be used whatsoever, however, they should be used carefully especially when they use with user input. Also, there are some other functions that may render your application vulnerable.이러한 함수와 모듈을 전혀 사용해서는 안된다고 말하는 것은 공평하지 않지만 특히 사용자 입력과 함께 사용할 때는 신중하게 사용해야합니다. 또한 응용 프로그램을 취약하게 만들 수 있는 몇 가지 다른 기능이 있습니다.

Stay away from evil regexes사악한 정규식을 멀리하십시오.

The Regular expression Denial of Service (ReDoS) is a Denial of Service attack, that exploits the fact that most Regular Expression implementations may reach extreme situations that cause them to work very slowly (exponentially related to input size). An attacker can then cause a program using a Regular Expression to enter these extreme situations and then hang for a very long time.정규식 ReDoS(Denial of Service)는 서비스 거부 공격으로, 대부분의 정규식 구현이 매우 느리게 작동하게 하는 극단적인 상황에 도달할 수 있다는 사실을 악용합니다(기하급수적으로 입력 크기와 관련됨). 그런 다음 공격자는 정규식을 사용하는 프로그램이 이러한 극단적인 상황에 빠지도록 한 다음 매우 오랜 시간 동안 중단될 수 있습니다.

The Regular Expression Denial of Service (ReDoS) is a type of Denial of Service attack that uses regular expressions. Some Regular Expression (Regex) implementations cause extreme situations that makes the application very slow. Attackers can use such regex implementations to cause application to get into these extreme situations and hang for a long time. Such regexes are called evil if application can be stuck on crafted input. Generally, these regexes are exploited by grouping with repetition and alternation with overlapping. For example, the following regular expression ^(([a-z])+.)+[A-Z]([a-z])+$ can be used to specify Java class names. However, a very long string (aaaa...aaaaAaaaaa...aaaa) can also match with this regular expression. There are some tools to check if a regex has a potential for causing denial of service. One example is vuln-regex-detector.ReDoS(정규식 서비스 거부)는 정규식을 사용하는 서비스 거부 공격의 한 유형입니다. 일부 정규식(Regex) 구현은 응용 프로그램을 매우 느리게 만드는 극단적인 상황을 유발합니다. 공격자는 이러한 정규식 구현을 사용하여 애플리케이션이 이러한 극단적인 상황에 처하고 오랫동안 중단되도록 할 수 있습니다. 이러한 정규식은 응용 프로그램이 제작 된 입력에 멈출 수있는 경우 악이라고합니다. 일반적으로 이러한 정규식은 반복으로 그룹화하고 겹치기를 번갈아 가며 사용합니다. 예를 들어, 다음 정규식 ^(([a-z])+.)+[A-Z]([a-z])+$ 을 사용하여 Java 클래스 이름을 지정할 수 있습니다. 그러나 매우 긴 문자열(aaaa... 아아아 aaaa)도 이 정규식과 일치할 수 있습니다. 정규식이 서비스 거부를 일으킬 가능성이 있는지 확인하는 몇 가지 도구가 있습니다. 한 가지 예는 vuln-regex-detector입니다.

Run security linters 보안 린터 실행

When developing code, keeping all security tips in mind can be really difficult. Also, keeping all team members obey these rules is nearly impossible. This is why there are Static Analysis Security Testing (SAST) tools. These tools do not execute your code, but they simply look for patterns that can contain security risks. As JavaScript is a dynamic and loosely-typed language, linting tools are really essential in the software development life cycle. The linting rules should be reviewed periodically and the findings should be audited. Another advantage of these tools is the feature that you can add custom rules for patterns that you may see dangerous. ESLint and JSHint are commonly used SAST tools for JavaScript linting.코드를 개발할 때 모든 보안 팁을 염두에 두는 것은 정말 어려울 수 있습니다. 또한 모든 팀원이 이러한 규칙을 준수하도록 하는 것은 거의 불가능합니다. 이것이 정적 분석 보안 테스트(SAST) 도구가 있는 이유입니다. 이러한 도구는 코드를 실행하지 않지만 보안 위험을 포함할 수 있는 패턴을 찾기만 합니다. JavaScript는 동적이고 느슨한 형식의 언어이기 때문에 linting 도구는 소프트웨어 개발 수명 주기에서 정말 중요합니다. 린팅 규칙을 정기적으로 검토하고 결과를 감사해야 합니다. 이러한 도구의 또 다른 장점은 위험할 수 있는 패턴에 대한 사용자 지정 규칙을 추가할 수 있는 기능입니다. ESLint 및 JSHint는 JavaScript linting에 일반적으로 사용되는 SAST 도구입니다.

Use strict mode 엄격 모드 사용

JavaScript has a number of unsafe and dangerous legacy features that should not be used. In order to remove these features, ES5 included a strict mode for developers. With this mode, errors that were silent previously are thrown. It also helps JavaScript engines perform optimizations. With strict mode, previously accepted bad syntax causes real errors. Because of these improvements, you should always use strict mode in your application. In order to enable strict mode, you just need to write "use strict"; on top of your code.JavaScript에는 사용해서는 안 되는 안전하지 않고 위험한 레거시 기능이 많이 있습니다. 이러한 기능을 제거하기 위해 ES5에는 개발자를 위한 엄격 모드가 포함되어 있습니다. 이 모드를 사용하면 이전에 무음이었던 오류가 발생합니다. 또한 JavaScript 엔진이 최적화를 수행하는 데 도움이 됩니다. 엄격 모드를 사용하면 이전에 허용된 잘못된 구문으로 인해 실제 오류가 발생합니다. 이러한 개선 사항으로 인해 응용 프로그램에서 항상 엄격 모드를 사용해야 합니다. 엄격 모드를 사용하려면 코드 위에 작성 "use strict"; 하기만 하면 됩니다.

The following code will generate a ReferenceError: Can't find variable: y on the console, which will not be displayed unless strict mode is used:다음 코드는 엄격 모드를 사용하지 않는 한 콘솔에 표시되지 ReferenceError: Can't find variable: y 않습니다.

"use strict";

func();
function func() {
  y = 3.14;   // This will cause an error (y is not defined)
}

Adhere to general application security principles 일반 애플리케이션 보안 원칙 준수

This list mainly focuses on issues that are common in Node.js applications, with recommendations and examples. In addition to these, there are general security by design principles that apply to web applications regardless of technologies used in application server. You should also keep those principles in mind while developing your applications. You can always refer to OWASP Cheat Sheet Series to learn more about web application vulnerabilities and mitigation techniques used against them.이 목록은 주로 Node.js 응용 프로그램에서 일반적인 문제와 권장 사항 및 예제에 중점을 둡니다. 이 외에도 응용 프로그램 서버에서 사용되는 기술에 관계없이 웹 응용 프로그램에 적용되는 일반적인 설계 보안 원칙이 있습니다. 또한 응용 프로그램을 개발하는 동안 이러한 원칙을 염두에 두어야 합니다. 언제든지 OWASP 치트 시트 시리즈를 참조하여 웹 애플리케이션 취약성 및 이에 사용되는 완화 기술에 대해 자세히 알아볼 수 있습니다.