공공부하자개발 · 영어 학습 노트
자바
실무 확장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정리‹ 이전다음 ›

3. 코드 예제

실행 방법입니다. 외부 jar 는 필요 없습니다.

cmd
cd java-src\extension\20_web_security
javac -encoding UTF-8 *.java
java Main --demo

Guard — 이스케이프·경로 검증·매직 바이트·화이트리스트

java
// 경로 탐색: 정규화 후 기준 폴더 밖이면 예외
public static Path safePath(Path baseDir, String name) {
    Path base = baseDir.normalize().toAbsolutePath();
    Path target = base.resolve(name).normalize().toAbsolutePath();
    if (!target.startsWith(base)) {
        throw new SecurityException("경로 탐색 시도: " + name);
    }
    return target;
}

// 업로드 검증: 확장자와 매직 바이트가 일치해야 통과
public static boolean checkMagic(byte[] bytes, String ext) {
    if (!ALLOWED_EXT.contains(ext.toLowerCase())) return false;
    return switch (ext.toLowerCase()) {
        case "png" -> startsWith(bytes, 0x89, 0x50, 0x4E, 0x47);
        case "pdf" -> startsWith(bytes, 0x25, 0x50, 0x44, 0x46);
        case "xlsx" -> startsWith(bytes, 0x50, 0x4B, 0x03, 0x04);
        default -> false;
    };
}

Main — IDOR 방어 핸들러

java
// 6. IDOR: 남의 주문을 user 파라미터로 조회하면 403
static void handleOrders(HttpExchange ex) throws IOException {
    Guard.secureHeaders(ex);
    ex.getResponseHeaders().set("Cache-Control", "no-store");
    String id = path.substring(path.lastIndexOf('/') + 1);
    String owner = ORDER_OWNER.get(id);
    if (!owner.equals(queryParam(ex, "user"))) {
        respond(ex, 403, "text/plain; charset=UTF-8", "다른 사용자의 주문입니다");
        return;
    }
    respond(ex, 200, "text/plain; charset=UTF-8", "주문 " + id + " 소유자: " + owner);
}

데모 실행 결과

java Main --demo 는 서버를 띄우고 공격 6가지와 정상 요청 1개를 실행한 뒤 스스로 종료합니다.

text
[XSS 시도] status=200 body=<html>...&lt;script&gt;alert(1)&lt;/script&gt;...
[경로 탐색 시도] status=403 body=경로 탐색 차단
[IDOR 시도(남의 주문)] status=403 body=다른 사용자의 주문입니다
[위조 업로드] status=400 body=매직 바이트 불일치, 업로드 거부
[정렬 컬럼 인젝션 시도] status=400 body=허용되지 않은 정렬 컬럼
[정상 요청] status=200 body=주문 1001 소유자: kim
[응답 헤더] X-Content-Type-Options=nosniff
[응답 헤더] Content-Security-Policy=default-src 'self'

예제 직접 실행

아래 폴더를 JDK 21 로 컴파일하고 실행합니다. 외부 jar 를 쓰는 레슨은 java-src/lib 를 클래스패스에 넣습니다.

cd java-src\extension\20_web_security
javac -encoding UTF-8 *.java && java Main

:: 외부 jar 가 필요한 레슨
javac -encoding UTF-8 -cp "..\..\lib\*;." *.java && java -cp "..\..\lib\*;." Main
코드 예제
  • Guard — 이스케이프·경로 검증·매직 바이트·화이트리스트
  • Main — IDOR 방어 핸들러
  • 데모 실행 결과
이전 섹션2 핵심 원리3 / 7다음 섹션4 응용 변형 예제