공공부하자개발 · 영어 학습 노트
자바
실무 확장Excel · 파일 업로드 · DB 연동0/22 완료
  • 01Excel(XLSX) 구조와 순수 JDK로 읽기/쓰기
  • 02Apache POI로 Excel 업로드/다운로드
  • 03파일 업로드/다운로드 서버 (HttpServer)
  • 04JDBC 기초와 트랜잭션 (H2)
  • 05MyBatis 어노테이션 매퍼로 쿼리 연동
  • 06MyBatis XML 매퍼 · Oracle 방언 · PageHelper · Spring Boot
  • 07REST API 서버와 JSON
  • 08Vue 3 SPA 와 Java 서버 연동
  • 09@Scheduled 운영
  • 10로깅 실무: 레벨·계층, MDC 추적, 예외·성능, 마스킹, 롤링, JSON 로그
  • 11외부 API 연동
  • 12테스트 실무
  • 13암호화·개인정보 보호
  • 14인코딩·한글 실무
  • 15@Transactional 심화
  • 16긴 작업 비동기 처리와 진행률
  • 17SFTP·FTP 파일 연계
  • 18로컬 캐시와 @Cacheable
  • 19메일·알림 발송
  • 20웹 보안 체크리스트
  • 21빌드 도구와 폐쇄망 의존성 반입
  • 22성능 측정: p50·p95·p99, 측정 계층, JFR, JMH 함정, 자체 부하 테스트, 병목 순위
사이트 소개개인정보처리방침연락처
© 2026 공부하자
홈 › 실무 확장 › 20 / 22

웹 보안 체크리스트

XSS·CSRF·SQL 인젝션·경로 탐색·업로드·IDOR·보안 헤더·의존성 취약점
섹션 7진행 0 / 22
1왜 배우는가2핵심 원리3코드 예제4응용 변형 예제5자주 하는 실수 (Tip)6연습 문제7정리‹ 이전다음 ›

2. 핵심 원리

체크리스트 13항목입니다. 항목마다 공격 지점과 방어 코드, Spring·MyBatis 적용 지점을 붙였습니다.

2.1 XSS (Cross-Site Scripting)

  • 무엇이 뚫리나: 사용자 입력을 그대로 HTML 에 출력하면 <script> 가 그대로 실행됩니다.
  • 어떻게 막나: 출력 시 &, <, >, ", ' 를 이스케이프하고 Content-Security-Policy 헤더를 붙입니다.
  • Spring·MyBatis 에서는: Vue 는 {{ }} 보간이 기본 이스케이프지만, v-html 로 서버 응답을 그대로 넣으면 이스케이프가 풀립니다.

2.2 CSRF (Cross-Site Request Forgery)

  • 무엇이 뚫리나: 로그인한 브라우저가 공격자 페이지의 요청을 자동으로 쿠키와 함께 보냅니다.
  • 어떻게 막나: 쿠키에 SameSite=Strict 또는 Lax 를 붙이고, 상태 변경 요청에 CSRF 토큰을 검증합니다.
  • Spring·MyBatis 에서는: Bearer JWT 는 쿠키 자동 전송이 없어 CSRF 에 강하지만, localStorage 저장 시 XSS 로 토큰이 탈취되는 트레이드오프가 있습니다.

2.3 SQL 인젝션

  • 무엇이 뚫리나: 사용자 입력이 SQL 문자열에 그대로 이어붙으면 조건절이 조작됩니다.
  • 어떻게 막나: 값은 바인드 파라미터로, 컬럼명·테이블명처럼 바인드가 안 되는 자리는 화이트리스트로 검증합니다.
  • Spring·MyBatis 에서는: #{} 는 PreparedStatement 바인딩이라 안전하지만, ${} 는 문자열 치환이라 ORDER BY 컬럼·테이블명에만 화이트리스트와 함께 씁니다.

