DB part.4

2025. 6. 10. 18:20·Daily Logs/TIL (Today I Learned)
데이터베이스 트랜잭션과 보안

데이터베이스 트랜잭션과 보안 완벽 가이드

💡 핵심 포인트
DB를 다룸에 있어서 트랜잭션은 꼭 알아야 하는 필수 개념입니다!

1. 트랜잭션이란 무엇인가?

트랜잭션은 데이터베이스의 상태를 변환시키는 하나의 논리적 기능을 수행하기 위한 작업의 단위 또는 한꺼번에 모두 수행되어야 할 일련의 연산들을 의미합니다.

실생활 예시: 계좌이체

호날두가 메시에게 100만원을 송금하는 상황을 생각해보세요:

1호날두의 계좌에서 100만원을 차감합니다.

2메시의 계좌에다가 100만원을 더합니다.

만약 1단계는 성공했는데 2단계에서 오류가 발생한다면? 호날두의 100만원은 어디로 갔을까요? 이런 문제를 방지하기 위해 트랜잭션 개념이 필요합니다.

트랜잭션의 핵심
• 커밋(Commit): 모든 작업이 성공적으로 완료되어 반영되는 것
• 롤백(Rollback): 문제가 하나라도 발생하여 원래 상태로 돌아가는 것

MySQL에서 트랜잭션 구현 - Stored Procedure

DELIMITER // CREATE PROCEDURE TransferMoney(IN account_id1 INT, IN account_id2 INT) BEGIN DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN -- 하나의 쿼리라도 에러가 발생하면 롤백! ROLLBACK; END; START TRANSACTION; UPDATE bank_accounts SET balance = balance - 1000 WHERE account_id = account_id1; UPDATE bank_accounts SET balance = balance + 1000 WHERE account_id = account_id2; -- 두 UPDATE 쿼리 모두 성공하면 커밋 COMMIT; END// DELIMITER ;

호날두(918225번)에서 메시(291036번)로 송금하려면:

CALL TransferMoney(918225, 291036);

2. ACID 특성 - 트랜잭션의 4가지 핵심 속성

A - 원자성(Atomicity)

• 데이터베이스의 모든 트랜잭션은 원자성을 보장합니다

• 수행이 되거나 안되거나 - 애매한 상태는 존재하지 않습니다

• "다 되거나! 다 안되거나!"

C - 일관성(Consistency)

• 트랜잭션이 완료되면 데이터의 일관성이 보장됩니다

• 무결성 제약을 깨뜨리는 트랜잭션은 실행되지 않습니다

• 예: 존재하지 않는 게시글에 댓글을 달 수 없음

I - 격리성(Isolation)

• 트랜잭션이 수행되면 다른 트랜잭션으로부터 영향을 받지 않습니다

• 호날두→메시 송금이 완료되기 전까지 다른 트랜잭션은 변경된 잔액을 볼 수 없습니다

D - 지속성(Durability)

• 트랜잭션이 성공적으로 수행되면 이 결과는 영원히 데이터베이스에 반영됩니다

3. 격리성(Isolation) 레벨 상세 분석

격리성은 성능과 일관성 간의 트레이드오프를 만듭니다. 쇼핑몰에서 마지막 1개 남은 상품을 두 고객이 동시에 구매하려는 상황으로 예시를 들어보겠습니다.

격리 수준별 동작 방식

1. Serializable (가장 높은 격리 수준)

특징: 하나의 트랜잭션이 완료될 때까지 다른 트랜잭션은 해당 상품의 재고에 접근할 수 없음

장점: 완벽한 일관성 보장

단점: 성능 저하, 대기 시간 발생

2. Repeatable Read (MySQL 기본 설정)

특징: 한 트랜잭션 내에서 같은 데이터를 반복해서 읽어도 동일한 결과 보장

동작: 두 고객이 동시에 재고 확인 가능하지만, 실제 재고 감소는 한 명만 성공

결과: 먼저 결제한 고객 성공, 늦은 고객은 실패하거나 대기

3. Read Committed (일반적인 DB 기본 설정)

특징: 커밋 완료된 데이터만 읽을 수 있음

문제점: Non-Repeatable Read 발생 가능

Non-Repeatable Read 예시:
1. 고객 A가 재고 확인: 1개
2. 고객 B가 구매 완료 (재고 0개로 변경)
3. 고객 A가 재고 재확인: 0개 (이전과 다른 결과!)
4. Read Uncommitted (가장 낮은 격리 수준)

특징: 커밋되지 않은 데이터도 읽을 수 있음

문제점: Dirty Read 발생

Dirty Read 예시:
1. 고객 A가 3개 구매 시작 (재고 5→2개로 변경, 아직 미커밋)
2. 고객 B가 재고 확인: 2개로 보임
3. 고객 A 결제 실패로 롤백 (재고 다시 5개)
4. 고객 B는 잘못된 정보로 구매 결정

격리 수준 선택 가이드라인

언제 어떤 격리 수준을 사용할까?
• 데이터 일관성이 매우 중요하다면: Serializable 또는 Repeatable Read
• 성능이 더 중요하고 약간의 일관성 저하를 허용: Read Committed
• 성능이 절대적으로 중요: Read Uncommitted (실제 운영환경에서는 거의 사용 안함)

