> 웹 프론트엔드 > JS 튜토리얼 > Node.js 애플리케이션 보안: 종합 가이드

Node.js 애플리케이션 보안: 종합 가이드

Patricia Arquette
풀어 주다: 2024-12-08 14:27:10
원래의
374명이 탐색했습니다.

Securing Your Node.js Application: A Comprehensive Guide

오늘날의 디지털 환경에서는 Node.js 애플리케이션의 보안이 무엇보다 중요합니다. Netflix 및 Uber와 같은 글로벌 리더부터 차세대 혁신을 구축하는 스타트업에 이르기까지 Node.js는 가장 까다로운 고성능 애플리케이션을 지원합니다. 그러나 애플리케이션의 취약점으로 인해 무단 액세스, 데이터 침해 및 사용자 신뢰 상실이 발생할 수 있습니다.

이 가이드는 실용적인 보안 사례와 OWASP 웹 보안 테스트 가이드(WSTG)의 주요 개념을 결합하여 Node.js 애플리케이션을 강화하는 데 도움을 줍니다. 실시간 운영을 관리하든 수백만 명의 사용자로 확장하든 이 포괄적인 리소스는 애플리케이션의 보안, 신뢰성 및 탄력성을 유지하도록 보장합니다.


정보 수집(WSTG-INFO)

정보 수집은 공격자가 애플리케이션에 대해 자세히 알아내기 위해 취하는 첫 번째 단계인 경우가 많습니다. 더 많은 정보를 수집할수록 취약점을 식별하고 악용하는 것이 더 쉬워집니다.

일반적인 Express.js 서버 구성 및 핑거프린팅

기본적으로 Express.js에는 서버에 대한 정보를 실수로 공개할 수 있는 설정이 포함되어 있습니다. 일반적인 예는 애플리케이션이 Express를 사용하고 있음을 나타내는 X-Powered-By HTTP 헤더입니다.

취약 코드 예:

const express = require('express');
const app = express();

// Your routes here

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

이 설정에서는 모든 HTTP 응답에 X-Powered-By: Express 헤더가 포함됩니다.

문제:

  • 핑거프린팅: 공격자는 이 헤더를 사용하여 사용 중인 기술을 확인할 수 있습니다. Express를 실행하고 있다는 사실을 알면 Express 또는 Node.js의 특정 버전에서 알려진 취약점에 대한 공격을 맞춤화할 수 있습니다.

완화:

공격자가 서버의 지문을 채취하기 어렵게 하려면 이 헤더를 비활성화하세요.

개선된 코드:

const express = require('express');
const app = express();

// Disable the X-Powered-By header
app.disable('x-powered-by');

// Your routes here

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

헬멧으로 완화 강화:

더 나은 접근 방식은 다양한 HTTP 헤더를 설정하여 앱 보안을 향상시키는 헬멧 미들웨어를 사용하는 것입니다.

const express = require('express');
const helmet = require('helmet');
const app = express();

// Use Helmet to secure headers
app.use(helmet());

// Your routes here

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

헬멧을 쓰는 이유는 무엇인가요?

  • 포괄적인 보안 헤더: 헬멧은 잘 알려진 웹 취약성으로부터 앱을 보호하는 데 도움이 되는 여러 HTTP 헤더를 설정합니다.
  • 사용 편의성: 단 한 줄로 애플리케이션의 보안 상태를 크게 향상할 수 있습니다.

구성 및 배포 관리 테스트(WSTG-CONF)

구성 및 배포 관리는 애플리케이션 보안의 중요한 측면입니다. 잘못된 구성은 공격자에게 문을 열어줄 수 있습니다.

프로덕션에서 개발 모드로 실행

프로덕션 서버에서 개발 모드로 애플리케이션을 실행하면 자세한 오류 메시지와 스택 추적이 노출될 수 있습니다.

취약 코드 예:

const express = require('express');
const app = express();

