Day 26 - 백엔드의 구조는 어떻게 설계해야할까?, 암호화(Encryption)와 복호화(Decryption)

이유승·2024년 12월 9일
0

* 프로그래머스, 타입스크립트로 함께하는 웹 풀 사이클 개발(React, Node.js) 5기 강의 수강 내용을 정리하는 포스팅.

* 원활한 내용 이해를 위해 수업에서 제시된 자료 이외에, 개인적으로 조사한 자료 등을 덧붙이고 있음.

1. 구조.. 구조.. 구조..?

  • 백엔드라고 종합해서 말은 하지만, 세부적으로 백엔드의 진입점 / 정적 파일 / 데이터베이스 연결 / 설정 / 미들웨어 / 템플릿 등등.. 백엔드 구성에 필요한 폴더와 파일들이 많기 때문.

  • 따라서 적절한 구조가 설계되지 않는다면, 백엔드 전체의 유지보수성과 가독성 그리고 확장성 측면에서 문제를 유발할 위험성이 커지게 된다.



2. 백엔드 구조 예시

  • 대강 이렇게 하면 된다는 예시.

  • 상황이나 필요에 따라서 세부적인 부분 혹은 전체 구조 자체가 달라질 수 있다.

  • 프론트엔드 예시이긴 하지만, 컴포넌트 / 라우터 / 모델 등의 기존 구조를 벗어난 기능 분할 설계(FSD)라는 아키텍처라는 개념도 존재한다.



구조 예시

project-name/
├── bin/
│   └── www                 # 서버 실행 파일
├── node_modules/           # 의존성 모듈
├── public/                 # 정적 파일 (CSS, 이미지 등)
│   ├── images/
│   ├── javascripts/
│   └── stylesheets/
├── routes/                 # 라우트 정의
│   ├── index.js
│   └── users.js
├── controllers/            # 컨트롤러 (비즈니스 로직)
├── models/                 # 데이터베이스 모델 정의
├── middlewares/            # 공통 미들웨어
├── views/                  # 템플릿 파일 (ejs, pug 등)
├── app.js                  # 앱 초기화 및 설정
├── package.json            # 프로젝트 메타데이터 및 의존성
└── README.md               # 프로젝트 설명

bin/

  • 서버 시작 스크립트를 포함합니다.
  • www 파일은 포트를 설정하고 app.js를 실행합니다.

routes/

  • 라우팅 로직을 담당합니다.
  • API 경로별로 파일을 분리하여 관리합니다.
    예: routes/users.js → /users 관련 경로 처리.

controllers/

  • 비즈니스 로직을 담당합니다.
  • 라우터에서 분리하여 코드의 가독성과 재사용성을 높입니다.

    예: controllers/usersController.js에서 사용자 데이터 처리 로직 작성.

models/

  • 데이터베이스 모델을 정의합니다.
  • ORM/ODM(Mongoose, Sequelize 등)을 사용하는 경우 여기에 정의합니다.

middlewares/

  • 공통적으로 사용하는 미들웨어를 정의합니다.

    예: 인증 미들웨어, 로깅 미들웨어 등.

public/

  • CSS, JavaScript, 이미지와 같은 정적 파일을 저장합니다.
  • express.static() 미들웨어로 정적 파일을 서빙합니다.

views/

  • 서버 사이드 렌더링에 사용되는 템플릿 엔진 파일을 저장합니다.
  • 템플릿 엔진으로는 Pug, EJS 등을 사용할 수 있습니다.

app.js

  • Express 앱을 초기화하고 미들웨어 및 라우터를 설정합니다.
  • app.js는 프로젝트의 중심 파일로, 모든 설정이 이곳에 정의됩니다.



구조가 너무 복잡한데..

  • 굳이 이렇게 나누는 까닭은 결국 모든 파일들은 목적이나 기능별로 나누어져야 하기 때문.

  • 공통적으로 사용하는 로직(예: 인증, 로깅)은 미들웨어로 분리하여 가독성과 유지보수성을 향상시킬 수 있고..

  • controllers와 services를 분리하면 컨트롤러는 요청-응답 핸들링만, 서비스는 비즈니스 로직만 담당하게 되면서 마찬가지로 효율성이 향상되게 된다.



3. 백엔드 아키텍처



1. MVC (Model-View-Controller) 아키텍처

개요

  • MVC는 웹 애플리케이션에서 가장 널리 사용되는 구조 중 하나입니다. 코드의 역할을 모델, 뷰, 컨트롤러로 분리하여 유지보수성을 높이는 방식입니다.

구조

project/
├── models/         # 데이터베이스와 관련된 로직
├── views/          # 템플릿 엔진(예: EJS, Pug)으로 사용자 인터페이스를 렌더링
├── controllers/    # 요청과 응답을 처리하는 로직
├── routes/         # 경로 설정
├── public/         # 정적 파일
├── app.js          # 앱 초기화

장점

  • 코드의 역할 분리가 명확하여 유지보수가 쉬움.
  • 비즈니스 로직(Model)과 프론트엔드(View)가 독립적으로 동작.

단점

  • 소규모 API 서버에는 다소 과도할 수 있음.
  • API 전용 서버에서는 views 디렉터리가 불필요.



2. 서비스 레이어 아키텍처

개요

  • 서비스 레이어(Service Layer)는 MVC 아키텍처의 변형으로, 컨트롤러와 모델 간의 비즈니스 로직을 서비스 레이어로 분리합니다. 이를 통해 컨트롤러가 요청-응답 핸들링에만 집중할 수 있습니다.

구조

project/
├── routes/         # 경로 설정
├── controllers/    # 요청과 응답 핸들링
├── services/       # 비즈니스 로직
├── models/         # 데이터베이스와 관련된 로직
├── middlewares/    # 공통 미들웨어
├── app.js          # 앱 초기화

예제

  • 컨트롤러는 요청과 응답만 처리:
const userService = require('../services/userService');

exports.getUser = async (req, res) => {
  const userId = req.params.id;
  const user = await userService.getUserById(userId);
  res.json(user);
};
  • 서비스는 비즈니스 로직을 처리:
const UserModel = require('../models/userModel');

exports.getUserById = async (userId) => {
  return await UserModel.findById(userId);
};

장점

  • 컨트롤러가 가벼워지고 재사용성이 높아짐.
  • 비즈니스 로직을 중앙집중화하여 관리.

단점

  • 서비스 레이어의 설계가 과도하게 세분화되면 복잡성이 증가.



3. 클린 아키텍처 (Clean Architecture)

개요

  • 클린 아키텍처는 도메인 로직을 중심으로 설계하여 유연성과 확장성을 극대화하는 방법론입니다. 의존성은 외부에서 내부로 흐른다는 원칙을 따릅니다.

구조

project/
├── src/
│   ├── entities/         # 핵심 비즈니스 로직 (순수 JS)
│   ├── usecases/         # 애플리케이션 비즈니스 규칙
│   ├── interfaces/       # 컨트롤러 및 외부 통신
│   ├── frameworks/       # Express, DB 등 외부 프레임워크 의존성
│   └── config/           # 설정 파일
├── app.js                # 앱 초기화

예제

Entities: 도메인 로직만 포함.
Usecases: 비즈니스 규칙.
Interfaces: HTTP 요청 처리.

장점

  • 프레임워크에 종속되지 않음.
  • 테스트 가능성과 확장성이 높음.

단점

  • 설계 및 초기 구현이 복잡할 수 있음.
  • 소규모 프로젝트에는 과도한 구조.



4. 레이어드 아키텍처

개요

  • 레이어드 아키텍처는 시스템을 프리젠테이션, 도메인, 데이터의 3계층으로 나눕니다. 각 계층은 아래 계층에만 의존하며, 독립적으로 테스트 및 확장이 가능합니다.

구조

project/
├── routes/              # 프리젠테이션 계층
├── controllers/         # 프리젠테이션 계층
├── services/            # 도메인 계층
├── models/              # 데이터 계층
├── app.js               # 앱 초기화

장점

  • 설계가 단순하고 직관적.
  • 역할 분리가 명확하여 유지보수가 용이.

단점

  • 계층 간 의존성이 높아질 수 있음.



어떤 구조를 선택하든..

  • 비즈니스 로직 분리: 컨트롤러와 서비스/모델을 분리해야 한다.

  • 미들웨어 활용: 인증, 로깅과 같은 공통 로직은 미들웨어로 구현해야한다.

  • 코드 재사용성: 공통 로직과 유틸리티 함수는 별도 디렉터리로 관리해야한다.

  • 위 3개 원칙은 항상 준수할 것.



4. 암호화(Encryption)와 복호화(Decryption)

  • 데이터의 보안을 위해 사용되는 개념.



1. 암호화(Encryption)

  • 평문(Plain Text, 사람이 읽을 수 있는 데이터)을 읽을 수 없는 암호문(Cipher Text)으로 변환하는 과정.

  • 데이터를 보호하여 허가되지 않은 접근으로부터 정보를 안전하게 유지하기 위함.

  • 쉽게 말하자면, 회원가입 기능을 통해 회원 정보를 DB에 저장했다고 가정해보자.

  • 그런데 비밀번호를 입력한 값 그대로 저장해버리면? 혹여나 DB가 유출되거나 하는 문제가 생겼을 때 돌이킬 수 없는 사태가 벌어질 수도 있다.

  • 외부에 노출되었을 때 보안 문제를 일으키는 민감한 정보라고 하면, 값 자체를 암호화하는게 안전한 방법.



2. 복호화(Decryption)

  • 암호문(Cipher Text)을 평문(Plain Text)으로 되돌리는 과정.

  • 암호화된 데이터를 원래의 형태로 변환하여 올바른 사용자만 읽을 수 있게 한다.

  • 위 예시를 계속해보자면.. 로그인 기능을 구현했을 때 DB에는 암호화된 비밀번호만 저장된다. 사용자가 입력한 비밀번호는 원본이기 때문에 DB의 암호화 비밀번호를 다시 풀어서 사용자가 입력한 비밀번호와 대조해주어야 한다.



3. 암호화 방법?

  • 암호화 알고리즘.

  • 데이터를 안전하게 보호하기 위해 사용되는 수학적 규칙과 절차.

  • 일개 개인이 알고리즘을 만들어서 사용한다는건 현실적으로 불가능하다.

  • 외부 공격에 안전한 알고리즘을 만드는 것부터 난관이고, 혼자 만들어봐야 다른 사람들이 널리 사용해주지 않으면 존재 가치가 없다.

  • 결국 더 똑똑하고 부지런한 사람들이 만들어둔 훌륭한 방법을 가져다가 사용하면 된다.

  • 아래는 암호화 알고리즘 예시. 어디서 한번 정도 들어본 방법들이 하나 정도는 보일 것이다.

  • 대강 적어는 두는데, 이건 보안 프로그래머를 준비하는게 아니라면 외워둘 필요도 없다..

AES (Advanced Encryption Standard):

현재 가장 널리 사용되는 대칭 암호화 알고리즘.
128, 192, 256비트 키 길이를 지원.

DES (Data Encryption Standard):

오래된 알고리즘으로, 현재는 보안 취약점 때문에 비추천.

3DES (Triple DES):

DES를 3번 적용한 방식으로 보안을 강화했지만, 속도가 느림.

Blowfish:

속도가 빠르고 유연한 키 길이를 제공하지만, AES에 밀려 사용이 줄어듦.

RSA:

비대칭 암호화의 대표적인 알고리즘.
긴 키 길이를 통해 강력한 보안 제공.

ECC (Elliptic Curve Cryptography):

RSA보다 더 짧은 키로 동등한 보안을 제공.
모바일 환경 등 리소스 제약이 있는 곳에서 사용 증가.

Diffie-Hellman:

안전한 키 교환을 위한 알고리즘.

profile
프론트엔드 개발자를 준비하고 있습니다.

0개의 댓글