2.4 경로 탐색 (Path Traversal)

  • 무엇이 뚫리나: 다운로드 파일명에 ../../etc/passwd 처럼 넣으면 기준 폴더 밖 파일을 읽어갑니다.
  • 어떻게 막나: 기준 폴더와 요청 경로를 합쳐 normalize() 한 뒤, 결과가 기준 폴더로 startsWith 하는지 검사합니다.
  • Spring·MyBatis 에서는: 첨부파일 서비스에서 DB 에는 원본 파일명만 저장하고, 실제 저장 경로는 서버가 만든 UUID 로 관리합니다.

2.5 업로드 검증

  • 무엇이 뚫리나: 확장자만 검사하면 photo.png 로 위장한 실행 스크립트가 업로드됩니다.
  • 어떻게 막나: 확장자 화이트리스트와 매직 바이트를 함께 검사하고, 크기 제한을 두고, 저장 파일명은 UUID 로 바꿉니다.
  • Spring·MyBatis 에서는: 업로드 폴더는 실행 권한이 없는 별도 디스크로 두고, 다운로드 시 Content-Disposition: attachment 로 강제 다운로드합니다.

2.6 인가 누락 (IDOR)

  • 무엇이 뚫리나: 로그인은 확인하지만 "이 데이터가 내 것인지"는 확인하지 않아, id 값만 바꾸면 남의 데이터가 보입니다.
  • 어떻게 막나: 컨트롤러가 아니라 서비스 계층에서 조회 대상의 소유자와 로그인 사용자를 비교합니다.
  • Spring·MyBatis 에서는: MyBatis 쿼리 자체에 WHERE owner_id = #{loginId} 조건을 넣어 DB 단에서도 한 번 더 걸러냅니다.

2.7 대량 할당 (Mass Assignment)

  • 무엇이 뚫리나: 요청 JSON 을 엔티티에 그대로 바인딩하면, isAdmin 같은 필드를 요청에 몰래 끼워 넣어 값을 바꿀 수 있습니다.
  • 어떻게 막나: 요청 전용 DTO 를 따로 두고, DTO 에 없는 필드는 애초에 바인딩되지 않게 합니다.
  • Spring·MyBatis 에서는: @RequestBody 는 DTO 로만 받고, 엔티티 변환은 서비스 계층에서 필드를 하나씩 매핑합니다.

2.8 보안 헤더 누락

  • 무엇이 뚫리나: 헤더가 없으면 브라우저가 MIME 스니핑, 클릭재킹, 평문 통신을 허용합니다.
  • 어떻게 막나: X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Strict-Transport-Security 를 공통으로 붙입니다.
  • Spring·MyBatis 에서는: 개인정보가 담긴 응답에는 Cache-Control: no-store 를 추가해 브라우저·프록시 캐시를 막습니다.

2.9 에러 노출

  • 무엇이 뚫리나: 예외를 그대로 응답에 담으면 스택트레이스, SQL 문, 내부 경로가 노출됩니다.
  • 어떻게 막나: 예외는 서버 로그에만 남기고, 클라이언트에는 07 레슨의 REST 에러 규격처럼 코드와 메시지만 내려줍니다.
  • Spring·MyBatis 에서는: @RestControllerAdvice 로 전역 예외 처리를 하나로 모아 실수로 원본 예외가 새는 지점을 없앱니다.

2.10 로그 인젝션

  • 무엇이 뚫리나: 사용자 입력을 로그에 그대로 남기면 CRLF 로 가짜 로그 줄을 끼워 넣어 로그를 위조합니다.
  • 어떻게 막나: 로그에 남기기 전 \r, \n 을 제거하고, 10 레슨 로깅 기준대로 개인정보는 마스킹합니다.
  • Spring·MyBatis 에서는: Logback 패턴에 사용자 입력을 그대로 넣지 말고, 항상 정리 함수를 거친 값만 넣습니다.

2.11 로그인 시도 제한·레이트 리밋

  • 무엇이 뚫리나: 시도 횟수 제한이 없으면 비밀번호를 무한정 대입해 볼 수 있습니다.
  • 어떻게 막나: 계정·IP 별로 실패 횟수를 세어 일정 횟수 이상이면 일정 시간 잠급니다.
  • Spring·MyBatis 에서는: 로그인 실패 횟수는 캐시(18 레슨)나 DB 컬럼에 두고, 성공 시 초기화합니다.