// Your routes here

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

이 설정에서는 자세한 오류 메시지가 클라이언트로 전송됩니다.

문제:

  • 정보 유출: 자세한 오류 메시지와 스택 추적을 통해 애플리케이션의 구조, 종속성, 파일 경로에 대한 민감한 정보가 드러날 수 있습니다.
  • 악용 촉진: 공격자는 이 정보를 사용하여 잠재적인 취약점을 식별하고 표적 공격을 수행할 수 있습니다.

완화:

NODE_ENV를 '프로덕션'으로 설정하고 프로덕션에서 일반 오류 메시지를 사용하세요.

개선된 코드:

const express = require('express');
const app = express();

// Disable the X-Powered-By header
app.disable('x-powered-by');

// Your routes here

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

모범 사례:

  • 환경 변수를 올바르게 설정하세요. 프로덕션 환경에서 NODE_ENV가 '프로덕션'으로 설정되어 있는지 확인하세요.
  • 내부 로깅: 최종 사용자에게 세부정보를 노출하지 않고 디버깅 목적으로 내부적으로 오류를 기록합니다.

기본 또는 취약한 자격 증명 사용

JWT(JSON 웹 토큰) 서명을 위한 간단한 비밀 키와 같은 기본 자격 증명이나 취약한 자격 증명을 사용하는 것은 흔히 발생하는 보안 실수입니다.

취약 코드 예:

const express = require('express');
const helmet = require('helmet');
const app = express();

// Use Helmet to secure headers
app.use(helmet());

// Your routes here

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

문제:

  • 약한 비밀 키: 'secret'과 같은 단순하거나 일반적인 문자열을 사용하면 공격자가 키를 쉽게 추측하거나 무차별 공격을 가할 수 있습니다.
  • 하드 코딩된 비밀: 비밀을 코드에 직접 저장하면 코드베이스가 손상된 경우 노출 위험이 높아집니다.
  • 토큰 위조: 비밀 키를 알고 있는 공격자가 유효한 JWT를 위조하여 무단 액세스 권한을 얻을 수 있습니다.

완화:

강력하고 안전한 비밀키를 사용하여 안전하게 보관하세요.

개선된 코드:

// app.js
const express = require('express');
const app = express();

// Error handling middleware
app.use((err, req, res, next) => {
  res.status(500).send(err.stack); // Sends stack trace to the client
});

// Your routes here

app.listen(3000);

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

모범 사례:

  • 환경 변수: 버전 관리에 비밀을 커밋하지 마세요. 소스 제어에 체크인되지 않은 환경 변수 또는 구성 파일을 사용하십시오.
  • 비밀번호 순환: 비밀번호를 주기적으로 순환하는 프로세스를 구현합니다.
  • 구성 확인: 애플리케이션 시작 중에 필요한 모든 환경 변수가 설정되었는지 확인하세요.

신원 관리 테스트(WSTG-IDNT)

ID 관리는 사용자 계정을 보호하고 무단 액세스를 방지하는 데 매우 중요합니다.

약한 사용자 이름 정책 및 계정 열거

취약한 사용자 이름을 허용하고 특정 오류 메시지를 제공하면 계정 열거 공격이 발생할 수 있습니다.

취약 코드 예:

const express = require('express');
const app = express();

// Your routes here

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

문제:

  • 약한 사용자 이름: 짧거나 간단한 사용자 이름을 허용하면 계정 도용 위험이 높아집니다.
  • 계정 열거: 특정 오류 메시지는 공격자가 유효한 사용자 이름을 결정하는 데 도움이 될 수 있습니다.

완화:

사용자 이름 확인을 구현하고 일반 오류 메시지를 사용하세요.

개선된 코드:

const express = require('express');
const app = express();

// Disable the X-Powered-By header
app.disable('x-powered-by');

// Your routes here

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