4. 데이터베이스 보안 - 접근 제어

데이터베이스는 서비스의 심장과도 같은 곳입니다. 고객의 개인정보를 포함한 민감한 정보들이 저장되므로 철저한 보안이 필요합니다.

접근 제어의 두 가지 핵심

인증(Authentication) - "누구인가?"
CREATE USER 'messi'@'localhost' IDENTIFIED BY 'goat';

localhost에서 접근할 수 있는 'messi' 사용자를 생성하고 'goat' 비밀번호로 인증

인가(Authorization) - "무엇을 할 수 있는가?"
GRANT SELECT, INSERT, DELETE ON soccer.* TO 'messi'@'localhost';

messi 사용자에게 soccer 데이터베이스에서 SELECT, INSERT, DELETE 권한만 부여

최소 권한의 법칙
사용자마다 해당 사용자가 컨트롤할 영역에 대해서만 명확하게 권한을 부여해야 합니다. 모든 권한을 부여하면 시스템에 위협이 될 수 있습니다.

5. 데이터 암호화

특히 비밀번호와 같은 민감한 정보는 반드시 암호화되어 저장되어야 합니다.

암호화의 기본 개념

• 암호화: 평문(Plain Text)을 암호문으로 변환하는 과정
• 복호화: 암호문을 다시 평문으로 복원하는 과정
• 대칭키: 암호화와 복호화에 같은 키 사용
• 비대칭키: 암호화와 복호화에 서로 다른 키 사용

비밀번호 암호화 과정

회원가입 절차

1. A 사용자가 비밀번호 'sparta' 입력

2. 시스템이 'sparta'를 '3ab0198'로 암호화

3. 데이터베이스에 '3ab0198' 저장

로그인 절차

1. A 사용자가 비밀번호 'sparta' 입력

2. 시스템이 'sparta'를 '3ab0198'로 암호화

3. DB에 저장된 '3ab0198'과 비교

4. 일치하면 인증 성공!

단방향 암호화
비밀번호는 복호화가 불가능한 단방향 암호화를 사용합니다. 암호화 키가 노출되어도 원본 데이터는 보호받을 수 있습니다.

6. SQL Injection 방어

🚨 중요한 보안 수칙
프로그램에서 쿼리 인자를 입력할 때는 반드시 Prepared Statement를 사용하세요!

SQL Injection 공격 예시

다음과 같은 로그인 쿼리가 있다고 가정해봅시다:

"SELECT * FROM Users WHERE Username='" + username + "' AND Password='" + password + "';"

악의적인 공격자가 username에 "admin'; --"를 입력하면:

"SELECT * FROM Users WHERE Username='admin'; --' AND Password='...';"

"--"는 SQL 주석이므로 비밀번호 검사 부분이 무시되어 관리자 계정에 무단 접근이 가능해집니다!

Prepared Statement로 방어하기

const mysql = require('mysql'); const connection = mysql.createConnection({ host : 'localhost', user : 'user', password : 'password', database : 'database' }); connection.connect(); const username = "admin'; --"; const password = "password"; // Prepared Statement 사용 - 인자값 위치가 ?로 대체 const sql = "SELECT * FROM Users WHERE Username = ? AND Password = ?"; connection.query(sql, [username, password], function(error, results, fields) { if (error) { throw error; } console.log(results); }); connection.end();
Prepared Statement의 장점
사용자 입력이 SQL 코드로 해석되는 것을 방지하여 SQL Injection 공격을 완전히 차단할 수 있습니다.

마무리

데이터베이스 트랜잭션과 보안은 모든 개발자가 반드시 알아야 할 핵심 개념입니다. 특히:

꼭 기억해야 할 포인트
1. ACID 특성을 이해하고 적절한 격리 수준 선택
2. 최소 권한 원칙으로 접근 제어 설정
3. 단방향 암호화로 민감한 데이터 보호
4. Prepared Statement로 SQL Injection 방어

이러한 보안 원칙들을 지켜서 안전하고 신뢰할 수 있는 시스템을 구축하시기 바랍니다!

'Daily Logs > TIL (Today I Learned)' 카테고리의 다른 글

DB part.6  (4) 2025.06.12
DB part.5  (2) 2025.06.11
DB part.3  (0) 2025.06.09
DB part.2  (0) 2025.06.08
DB part.1  (4) 2025.06.07
'Daily Logs/TIL (Today I Learned)' 카테고리의 다른 글
  • DB part.6
  • DB part.5
  • DB part.3
  • DB part.2
Jcob.moon
Jcob.moon
반가워요~ 하루하루 꾸준히 코딩 작성하는 곳입니다 !!
  • Jcob.moon
    Pixelated Thoughts
    Jcob.moon
  • 전체
    오늘
    어제
    • HelloWorld (178)
      • Daily Logs (126)
        • TIL (Today I Learned) (65)
        • Algorithm Practice (55)
        • Dev Book Notes (6)
      • Deep Dives (36)
        • 문제 해결 (Troubleshooting) (3)
        • CS Fundamentals (22)
        • Career Prep (4)
        • Technical Notes (7)
      • Project Log (7)
      • Any (3)
      • Cooperation (5)
        • Github (2)
        • Conventions (1)
        • Git (1)
        • Postman (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.3
Jcob.moon
DB part.4
상단으로

티스토리툴바