2.12 의존성 취약점

  • 무엇이 뚫리나: 오래된 라이브러리에 이미 공개된 CVE 가 있으면 공격자가 그대로 익스플로잇을 씁니다.
  • 어떻게 막나: 배포 전 사용 중인 jar 버전과 알려진 CVE 목록을 대조합니다.
  • Spring·MyBatis 에서는: 폐쇄망은 OWASP dependency-check 오프라인 DB 를 내려받아 쓰고, rpm -qa 결과와 jar 목록을 함께 점검합니다.

2.13 설정 노출

  • 무엇이 뚫리나: actuator 의 env, heapdump 엔드포인트나 .git, 백업 파일이 그대로 서빙되면 설정값과 소스가 유출됩니다.
  • 어떻게 막나: actuator 는 인증된 관리자만 접근하게 하고, 정적 파일 서버에서 .git, *.bak, *.sql 확장자를 차단합니다.
  • Spring·MyBatis 에서는: management.endpoints.web.exposure.include 는 필요한 것만 열고, env·heapdump 는 기본 차단합니다.

2.14 Spring Security 대응표

체크 항목 Spring Security 설정
CSRF csrf().csrfTokenRepository(...) 또는 세션 미사용 시 비활성화
세션 고정 sessionManagement().sessionFixation().migrateSession()
인가 authorizeHttpRequests() 로 경로별 권한 선언
비밀번호 저장 BCryptPasswordEncoder
로그인 실패 제한 AuthenticationFailureHandler 에서 실패 카운트
보안 헤더 headers().contentSecurityPolicy(...), frameOptions()
CORS cors().configurationSource(...) 로 허용 출처 명시

2.15 배포 전 점검표

  1. 모든 출력에 이스케이프가 적용됐는지 확인합니다.
  2. 상태 변경 API 에 CSRF 방어(토큰 또는 SameSite)가 있는지 확인합니다.
  3. MyBatis 매퍼에서 ${} 사용처를 모두 찾아 화이트리스트 여부를 확인합니다.
  4. 파일 다운로드·업로드 경로에 safePath 검증이 있는지 확인합니다.
  5. 업로드 확장자·매직 바이트·크기 제한이 모두 걸려 있는지 확인합니다.
  6. 상세 조회·수정 API 마다 소유자 검증이 있는지 확인합니다.
  7. 요청 DTO 와 엔티티가 분리돼 있는지 확인합니다.
  8. 공통 보안 헤더가 필터·인터셉터에 등록됐는지 확인합니다.
  9. 전역 예외 처리가 스택트레이스를 감추는지 확인합니다.
  10. 로그에 CRLF 제거와 개인정보 마스킹이 적용됐는지 확인합니다.
  11. 로그인 실패 제한이 실제로 동작하는지 테스트합니다.
  12. 사용 중인 jar 버전과 CVE 목록을 대조했는지 확인합니다.
  13. actuator 민감 엔드포인트가 차단됐는지 확인합니다.
  14. 정적 파일 서버가 .git, 백업 파일을 서빙하지 않는지 확인합니다.
  15. 개인정보 응답에 Cache-Control: no-store 가 있는지 확인합니다.
핵심 원리
  • 2.1 XSS (Cross-Site Scripting)
  • 2.2 CSRF (Cross-Site Request Forgery)
  • 2.3 SQL 인젝션
  • 2.4 경로 탐색 (Path Traversal)
  • 2.5 업로드 검증
  • 2.6 인가 누락 (IDOR)
  • 2.7 대량 할당 (Mass Assignment)
  • 2.8 보안 헤더 누락
  • 2.9 에러 노출
  • 2.10 로그 인젝션
  • 2.11 로그인 시도 제한·레이트 리밋
  • 2.12 의존성 취약점
  • 2.13 설정 노출
  • 2.14 Spring Security 대응표
  • 2.15 배포 전 점검표
이전 섹션1 왜 배우는가2 / 7다음 섹션3 코드 예제