설명:

  • 사용자 이름 확인: 사용자 이름이 특정 기준을 충족하는지 확인하여 취약한 항목을 줄입니다.
  • 일반 오류 메시지: 공격자가 오류 응답을 통해 유효한 사용자 이름을 식별하지 못하도록 방지합니다.

인증 테스트(WSTG-ATHN)

인증 메커니즘은 사용자 신원을 확인하고 무단 액세스를 방지하는 데 필수적입니다.

비밀번호 및 2FA에 대한 무차별 공격

보호 기능이 부족하여 공격자가 반복적인 시도를 통해 비밀번호 또는 2FA 코드를 추측할 수 있습니다.

취약 코드 예:

const express = require('express');
const helmet = require('helmet');
const app = express();

// Use Helmet to secure headers
app.use(helmet());

// Your routes here

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

문제:

  • 무제한 로그인 시도: 공격자는 다른 비밀번호나 2FA 코드를 반복적으로 시도할 수 있습니다.
  • 약한 2FA 구현: 정적 또는 예측 가능한 2FA 코드는 취약합니다.

완화:

속도 제한을 구현하고 2FA 보안을 강화합니다.

개선된 코드:

// app.js
const express = require('express');
const app = express();

// Error handling middleware
app.use((err, req, res, next) => {
  res.status(500).send(err.stack); // Sends stack trace to the client
});

// Your routes here

app.listen(3000);

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

추가 조치:

  • 실패한 시도 후 CAPTCHA 사용: 인간 사용자를 확인하기 위해 여러 번의 로그인 시도 실패 후 CAPTCHA를 도입합니다.
  • 2FA용 TOTP 사용: 동적이며 안전한 2FA 코드를 위해 시간 기반 일회용 비밀번호를 사용하세요.

설명:

  • 속도 제한: 로그인 시도를 제한하여 자동 공격 위험을 줄입니다.
  • 향상된 2FA: 시간 기반 코드는 정적 코드에 비해 보안을 강화합니다.

인증 테스트(WSTG-ATHZ)

승인을 통해 사용자는 사용이 허용된 리소스에만 액세스하여 무단 작업을 방지할 수 있습니다.

안전하지 않은 직접 개체 참조(IDOR)

사용자는 요청에서 식별자를 조작하여 승인되지 않은 리소스에 액세스할 수 있습니다.

취약 코드 예:

// app.js
const express = require('express');
const app = express();

// Your routes here

// Error handling middleware
if (app.get('env') === 'production') {
  // Production error handler
  app.use((err, req, res, next) => {
    // Log the error internally
    console.error(err);
    res.status(500).send('An unexpected error occurred.');
  });
} else {
  // Development error handler (with stack trace)
  app.use((err, req, res, next) => {
    res.status(500).send(`<pre class="brush:php;toolbar:false">${err.stack}
`); }); } app.listen(3000);
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

문제:

  • 무단 액세스: 사용자는 orderId 매개변수를 수정하여 액세스해서는 안 되는 데이터에 액세스할 수 있습니다.

완화:

액세스를 제공하기 전에 리소스 소유권을 확인하세요.

개선된 코드:

const express = require('express');
const app = express();

// Your routes here

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

설명:

  • 소유권 확인: 요청한 리소스가 인증된 사용자에게 속하는지 확인합니다.
  • 액세스 제어: 요청 매개변수를 조작하여 사용자가 다른 사람의 데이터에 액세스하는 것을 방지합니다.

세션 관리 테스트(WSTG-SESS)

세션 관리는 사용자 상태를 유지하고 안전한 상호 작용을 보장하는 데 매우 중요합니다.

만료시간 없는 토큰

만료되지 않는 토큰은 손상될 경우 보안 위험을 초래합니다.

취약 코드 예:

const express = require('express');
const app = express();

// Disable the X-Powered-By header
app.disable('x-powered-by');

// Your routes here

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

문제:

  • 영구 토큰: 만료되지 않은 토큰은 무기한 유효하므로 오용 기회가 늘어납니다.

