Skip to content

BackendFrameworkProgramming/RentalManagementSystem

Repository files navigation

로봇 임대관리시스템 - 3조

백엔드 프레임워크 프로그래밍 팀 프로젝트 웨어러블 로봇 디바이스 임대관리 시스템

기술 스택

  • Java 21 + Spring Boot 4.0.6 + JPA + Thymeleaf
  • MySQL 8.0 (원격 서버)
  • Gradle 9.4.1 (Wrapper)
  • MQTT (DrValue 라이브러리)
  • JWT 인증 (Access/Refresh Token) + 역할 기반 접근제어(RBAC)

접근 권한 (RBAC) 및 데이터 스코핑

로그인 주체는 센터 운영 측이며 역할 3종으로 구분한다. (디바이스 착용자/신청자는 로그인 주체가 아닌 관리 데이터)

역할 권한
ADMIN (관리자) 운영 화면 8종 + 관리 화면(모델·공통코드·에러로그·설계이력 등) 전체
STAFF (운영자) 운영 화면 8종 조회/관리
BRANCH_MANAGER (지점관리자) 본인 지점 데이터만 (목록·요약·디바이스 등 전 영역 스코핑)
  • 회원가입은 없고 ADMIN이 운영자/지점관리자 계정을 생성한다.
  • JWT에 역할·지점ID를 담아 서비스 계층(SecurityUtil)에서 본인 지점만 조회하도록 강제(IDOR 방어).

코드 품질 (교수님 최종 코드리뷰 반영)

교수님 최종 피드백 5종을 전 도메인에 반영했다.

  1. 페이징 후 필터 (전체 적재 금지)
  2. findAll().stream() 순회 → exists 쿼리로 대체
  3. 카운트는 엔티티 적재 없이 count 쿼리로
  4. Map 응답 → 요청/응답 DTO
  5. 문자열 상태값 → Enum (@Enumerated(STRING))

추가로 N+1은 @EntityGraph/JOIN FETCH·집계 쿼리로 방어하고, 막바지에 팀 전체 코드 유지보수 점검(N+1·동시성 race·소프트삭제 일관성·필수값 유효성)을 한 차례 더 수행했다.

DB 접속 정보

항목
Host 101.79.16.88
Port 3306
Database team3
User team3
Password 팀 내부 채널로 별도 공유 (보안상 README 미기재)
mysql -h 101.79.16.88 -u team3 -p team3

실행 방법

  1. 프로젝트 clone
git clone https://github.com/BackendFrameworkProgramming/RentalManagementSystem.git
  1. IntelliJ에서 열기 -> Gradle 빌드 대기

  2. RentalManagementSystemApplication.java 실행

  3. 브라우저에서 http://localhost:8083/login 접속

Java 21 필요. 로컬에 JDK 21이 없어도 settings.gradle의 foojay-resolver 플러그인이 Gradle 빌드 시 JDK 21을 자동으로 내려받습니다. (단, java -jar 직접 실행에는 JDK 21 런타임 필요)

환경변수 (보안 설정)

민감 정보와 운영 설정은 환경변수로 주입할 수 있습니다. 설정하지 않으면 안전한 기본값으로 동작하므로 로컬 실행 시 별도 설정 없이 그대로 돌아갑니다. 운영 서버에서는 아래 값을 환경변수로 주입하세요.

환경변수 용도 기본값
DB_USERNAME DB 계정 team3
DB_PASSWORD DB 비밀번호 (코드 기본값 — 운영 시 반드시 주입 권장)
JWT_SECRET JWT 서명 키 (코드 기본값 — 운영 시 반드시 주입 권장)
JPA_SHOW_SQL SQL 콘솔 출력 false (로컬 디버깅 시 true)
JPA_FORMAT_SQL SQL 포맷 출력 false
LOG_SQL_LEVEL Hibernate SQL 로그 레벨 WARN
LOG_APP_LEVEL 애플리케이션 로그 레벨 INFO

⚠️ 현재 DB 비밀번호/JWT 시크릿의 기본값은 과거 git 히스토리에 노출된 적이 있습니다. 실제 운영 보안을 위해서는 비밀번호 교체 + 환경변수 주입이 필요합니다.

예) 로컬에서 SQL 보면서 디버깅:

JPA_SHOW_SQL=true ./gradlew bootRun

보안 (OWASP Top 10 대응)

