2025. 2. 15. 20:45ㆍ프로젝트
데이터베이스 및 개인정보 보호 – 시작하기
📌 이 단계의 목표:
✅ 데이터베이스 보안 강화 (암호화, 접근 제한, 백업 설정)
✅ 개인정보 보호 조치 (비밀번호 암호화, 민감 데이터 보호)
✅ SQL Injection 및 권한 관리 최적화
데이터베이스 및 개인정보 보호 – 세부 항목
✅ 비밀번호 암호화 | bcrypt 또는 argon2로 비밀번호 해싱 및 저장 | 미완료 |
✅ DB 접근 권한 제한 | 관리자만 중요 데이터 조회 가능 (role-based access) | 미완료 |
✅ SQL Injection 방지 (추가 강화) | ORM 사용 및 모든 입력값 검증 (Sequelize, Prepared Statement) | 부분 완료 |
✅ 데이터 암호화 (민감 정보 보호) | 이메일, 전화번호 등 AES-256 또는 환경변수 암호화 적용 | 미완료 |
✅ 백업 및 로그 보관 정책 | DB 자동 백업 및 접근 로그 기록 (winston) | 미완료 |
1. 비밀번호 암호화 – bcrypt 적용
📌 목표:
✅ 사용자 비밀번호를 안전하게 저장하기 위해 단방향 해시 적용
✅ bcrypt 사용하여 암호화 및 보안 강화
✅ 비밀번호 비교 함수 구현
설치 명령어
npm install bcrypt
비밀번호 해싱 및 저장 방법
📌 bcrypt를 사용하여 비밀번호 해싱 (암호화)
import bcrypt from "bcrypt";
const saltRounds = 10; // 해시 반복 횟수 (10~12 추천)
// 비밀번호 해싱 함수
export const hashPassword = async (password) => {
return await bcrypt.hash(password, saltRounds);
};
📌 사용자 회원가입 시 비밀번호 암호화 (routes/auth.js)
import { hashPassword } from "../utils/security.js";
app.post("/register", async (req, res) => {
try {
const { email, password, name } = req.body;
// ✅ 비밀번호 암호화
const hashedPassword = await hashPassword(password);
// ✅ DB에 저장 (Sequelize 예제)
const newUser = await User.create({
email,
password: hashedPassword, // 암호화된 비밀번호 저장
name,
});
res.status(201).json({ message: "회원가입 성공!" });
} catch (error) {
res.status(500).json({ message: "회원가입 중 오류 발생", error });
}
});
비밀번호 비교 함수 (로그인 시 사용)
📌 로그인 시 입력된 비밀번호와 암호화된 비밀번호 비교
// 비밀번호 검증 함수
export const comparePassword = async (plainPassword, hashedPassword) => {
return await bcrypt.compare(plainPassword, hashedPassword);
};
📌 로그인 라우트 (routes/auth.js)
import { comparePassword } from "../utils/security.js";
app.post("/login", async (req, res) => {
try {
const { email, password } = req.body;
// ✅ 사용자 조회
const user = await User.findOne({ where: { email } });
if (!user) return res.status(401).json({ message: "이메일이 존재하지 않습니다." });
// ✅ 비밀번호 검증
const isMatch = await comparePassword(password, user.password);
if (!isMatch) return res.status(401).json({ message: "비밀번호가 올바르지 않습니다." });
// ✅ 로그인 성공
req.session.user = { id: user.id, email: user.email };
res.status(200).json({ message: "로그인 성공!" });
} catch (error) {
res.status(500).json({ message: "로그인 중 오류 발생", error });
}
});
2. 데이터베이스 접근 권한 제한
📌 목표:
✅ 관리자(SuperUser)만 특정 데이터 접근 가능
✅ 일반 유저(User)는 본인 데이터만 조회 가능
✅ SQL Injection 방지를 위한 ORM 권한 관리 강화
데이터베이스 접근 권한 모델링 (RBAC 적용)
RBAC(Role-Based Access Control, 역할 기반 접근 제어)를 적용하여 유저(User), 전문가(Expert), 슈퍼유저(SuperUser)의 데이터 접근을 제한해야 합니다.
📌 역할(Role)별 접근 권한 예시
User | 본인이 등록한 시스템 조회, 자가진단 수행 |
Expert | 슈퍼유저가 매칭한 시스템 피드백 제공 |
SuperUser | 모든 시스템 조회, 유저 관리, 전문가 매칭 |
접근 권한 미들웨어 구현 (middlewares/auth.js)
📌 사용자 역할(Role) 기반 접근 제한 미들웨어
// ✅ 인증 미들웨어
const requireAuth = (req, res, next) => {
if (!req.session?.user && !req.session?.expert && !req.session?.superuser) {
return res.status(401).json({ message: "로그인이 필요합니다." });
}
next();
};
// ✅ 슈퍼유저 전용 인증 미들웨어
const requireSuperUser = (req, res, next) => {
if (!req.session?.superuser) {
return res.status(403).json({ message: "슈퍼유저 권한이 필요합니다." });
}
next();
};
SQL Injection 방지 및 ORM 권한 적용
📌 Sequelize ORM 사용으로 SQL Injection 방지 강화
app.post("/login", async (req, res) => {
try {
const { email, password } = req.body;
// ✅ SQL Injection 방지: ORM 사용
const user = await User.findOne({ where: { email } });
if (!user) return res.status(401).json({ message: "이메일이 존재하지 않습니다." });
// ✅ 비밀번호 검증
const isMatch = await comparePassword(password, user.password);
if (!isMatch) return res.status(401).json({ message: "비밀번호가 올바르지 않습니다." });
req.session.user = { id: user.id, email: user.email, role: user.role };
res.status(200).json({ message: "로그인 성공!" });
} catch (error) {
res.status(500).json({ message: "로그인 중 오류 발생", error });
}
});
✅ Sequelize ORM을 사용하면 SQL Injection을 자동으로 방지할 수 있음!
✅ 직접 SQL을 쓰지 말고 where: {}을 이용하면 안전함!
✅ 로그인, 회원가입, 조회 API에서 ORM 방식으로 데이터 조회하기!
3. 데이터 암호화 (민감 정보 보호) – AES-256 적용
📌 목표:
✅ 비밀번호뿐만 아니라 민감한 개인정보(이메일, 전화번호 등)도 암호화
✅ AES-256 암호화 적용하여 데이터 보호
✅ 데이터 복호화(복원) 기능 추가
데이터 암호화가 필요한 이유
❌ 일반적으로 데이터는 DB에 평문(Plain Text)으로 저장되면 보안에 취약합니다
예를 들어, 해커가 DB를 탈취하면 모든 유저의 이메일과 전화번호가 그대로 노출될 수 있습니다.
✅ 그래서 AES-256 같은 강력한 암호화 알고리즘을 사용해서 데이터를 보호해야 합니다
이렇게 하면 해커가 데이터를 훔쳐도 복호화 키(Secret Key)가 없으면 읽을 수 없습니다
AES-256 암호화를 위한 crypto 모듈 설치
📌 Node.js 내장 crypto 모듈 사용 (추가 라이브러리 설치 불필요!)
import crypto from "crypto";
import dotenv from "dotenv";
dotenv.config();
📌 .env 파일에 암호화 키 추가
ENCRYPTION_KEY=your_secret_32_character_key
IV_KEY=your_16_character_iv
✔️ ENCRYPTION_KEY는 32바이트(256비트), IV_KEY는 **16바이트(128비트)**여야 함!
✔️ 키를 무작위로 생성하고 싶다면
console.log(crypto.randomBytes(32).toString("hex")); // 32바이트 키 생성
console.log(crypto.randomBytes(16).toString("hex")); // 16바이트 IV 생성
암호화 & 복호화 함수 만들기 (utils/encryption.js)
AES-256 암호화 함수
import crypto from "crypto";
import dotenv from "dotenv";
dotenv.config();
const ENCRYPTION_KEY = process.env.ENCRYPTION_KEY; // 32바이트 키
const IV_KEY = process.env.IV_KEY; // 16바이트 IV
export const encryptData = (text) => {
const iv = Buffer.from(IV_KEY, "hex");
const cipher = crypto.createCipheriv("aes-256-cbc", Buffer.from(ENCRYPTION_KEY, "hex"), iv);
let encrypted = cipher.update(text, "utf8", "hex");
encrypted += cipher.final("hex");
return encrypted;
};
export const decryptData = (encryptedText) => {
const iv = Buffer.from(IV_KEY, "hex");
const decipher = crypto.createDecipheriv("aes-256-cbc", Buffer.from(ENCRYPTION_KEY, "hex"), iv);
let decrypted = decipher.update(encryptedText, "hex", "utf8");
decrypted += decipher.final("utf8");
return decrypted;
};
✔️ AES-256-CBC 알고리즘을 사용해 데이터 암호화!
✔️ 암호화된 데이터는 복호화 키 없이는 절대 읽을 수 없음!
DB 저장 시 민감 정보 암호화 (routes/auth.js)
📌 유저 회원가입 시 이메일 & 전화번호 암호화
import { encryptData } from "../utils/encryption.js";
app.post("/register", async (req, res) => {
try {
const { email, phone_number, password } = req.body;
// ✅ 이메일 & 전화번호 암호화
const encryptedEmail = encryptData(email);
const encryptedPhone = encryptData(phone_number);
const newUser = await User.create({
email: encryptedEmail,
phone_number: encryptedPhone,
password, // 비밀번호는 이미 bcrypt 해싱 적용됨
});
res.status(201).json({ message: "회원가입 성공!" });
} catch (error) {
res.status(500).json({ message: "회원가입 중 오류 발생", error });
}
});
유저 정보 조회 시 자동 복호화
(routes/user.js)
📌 유저 정보 조회 시 복호화된 데이터 제공
import { decryptData } from "../utils/encryption.js";
app.get("/user", requireAuth, async (req, res) => {
try {
const user = await User.findOne({ where: { id: req.session.user.id } });
if (!user) return res.status(404).json({ message: "사용자를 찾을 수 없습니다." });
// ✅ 이메일 & 전화번호 복호화
const decryptedEmail = decryptData(user.email);
const decryptedPhone = decryptData(user.phone_number);
res.json({
id: user.id,
email: decryptedEmail,
phone_number: decryptedPhone,
});
} catch (error) {
res.status(500).json({ message: "사용자 정보 조회 오류", error });
}
});
✔️ DB에서 꺼내올 때 자동으로 복호화해서 유저에게 제공!
✔️ DB 내부에는 암호화된 데이터만 저장되므로 보안이 강화됨!
최종 점검표 – 데이터 암호화 적용 완료
보안항목 | 현재상태 | 설명 |
✅ AES-256 암호화 함수 (encryptData, decryptData) | 완료 | crypto 모듈을 사용해 강력한 암호화 적용 |
✅ 회원가입 시 이메일 & 전화번호 암호화 | 완료 | DB에 평문 데이터 저장 금지 |
✅ 유저 정보 조회 시 자동 복호화 | 완료 | DB에서 조회된 데이터는 자동 복호화 |
'프로젝트' 카테고리의 다른 글
개인정보-컴플라이언스-웹애플리케이션 (2. 입력값 검증 및 웹 보안 ) (0) | 2025.02.15 |
---|---|
개인정보-컴플라이언스-웹애플리케이션 (1. 인증 및 세션 보안) (0) | 2025.02.14 |
개인정보-컴플라이언스-웹애플리케이션 (수정사항 7) (0) | 2025.02.02 |
개인정보-컴플라이언스-웹애플리케이션 (수정사항 6) (0) | 2025.01.29 |
개인정보-컴플라이언스-웹애플리케이션 (수정사항 5) (0) | 2025.01.29 |