완화:

토큰 만료 시간을 설정하세요.

개선된 코드:

const express = require('express');
const helmet = require('helmet');
const app = express();

// Use Helmet to secure headers
app.use(helmet());

// Your routes here

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

설명:

  • 토큰 만료: 유효 기간을 제한하여 토큰이 손상될 경우 위험을 줄입니다.
  • 보안 모범 사례: 정기적인 토큰 갱신으로 전반적인 보안이 강화됩니다.

안전하지 않은 토큰 보관

localStorage에 토큰을 저장하면 XSS(교차 사이트 스크립팅) 공격에 노출됩니다.

취약 코드 예:

// app.js
const express = require('express');
const app = express();

// Error handling middleware
app.use((err, req, res, next) => {
  res.status(500).send(err.stack); // Sends stack trace to the client
});

// Your routes here

app.listen(3000);

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

문제:

  • 클라이언트측 노출: 악성 스크립트가 localStorage에 액세스하여 토큰을 훔치고 세션을 하이재킹할 수 있습니다.

완화:

HTTP 전용 쿠키를 사용하여 토큰을 안전하게 저장하세요.

개선된 코드:

// app.js
const express = require('express');
const app = express();

// Your routes here

// Error handling middleware
if (app.get('env') === 'production') {
  // Production error handler
  app.use((err, req, res, next) => {
    // Log the error internally
    console.error(err);
    res.status(500).send('An unexpected error occurred.');
  });
} else {
  // Development error handler (with stack trace)
  app.use((err, req, res, next) => {
    res.status(500).send(`<pre class="brush:php;toolbar:false">${err.stack}
`); }); } app.listen(3000);
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

설명:

  • HTTP 전용 쿠키: JavaScript에 액세스할 수 없어 XSS 위험을 완화합니다.
  • 보안 및 SameSite 플래그: 중간자 및 교차 사이트 요청 위조 공격에 대한 보호 기능을 강화합니다.

입력 검증 테스트(WSTG-INPV)

입력 유효성 검사는 사용자가 제공한 데이터가 안전하고 예상대로인지 확인하여 주입 공격을 방지합니다.

입력 유효성 검사 부족

검증 없이 사용자 입력을 수락하고 처리하면 취약점이 발생할 수 있습니다.

취약 코드 예:

const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();

// Weak secret key
const SECRET_KEY = 'secret';

app.post('/login', (req, res) => {
  // Authenticate user (authentication logic not shown)
  const userId = req.body.userId;

  // Sign the JWT with a weak secret
  const token = jwt.sign({ userId }, SECRET_KEY);
  res.json({ token });
});

app.get('/protected', (req, res) => {
  const token = req.headers['authorization'];

  try {
    // Verify the token using the weak secret
    const decoded = jwt.verify(token, SECRET_KEY);
    res.send('Access granted to protected data');
  } catch (err) {
    res.status(401).send('Unauthorized');
  }
});

app.listen(3000, () => {
  console.log('Server started on port 3000');
});

로그인 후 복사
로그인 후 복사

문제:

  • 삽입 공격: 검증되지 않은 입력은 SQL 주입, NoSQL 주입 또는 기타 코드 주입 공격으로 이어질 수 있습니다.

완화:

모든 사용자 입력을 검증하고 삭제합니다.

개선된 코드:

const express = require('express');
const app = express();

// Your routes here

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

설명:

  • 입력 유효성 검사: 입력이 예상 기준을 충족하는지 확인합니다.
  • 입력 삭제: 잠재적으로 유해한 문자를 제거하거나 이스케이프합니다.
  • 보안 데이터베이스 쿼리: 매개변수화된 쿼리를 사용하면 삽입 공격을 방지할 수 있습니다.

오류 처리 테스트(WSTG-ERRH)

올바른 오류 처리는 민감한 정보 공개를 방지하고 사용자 경험을 향상시킵니다.