수업에서 다룬 OWASP Top 10 항목을 코드에 반영했습니다.

  • A01 접근 통제: 회원가입(계정 생성)은 ADMIN만 가능. 관리 화면/API는 역할 기반 접근제어(RBAC) 적용
  • A02 암호화 실패: 비밀번호는 BCrypt 단방향 해시. DB 비번/JWT 시크릿은 환경변수로 외부화
  • A05 보안 설정 오류: SQL/상세 로그 운영 기본값 off (내부 구조 노출 방지). 보안 HTTP 응답 헤더 6종(HSTS·CSP·Referrer-Policy·Permissions-Policy·X-Frame-Options·X-Content-Type-Options)을 SecurityConfig에 적용
  • A06 취약 구성요소: 의존성 버전은 Spring BOM으로 고정(결정적 빌드)
  • A07 인증 실패: 로그인 5회 실패 시 5분 일시 잠금 (LoginAttemptService, 무차별 대입 방어)
  • A09/A10 로깅·예외 처리: 예외 응답에는 일반 메시지만, 상세(스택 트레이스)는 서버 로그/DB에만 기록

향후 보안 과제 (TODO)

아직 처리하지 않았거나 추가 검토가 필요한 항목입니다.

  • A01 접근 통제 — 회원가입 정책 재검토: 현재 회원가입을 ADMIN 전용으로 제한했으나, 시연/운영 시나리오에 따라 일반 가입 허용 여부를 다시 결정할 것. 더불어 본인 리소스만 접근 가능한지(IDOR) 메소드 단위 권한 검증도 함께 검토.
  • DB 비밀번호 / JWT 시크릿 교체: 환경변수로 외부화는 했으나 기존 값이 git 히스토리에 남아 있음. 근본 해결을 위해 실제 비밀번호/시크릿을 교체할 것.
  • 의존성 취약점 스캔 (A06): OWASP dependency-check를 별도 CI 환경에서 실행해 취약 라이브러리 점검. (Gradle 플러그인 직접 적용은 의존성 충돌로 보류)
  • 배포 전 보안 점검 절차화: 런칭 전 보안 점검 툴 1회 실행 + AI 코드 검증을 거쳐 배포하는 절차를 팀 규칙으로 정착. (교수님 강조 사항) → HTTPS 적용 완료 후 점검 도구 선정: Nikto(서버 CLI), securityheaders.com / CryptCheck(웹). :8083 비표준 포트라 SSL Labs·Mozilla Observatory(443 전용)는 사용 불가.

보안 점검 (배포 전 스캔)

배포 전 1회 보안 점검 — 교수님 강조 사항. 점검 대상: https://rms.o-r.kr:8083

:8083 비표준 포트라 SSL Labs·Mozilla Observatory(443 전용)는 사용 불가 → 아래 3종으로 대체.

3종 점검 모두 완료. 결과 화면 캡처는 제출물/노션에 첨부했다.

도구 점검 항목 담당 상태 결과 요약
Nikto 웹서버 취약점·설정오류 김규민 ✅ 완료 취약점 0건 검출 (무결성 확인). 경고 1건은 앱(SecurityConfig)에서 정상 방어 중.
securityheaders.com 보안 HTTP 헤더 등급 정은혜 ✅ 완료 보안 헤더 6종을 앱(SecurityConfig)에 적용 → 등급 A 달성
CryptCheck.fr TLS 등급 전민석 ✅ 완료 nginx에 TLS 1.3 + AEAD cipher 적용, SHA1/CBC 제거 → 등급 E에서 A+ 달성

실행 방법

# 김규민 — Nikto (서버 SSH)
sudo apt install -y nikto
nikto -h https://rms.o-r.kr:8083
  • 정은혜 — securityheaders.com 접속 후 입력칸에 https://rms.o-r.kr:8083 → Scan
  • 전민석 — CryptCheck.fr 접속 후 입력칸에 rms.o-r.kr:8083 → 검사

HTTP 보안 헤더(HSTS·CSP·Referrer-Policy·Permissions-Policy·X-Frame-Options·X-Content-Type-Options)는 앱 코드(SecurityConfig)에서 적용 완료 → securityheaders.com 등급 A 달성. ⚠️ nginx에 동일 헤더를 또 추가하면 응답 헤더가 중복(특히 CSP)되므로, 보안 헤더는 앱 한 곳에서만 관리한다. nginx에서는 TLS 프로토콜/cipher 등급 보강만 담당.

배포 (Deployment)

운영 서버에 배포되어 있습니다.

기존 http://101.79.16.88:8083 직접 접속은 현재 nginx가 8083을 TLS로 점유하므로 더 이상 평문 HTTP로 열리지 않습니다. 위 HTTPS 도메인으로 접속하세요.