민감한 오류 정보 노출

자세한 오류 메시지를 통해 공격자에게 시스템 내부 정보가 드러날 수 있습니다.

취약 코드 예:

const express = require('express');
const app = express();

// Disable the X-Powered-By header
app.disable('x-powered-by');

// Your routes here

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

문제:

  • 정보 공개: 공격자는 애플리케이션의 구조와 잠재적인 취약점에 대한 통찰력을 얻을 수 있습니다.

완화:

일반적인 오류 메시지를 사용하고 내부적으로 자세한 오류를 기록하세요.

개선된 코드:

const express = require('express');
const helmet = require('helmet');
const app = express();

// Use Helmet to secure headers
app.use(helmet());

// Your routes here

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

설명:

  • 내부 로깅: 자세한 오류 정보를 안전하게 유지합니다.
  • 사용자 친화적인 메시지: 민감한 세부정보를 공개하지 않고 일반적인 메시지를 제공합니다.

약한 암호화 테스트(WSTG-CRYP)

암호화는 민감한 데이터를 보호합니다. 약한 암호화 방식을 사용하면 보안이 약화됩니다.

안전하지 않은 해싱 알고리즘 사용

오래된 알고리즘으로 비밀번호를 해싱하는 것은 안전하지 않습니다.

취약 코드 예:

// app.js
const express = require('express');
const app = express();

// Error handling middleware
app.use((err, req, res, next) => {
  res.status(500).send(err.stack); // Sends stack trace to the client
});

// Your routes here

app.listen(3000);

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

문제:

  • 약한 해싱: MD5 및 SHA-1과 같은 알고리즘은 충돌 공격에 취약하므로 비밀번호 해싱에 사용해서는 안 됩니다.

완화:

비밀번호용으로 설계된 강력한 해싱 알고리즘을 사용합니다.

개선된 코드:

// app.js
const express = require('express');
const app = express();

// Your routes here

// Error handling middleware
if (app.get('env') === 'production') {
  // Production error handler
  app.use((err, req, res, next) => {
    // Log the error internally
    console.error(err);
    res.status(500).send('An unexpected error occurred.');
  });
} else {
  // Development error handler (with stack trace)
  app.use((err, req, res, next) => {
    res.status(500).send(`<pre class="brush:php;toolbar:false">${err.stack}
`); }); } app.listen(3000);
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

설명:

  • Bcrypt: 솔팅과 여러 라운드의 해싱을 통합하는 강력한 해싱 기능입니다.
  • 비밀번호 보안: 공격자가 비밀번호를 리버스 엔지니어링하는 것을 계산적으로 불가능하게 만듭니다.

비밀 키 하드코딩

비밀정보를 코드에 직접 저장하면 노출 위험이 높아집니다.

취약 코드 예:

const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();

// Weak secret key
const SECRET_KEY = 'secret';

app.post('/login', (req, res) => {
  // Authenticate user (authentication logic not shown)
  const userId = req.body.userId;

  // Sign the JWT with a weak secret
  const token = jwt.sign({ userId }, SECRET_KEY);
  res.json({ token });
});

app.get('/protected', (req, res) => {
  const token = req.headers['authorization'];

  try {
    // Verify the token using the weak secret
    const decoded = jwt.verify(token, SECRET_KEY);
    res.send('Access granted to protected data');
  } catch (err) {
    res.status(401).send('Unauthorized');
  }
});

app.listen(3000, () => {
  console.log('Server started on port 3000');
});

로그인 후 복사
로그인 후 복사

문제:

  • 비밀 노출: 코드베이스가 손상되면 하드코딩된 비밀을 쉽게 추출할 수 있습니다.

완화:

환경 변수 또는 보안 구성 파일에 비밀을 저장하세요.

개선된 코드:

const express = require('express');
const app = express();

// Your routes here

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

설명:

  • 환경 변수: 코드베이스 및 버전 제어 시스템에 비밀을 유지하세요.
  • 보안 관행: 우발적인 노출 위험을 줄입니다.

비즈니스 로직 테스트(WSTG-BUSL)

비즈니스 로직 취약점은 애플리케이션 흐름이 의도하지 않은 방식으로 조작될 수 있을 때 발생합니다.

대량작업 남용

제한되지 않은 데이터 작업은 성능 문제나 데이터 유출로 이어질 수 있습니다.

취약 코드 예:

const express = require('express');
const app = express();

// Disable the X-Powered-By header
app.disable('x-powered-by');

// Your routes here

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

문제:

  • 서비스 거부(DoS): 대규모 데이터 내보내기로 인해 서버 리소스가 고갈될 수 있습니다.
  • 데이터 유출: 무제한 액세스로 인해 민감한 정보가 노출될 수 있습니다.

완화:

페이지 매김 및 액세스 제어를 구현합니다.

개선된 코드:

const express = require('express');
const helmet = require('helmet');
const app = express();

// Use Helmet to secure headers
app.use(helmet());

// Your routes here

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

설명:

  • 페이지 매김: 반환되는 데이터의 양을 제어하여 리소스 고갈을 방지합니다.
  • 액세스 제어: 사용자가 자신의 데이터에만 액세스할 수 있도록 보장합니다.

클라이언트 측 테스트(WSTG-CLNT)

XSS(교차 사이트 스크립팅)와 같은 공격으로부터 사용자를 보호하려면 클라이언트측 취약점으로부터 보호하는 것이 필수적입니다.

xss 라이브러리를 사용하여 사용자 입력 이스케이프

클라이언트 측 스크립트에서 사용자 입력을 부적절하게 처리하면 XSS 공격이 발생할 수 있습니다.

취약 코드 예:

// app.js
const express = require('express');
const app = express();

// Error handling middleware
app.use((err, req, res, next) => {
  res.status(500).send(err.stack); // Sends stack trace to the client
});

// Your routes here

app.listen(3000);

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

문제:

  • 안전하지 않은 DOM 조작: innerHTML에 정제되지 않은 사용자 입력을 삽입하면 악성 스크립트가 실행될 수 있습니다.

완화:

xss 라이브러리를 사용하여 렌더링하기 전에 사용자 입력을 삭제하세요.

개선된 코드:

// app.js
const express = require('express');
const app = express();

// Your routes here

// Error handling middleware
if (app.get('env') === 'production') {
  // Production error handler
  app.use((err, req, res, next) => {
    // Log the error internally
    console.error(err);
    res.status(500).send('An unexpected error occurred.');
  });
} else {
  // Development error handler (with stack trace)
  app.use((err, req, res, next) => {
    res.status(500).send(`<pre class="brush:php;toolbar:false">${err.stack}
`); }); } app.listen(3000);
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

설명:

  • 입력 삭제: xss 라이브러리는 잠재적으로 위험한 콘텐츠를 이스케이프 처리하거나 제거하여 입력을 정리합니다.
  • 스크립트 실행 방지: 악성 스크립트를 무력화하여 브라우저에서 실행되지 않도록 합니다.

모범 사례:

  • 가능한 경우 textContent 사용: textContent에 사용자 입력을 할당하면 이를 일반 텍스트로 처리합니다.
const express = require('express');
const app = express();

// Your routes here

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
  • 클라이언트측 검증과 서버측 검증 결합: 심층 방어 접근 방식으로 보안이 강화됩니다.

API 테스트(WSTG-APIT)

데이터 유출과 무단 액세스를 방지하려면 API 엔드포인트를 보호하는 것이 중요합니다.

GraphQL 내부 검사 노출

프로덕션에서 GraphQL 내부 검사를 활성화하면 API 스키마가 드러납니다.

취약 코드 예:

const express = require('express');
const app = express();

// Disable the X-Powered-By header
app.disable('x-powered-by');

// Your routes here

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

문제:

  • 스키마 공개: 공격자가 API 스키마를 탐색하여 표적 공격을 수행하는 데 도움을 줄 수 있습니다.

완화:

프로덕션 환경에서는 자체 검사를 비활성화합니다.

개선된 코드:

const express = require('express');
const helmet = require('helmet');
const app = express();

// Use Helmet to secure headers
app.use(helmet());

// Your routes here

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

설명:

  • 조건부 자체 검사: 개발 중에는 자체 검사를 허용하지만 프로덕션에서는 비활성화합니다.
  • 보안 강화: 스키마 세부정보를 숨겨 공격 표면을 줄입니다.

제한되지 않은 쿼리 복잡성

깊게 중첩되거나 복잡한 쿼리는 서버 리소스를 고갈시킬 수 있습니다.

취약 코드 예:

// app.js
const express = require('express');
const app = express();

// Error handling middleware
app.use((err, req, res, next) => {
  res.status(500).send(err.stack); // Sends stack trace to the client
});

// Your routes here

app.listen(3000);

로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

문제:

  • 서비스 거부(DoS): 복잡한 쿼리로 인해 CPU 및 메모리 사용량이 높아질 수 있습니다.

완화:

쿼리의 깊이와 복잡성을 제한하세요.

개선된 코드:

// app.js
const express = require('express');
const app = express();

// Your routes here

// Error handling middleware
if (app.get('env') === 'production') {
  // Production error handler
  app.use((err, req, res, next) => {
    // Log the error internally
    console.error(err);
    res.status(500).send('An unexpected error occurred.');
  });
} else {
  // Development error handler (with stack trace)
  app.use((err, req, res, next) => {
    res.status(500).send(`<pre class="brush:php;toolbar:false">${err.stack}
`); }); } app.listen(3000);
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사
로그인 후 복사

설명:

  • 깊이 제한: 리소스 고갈을 방지하기 위해 쿼리의 깊이를 제한합니다.
  • 성능 보호: API의 응답성과 가용성을 유지합니다.

결론

Node.js 애플리케이션 보안에는 다계층 접근 방식이 필요합니다.

  • 정보 유출 방지: 민감한 데이터가 노출되지 않도록 코드와 서버 구성을 정리하세요.
  • 구성을 안전하게 관리: 기본 자격 증명을 제거하고 구성 파일을 보호합니다.
  • 입력 유효성 검사 및 삭제: 사용자 입력을 절대 신뢰하지 마세요.
  • 적절한 인증 및 권한 부여 구현: 사용자에게 적절한 액세스 권한이 있는지 확인하세요.
  • 강력한 암호화 사용: 보안 알고리즘과 키 관리로 데이터를 보호하세요.
  • 오류를 적절하게 처리: 민감한 정보를 공개하지 마세요.
  • 클라이언트 측 상호 작용 보호: XSS 및 기타 브라우저 기반 공격을 완화합니다.
  • 보안 API: 데이터 노출을 제어하고 속도 제한을 적용합니다.

이러한 사례를 통합하면 애플리케이션의 보안을 강화하고 사용자 데이터를 보호하며 신뢰를 유지할 수 있습니다.


추가 자료

  • OWASP 웹 보안 테스트 가이드(WSTG): OWASP WSTG
  • Node.js 보안 가이드: Node.js 보안
  • Express.js 보안 팁: Express 보안 모범 사례
  • GraphQL 보안 모범 사례: Apollo GraphQL 보안
  • OWASP 상위 10위: OWASP 상위 10위
  • MDN 웹 문서 - 웹 보안: MDN 웹 보안

참고: 이 가이드는 일반적인 권장 사항을 제공합니다. 구체적인 보안 문제는 전문가에게 문의하세요.

위 내용은 Node.js 애플리케이션 보안: 종합 가이드의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:dev.to
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
저자별 최신 기사
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