HTTPS / TLS 구성 (2026-06-10 적용)

ACG(클라우드 방화벽)가 80/443을 막고 8083만 열려 있어, 이미 열린 8083을 nginx가 TLS로 점유하고 실제 Spring 앱은 내부 포트(9083)로 옮기는 방식으로 HTTPS를 적용했다.

[브라우저] --HTTPS--> nginx (0.0.0.0:8083, TLS 종료) --HTTP--> Spring 앱 (127.0.0.1:9083)
구성
도메인 rms.o-r.kr (내도메인.한국 무료 도메인, A레코드 → 101.79.16.88)
인증서 Let's Encrypt — DNS-01 수동 인증 (HTTP-01은 80포트 미개방으로 불가)
인증서 경로 /etc/letsencrypt/live/rms.o-r.kr/
만료일 2026-09-07 (수동 발급 — 자동 갱신 안 됨, 갱신 시 certbot 명령 재실행)
nginx 설정 /etc/nginx/sites-available/rms.o-r.kr (8083 ssl → 127.0.0.1:9083)
앱 포트 127.0.0.1:9083 (config/application.properties 오버라이드)
프로세스 관리 PM2 (name: team_3, id 2) — pm2 restart team_3

서버 포트 오버라이드 — git pull 안전

nginx 뒤에서 앱은 9083으로 떠야 하지만, 추적되는 src/main/resources/application.properties는 레포 원본(8083) 그대로 둔다. 서버 전용 설정은 추적되지 않는 config/application.properties에 두어, Spring Boot가 classpath 설정보다 우선 로드하게 한다:

# ~/team/team3/RentalManagementSystem/config/application.properties  (서버 전용, git 추적 안 됨)
server.port=9083
server.address=127.0.0.1
server.forward-headers-strategy=framework

이 파일은 .git/info/exclude/config/로 등록돼 커밋되지 않으므로, 서버에서 git pull 해도 충돌·원복이 없다. 배포는 평소대로:

git pull origin main && pm2 restart team_3

서버 SSH 접속

Windows PowerShell 또는 터미널에서:

ssh root@101.79.16.88
  • 비밀번호 입력 시 화면에 아무것도 안 보이는 게 정상입니다. 그대로 입력 후 Enter.
  • 서버 IP / 계정 / 비밀번호 등 접속 정보는 팀 내부 채널로 별도 공유합니다. (보안상 미기재)

서버에서 배포/갱신 절차

앱은 PM2로 관리되며 nginx(8083 TLS)가 내부 앱(9083)으로 프록시한다.

cd ~/team/team3/RentalManagementSystem
git pull origin main
./gradlew clean build -x test
pm2 restart team_3      # 앱 재기동
pm2 logs team_3         # 로그 확인 (Started ... 후 Ctrl+C)

트러블슈팅git pullgradle-wrapper.jar would be overwritten 에러가 나면, 추적되지 않는 jar이 남아있는 경우입니다. rm gradle/wrapper/gradle-wrapper.jar 후 다시 git pull 하세요.

기본 계정

앱 최초 실행 시 관리자 계정이 자동 생성됩니다 (DataInitializer).

  • 아이디: admin
  • 비밀번호: 팀 내부 채널로 공유 (소스 DataInitializer.java 참고)

일반 회원 비밀번호는 단방향 암호화되어 저장되므로 복호화로 조회할 수 없습니다. 잊은 경우 재가입하거나 DB에서 해시를 갱신해야 합니다.

담당 배정

담당 화면 / 도메인 패키지 대표 기여
윤태웅 (PM) 화면1 디바이스 + 모델 + 화면6 센터 + 에러로그 + 공통코드 + 사용자 + MQTT taewoong/ 공통구조·인증(JWT/RBAC)·배포(HTTPS)·전 도메인 리팩토링
전민석 화면5 지점 + 화면7 부서/팀 minseok/ 부서삭제 exists화 · CryptCheck TLS A+
정은혜 화면8 직원 + 화면3 생체/응급 eunhye/ 3N+1 집계쿼리 · 보안헤더 A · 팀 전체 유지보수 점검
김규민 화면2 임대 + 화면4 AS gyumin/ AS 상태전이 가드 · Nikto 취약점 0건

프로젝트 구조

src/main/java/hanyang/RentalManagementSystem/
  common/           <- Entity, Repository, DTO, 공통 구조 (PM)
  taewoong/         <- 디바이스, 모델, 센터, 코드, 사용자, MQTT, 에러로그
  minseok/          <- 지점, 부서/팀 (전민석)
  eunhye/           <- 직원, 생체/응급 (정은혜)
  gyumin/           <- 임대, AS (김규민)

src/main/resources/
  templates/        <- Thymeleaf HTML
  static/           <- CSS, JS
  application.properties

Git 규칙

  • PM이 common/(공통 구조)을 단일 관리 → 머지 충돌 방지
  • 팀원은 본인 폴더(minseok, eunhye, gyumin)에서 작업
  • 후반 공통/레포지토리 수정이 필요하면 톡방에서 점유 확인 후 진행
  • 작업 전 pull, 작업 후 commit -> pull -> push
git pull origin main
git add .
git commit -m "작업내용"
git pull origin main
git push origin main

변경 이력

2026-06-15 — 팀 전체 코드 유지보수 점검 (정은혜)

  • N+1 제거: 생체정보 목록 3N+1(@EntityGraph + 응급기록 묶음조회), 지점 목록 N+1(담당자 IN 묶음조회)
  • 회원가입 동시성 race 방어: existsBy~save 사이 유니크 위반을 try-catch(saveAndFlush)로 409 처리 (교수님 ③)
  • 소프트삭제 일관성: findByIdfindByIdAndIsDeletedFalse (지점담당자/임대/AS/생체)
  • 필수값 유효성 보강: 모델·공통코드·지점·부서팀·직원·생체 생성 검증 추가 (교수님 ⑤)

2026-06-13 — 지점관리자 데이터 스코핑 완성

  • BRANCH_MANAGER는 목록·디바이스·좌측 '지점별 요약' 패널까지 본인 지점만 조회

2026-06-12 — 역할 모델 정립 + 전 도메인 리팩토링 (교수님 최종 피드백)

  • 역할 ADMIN/STAFF/BRANCH_MANAGER 확정, 사용자 관리(생성/수정) 기능 추가
  • 교수님 최종 코드리뷰 5종(페이징·exists·count·DTO·Enum)을 전 도메인 반영, N+1 @EntityGraph 방어

2026-06-10 — 보안 HTTP 응답 헤더 적용 (securityheaders.com 대응)

  • 보안 헤더 6종 추가 (common/config/SecurityConfig.java.headers()): HSTS / CSP / Referrer-Policy / Permissions-Policy / X-Frame-Options / X-Content-Type-Options
  • HSTS: 앞단 nginx가 TLS 종료(앱은 평문 HTTP 수신)하므로 AnyRequestMatcher로 모든 요청에 방출, max-age 1년
  • CSP: default-src 'self' 기반(실용형). 템플릿 인라인 스크립트/onclick/style 다수로 script/style-src'unsafe-inline' 허용 → 등급 A (A+는 nonce 리팩터링 필요)
  • 적용 위치: nginx가 아닌 앱 코드 한 곳에서 관리 (nginx 중복 추가 시 헤더 중복 발생)
  • 로컬 기동 후 curl -I로 6종 헤더 응답 확인
  • 담당: 정은혜

2026-06-10 — HTTPS(TLS) 적용 및 보안 점검 환경 구축

  • 무료 도메인 발급: rms.o-r.kr (내도메인.한국, A레코드 → 101.79.16.88)
  • Let's Encrypt 인증서 발급: DNS-01 수동 인증 (ACG 80/443 미개방으로 HTTP-01 불가)
  • nginx 리버스 프록시 구성: 8083을 nginx가 TLS 종료 → 내부 127.0.0.1:9083 앱으로 전달
  • 앱 포트 이동: 8083 → 9083 (추적 안 되는 config/application.properties로 오버라이드 → git pull 안전)
  • 리다이렉트 정상화: X-Forwarded-Host/Port 헤더 추가로 프록시 뒤 스킴/포트 유실 해결
  • 접속 주소: https://rms.o-r.kr:8083/login
  • 자세한 구성·주의사항은 배포 > HTTPS / TLS 구성 참고

2026-05-30 — Java 21 업그레이드 및 서버 배포

  • Java 17 → 21 업그레이드 (build.gradle toolchain 버전 상향)
  • Gradle toolchain 자동 조달: settings.gradle에 foojay-resolver 플러그인 추가 → JDK 21 자동 다운로드
  • gradle-wrapper.jar 추가: git에 누락돼 있던 wrapper jar 커밋 (clone 후 ./gradlew 실행 가능)
  • 서버 포트 8080 → 8083 변경 (application.properties)
  • NCP Ubuntu 서버 배포: clone → 빌드 → 실행, http://101.79.16.88:8083 구동 확인

About

임대 관리 시스템 팀 프로젝트

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors