OWASP Top 10(2025)

OWASP Top 10:2025. 4๋…„ ๋งŒ์— ๊ฐœ์ •๋œ ์›น ๋ณด์•ˆ ์œ„ํ˜‘ ํ‘œ์ค€. ์ƒˆ๋กœ ์ถ”๊ฐ€๋œ ๊ณต๊ธ‰๋ง·์˜ˆ์™ธ ์ฒ˜๋ฆฌ ํ•ญ๋ชฉ๋ถ€ํ„ฐ 1์œ„ ์ ‘๊ทผ ์ œ์–ด๊นŒ์ง€, ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž๊ฐ€ ์•Œ์•„์•ผ ํ•  10๊ฐ€์ง€๋ฅผ ์‹ค์ œ ๊ณต๊ฒฉ ์˜ˆ์‹œ์™€ ๋Œ€์‘ ์ฝ”๋“œ๋กœ ์ •๋ฆฌํ•œ๋‹ค.


๋“ค์–ด๊ฐ€๋ฉฐ

2025๋…„ 11์›”, OWASP๊ฐ€ 4๋…„ ๋งŒ์— Top 10์„ ๊ฐœ์ •ํ–ˆ๋‹ค.
OWASP Top 10์€ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ณด์•ˆ ์œ„ํ˜‘์„ ๋นˆ๋„์™€ ์˜ํ–ฅ๋„ ๊ธฐ์ค€์œผ๋กœ ์ถ”๋ฆฐ ์‚ฌ์‹ค์ƒ์˜ ์—…๊ณ„ ํ‘œ์ค€ ๋ฌธ์„œ๋‹ค.
2021๋…„ ํŒ์„ ๊ธฐ์ค€์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์งœ์˜จ ์‚ฌ๋žŒ์ด๋ผ๋ฉด, ์ด๋ฒˆ์— ๋ฐ”๋€ ํ•ญ๋ชฉ๋“ค์„ ํ•œ ๋ฒˆ ์งš๊ณ  ๋„˜์–ด๊ฐˆ ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

๋ณด์•ˆ์€ "๋‚˜์ค‘์— ๋ถ™์ด๋Š” ๊ธฐ๋Šฅ"์ด ์•„๋‹ˆ๋ผ ์„ค๊ณ„ ๋‹จ๊ณ„๋ถ€ํ„ฐ ๊ณ ๋ คํ•˜๋Š” ๊ธฐ๋ณธ๊ฐ’์ด๋‹ค. OWASP Top 10์€ ๊ทธ ์ถœ๋ฐœ์ ์ด๋‹ค.

์ด ๊ธ€์—์„œ๋Š” 2025๋…„ ํŒ 10๊ฐ€์ง€ ํ•ญ๋ชฉ์„ ๋ฌด์—‡์ด ๋ฐ”๋€Œ์—ˆ๋Š”์ง€์™€ ํ•จ๊ป˜, ๊ฐ ํ•ญ๋ชฉ์˜ ์‹ค์ œ ๊ณต๊ฒฉ ์˜ˆ์‹œ + ๋Œ€์‘ ๋ฐฉ๋ฒ•์„ ์ฝ”๋“œ๋กœ ์ •๋ฆฌํ•œ๋‹ค.
์˜ˆ์‹œ๋Š” Java/Spring ๊ธฐ์ค€์ด๋‹ค.

์ฐธ๊ณ  — "2023๋…„์—๋„ ๊ฐœ์ •๋˜์ง€ ์•Š์•˜๋‚˜?"
ํ—ท๊ฐˆ๋ฆฌ๊ธฐ ์‰ฌ์šด๋ฐ, OWASP์—๋Š” ์—ฌ๋Ÿฌ ์ข…๋ฅ˜์˜ Top 10์ด ์žˆ๋‹ค.
์ด ๊ธ€์ด ๋‹ค๋ฃจ๋Š” ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์šฉ OWASP Top 10์€ 2017 → 2021 → 2025 ์ˆœ์œผ๋กœ ๊ฐœ์ •๋๊ณ ,
๊ทธ ์‚ฌ์ด(2023๋…„)์— ๋‚˜์˜จ ๊ฒƒ์€ API ์ „์šฉ์ธ OWASP API Security Top 10 2023์œผ๋กœ ๋ณ„๊ฐœ์˜ ๋ฌธ์„œ๋‹ค.
API ๋ฒ„์ „์€ ๋ณ„๋„ ๊ธ€์—์„œ ๋‹ค๋ฃฌ๋‹ค.


2021 → 2025, ๋ฌด์—‡์ด ๋ฐ”๋€Œ์—ˆ๋‚˜

์ด๋ฒˆ ๊ฐœ์ •์˜ ํ•ต์‹ฌ์€ "์ฆ์ƒ์ด ์•„๋‹ˆ๋ผ ๊ทผ๋ณธ ์›์ธ"์— ์ดˆ์ ์„ ๋งž์ถ˜ ๊ฒƒ์ด๋‹ค. ํฐ ๋ณ€ํ™”๋Š” ์„ธ ๊ฐ€์ง€๋‹ค.

  • ์‹ ๊ทœ 2๊ฐœ: A03 ์†Œํ”„ํŠธ์›จ์–ด ๊ณต๊ธ‰๋ง ์‹คํŒจ, A10 ์˜ˆ์™ธ ์ƒํ™ฉ ์ฒ˜๋ฆฌ ๋ฏธํก
  • ํ†ตํ•ฉ: ๊ธฐ์กด ๋‹จ๋… ํ•ญ๋ชฉ์ด๋˜ SSRF(์„œ๋ฒ„ ์ธก ์š”์ฒญ ์œ„์กฐ)๊ฐ€ A01 ์ ‘๊ทผ ์ œ์–ด๋กœ ํก์ˆ˜๋จ
  • ํ™•์žฅ: ๊ธฐ์กด "์ทจ์•ฝํ•˜๊ณ  ์˜ค๋ž˜๋œ ์ปดํฌ๋„ŒํŠธ"๊ฐ€ "์†Œํ”„ํŠธ์›จ์–ด ๊ณต๊ธ‰๋ง ์‹คํŒจ"๋กœ ๋ฒ”์œ„ ํ™•๋Œ€

์ „์ฒด ์ˆœ์œ„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

์ˆœ์œ„ ํ•ญ๋ชฉ 2021 ๋Œ€๋น„
A01 Broken Access Control (์ ‘๊ทผ ์ œ์–ด ์‹คํŒจ) 1์œ„ ์œ ์ง€ (+SSRF ํก์ˆ˜)
A02 Security Misconfiguration (๋ณด์•ˆ ์„ค์ • ์˜ค๋ฅ˜) 5์œ„ → 2์œ„ โ–ฒ
A03 Software Supply Chain Failures (๊ณต๊ธ‰๋ง ์‹คํŒจ) ํ™•์žฅ โ–ฒ
A04 Cryptographic Failures (์•”ํ˜ธํ™” ์‹คํŒจ) 2์œ„ → 4์œ„ โ–ผ
A05 Injection (์ธ์ ์…˜) 3์œ„ → 5์œ„ โ–ผ
A06 Insecure Design (์•ˆ์ „ํ•˜์ง€ ์•Š์€ ์„ค๊ณ„) 4์œ„ → 6์œ„ โ–ผ
A07 Authentication Failures (์ธ์ฆ ์‹คํŒจ) 7์œ„ ์œ ์ง€
A08 Software or Data Integrity Failures (๋ฌด๊ฒฐ์„ฑ ์‹คํŒจ) 8์œ„ ์œ ์ง€
A09 Security Logging & Alerting Failures (๋กœ๊น…·์•Œ๋ฆผ ์‹คํŒจ) 9์œ„ ์œ ์ง€
A10 Mishandling of Exceptional Conditions (์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๋ฏธํก) ์‹ ๊ทœ โ˜…

A01. Broken Access Control — ์ ‘๊ทผ ์ œ์–ด ์‹คํŒจ

3๋…„ ์—ฐ์† 1์œ„. ๊ฐ€์žฅ ํ”ํ•˜๊ณ , ๊ฐ€์žฅ ์œ„ํ—˜ํ•˜๋‹ค. ์ธ์ฆ(๋กœ๊ทธ์ธ)์€ ๋์ง€๋งŒ ์ธ๊ฐ€(๊ถŒํ•œ)๊ฐ€ ๋ถ€์‹คํ•œ ๊ฒฝ์šฐ๋‹ค.

// ์ทจ์•ฝ: ๋ณธ์ธ ํ™•์ธ ์—†์ด ํŒŒ๋ผ๋ฏธํ„ฐ์˜ id๋ฅผ ๊ทธ๋Œ€๋กœ ์‹ ๋ขฐ
@GetMapping("/api/orders/{orderId}")
public Order getOrder(@PathVariable Long orderId) {
    return orderRepository.findById(orderId).orElseThrow();
    // orderId๋งŒ ๋ฐ”๊พธ๋ฉด ๋‚จ์˜ ์ฃผ๋ฌธ๋„ ์กฐํšŒ๋œ๋‹ค (IDOR ์ทจ์•ฝ์ )
}

orderId=1001์„ 1002๋กœ ๋ฐ”๊พธ๋ฉด ๋‚จ์˜ ์ฃผ๋ฌธ์ด ๋ณด์ธ๋‹ค. ์ด๊ฑธ IDOR(Insecure Direct Object Reference)๋ผ๊ณ  ํ•œ๋‹ค.

// ๋Œ€์‘: ๋ฆฌ์†Œ์Šค์˜ ์†Œ์œ ์ž๊ฐ€ ์š”์ฒญ์ž ๋ณธ์ธ์ธ์ง€ ๊ฒ€์ฆ
@GetMapping("/api/orders/{orderId}")
public Order getOrder(@PathVariable Long orderId,
                      @AuthenticationPrincipal UserDetails user) {
    Order order = orderRepository.findById(orderId).orElseThrow();
    if (!order.getUserId().equals(user.getId())) {
        throw new AccessDeniedException("๋ณธ์ธ์˜ ์ฃผ๋ฌธ๋งŒ ์กฐํšŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค");
    }
    return order;
}

๋Œ€์‘ ์š”์•ฝ: ๋ชจ๋“  ๋ฆฌ์†Œ์Šค ์ ‘๊ทผ์— ์†Œ์œ ๊ถŒ·๊ถŒํ•œ์„ ๊ฒ€์ฆํ•œ๋‹ค. ๊ธฐ๋ณธ์€ "๊ฑฐ๋ถ€", ๋ช…์‹œ์ ์œผ๋กœ ํ—ˆ์šฉ๋œ ๊ฒƒ๋งŒ ํ†ต๊ณผ์‹œํ‚จ๋‹ค(deny by default).
์ด๋ฒˆ ํŒ๋ถ€ํ„ฐ SSRF๋„ ์ด ์นดํ…Œ๊ณ ๋ฆฌ์— ํฌํ•จ๋˜๋ฏ€๋กœ, ์™ธ๋ถ€ URL์„ ๋ฐ›์•„ ์„œ๋ฒ„๊ฐ€ ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ๋Š” ๋‚ด๋ถ€๋ง·๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ฃผ์†Œ(์˜ˆ: 196.254.169.254)๋ฅผ ์ฐจ๋‹จํ•ด์•ผ ํ•œ๋‹ค.


A02. Security Misconfiguration — ๋ณด์•ˆ ์„ค์ • ์˜ค๋ฅ˜

5์œ„์—์„œ 2์œ„๋กœ ํฌ๊ฒŒ ์˜ฌ๋ž๋‹ค. ์„ค์ • ๊ธฐ๋ฐ˜ ๋™์ž‘์ด ๋Š˜๋ฉด์„œ misconfiguration๋„ ํ•จ๊ป˜ ๋Š˜์—ˆ๋‹ค.
๊ธฐ๋ณธ ๋น„๋ฐ€๋ฒˆํ˜ธ, ๋ถˆํ•„์š”ํ•˜๊ฒŒ ์—ด๋ฆฐ ๋””๋ฒ„๊ทธ ๋ชจ๋“œ, ๊ณผ๋„ํ•œ ์—๋Ÿฌ ๋…ธ์ถœ ๋“ฑ์ด ํ•ด๋‹น๋œ๋‹ค.

# ์ทจ์•ฝ: ์šด์˜ ํ™˜๊ฒฝ์—์„œ ์ƒ์„ธ ์—๋Ÿฌ์™€ ๋””๋ฒ„๊ทธ ๋…ธ์ถœ
server:
  error:
    include-stacktrace: always   # ์ŠคํƒํŠธ๋ ˆ์ด์Šค๊ฐ€ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋…ธ์ถœ
spring:
  h2:
    console:
      enabled: true              # ์šด์˜์— H2 ์ฝ˜์†”์ด ์—ด๋ ค ์žˆ์Œ
# ๋Œ€์‘: ์šด์˜ ํ”„๋กœํŒŒ์ผ์—์„œ๋Š” ์ตœ์†Œ ์ •๋ณด๋งŒ
server:
  error:
    include-stacktrace: never
    include-message: never
spring:
  h2:
    console:
      enabled: false

๋Œ€์‘ ์š”์•ฝ: ์šด์˜/๊ฐœ๋ฐœ ์„ค์ •์„ ํ”„๋กœํŒŒ์ผ๋กœ ๋ถ„๋ฆฌํ•˜๊ณ , ๊ธฐ๋ณธ ๊ณ„์ •·์ƒ˜ํ”Œ ํŽ˜์ด์ง€·๋ถˆํ•„์š”ํ•œ ํฌํŠธ๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค.
๋ณด์•ˆ ํ—ค๋”(HSTS, X-Content-Type-Options ๋“ฑ)๋ฅผ ๊ธฐ๋ณธ ์ ์šฉํ•œ๋‹ค.


A03. Software Supply Chain Failures — ๊ณต๊ธ‰๋ง ์‹คํŒจ (์‹ ๊ทœ)

์ด๋ฒˆ์— ๊ฐ€์žฅ ์ฃผ๋ชฉ๋ฐ›์€ ์‹ ๊ทœ ํ•ญ๋ชฉ. ๋‚ด๊ฐ€ ์ง  ์ฝ”๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ ๋‚ด๊ฐ€ ๊ฐ€์ ธ๋‹ค ์“ด ์˜์กด์„ฑ์—์„œ ์‚ฌ๊ณ ๊ฐ€ ๋‚œ๋‹ค.
์˜คํ”ˆ์†Œ์Šค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, ๋นŒ๋“œ ์‹œ์Šคํ…œ, ๋ฐฐํฌ ์ธํ”„๋ผ ์ „์ฒด๊ฐ€ ๊ณต๊ฒฉ ํ‘œ๋ฉด์ด๋‹ค. Log4Shell์ด ๋Œ€ํ‘œ์  ์‚ฌ๋ก€๋‹ค.

# ๋Œ€์‘ 1: ์˜์กด์„ฑ ์ทจ์•ฝ์  ์Šค์บ”์„ ๋นŒ๋“œ์— ํฌํ•จ
./gradlew dependencyCheckAnalyze   # OWASP Dependency-Check

# ๋Œ€์‘ 2: ์•Œ๋ ค์ง„ ์ทจ์•ฝ์  ํ™•์ธ
npm audit
// ๋Œ€์‘ 3: ์˜์กด์„ฑ ๋ฒ„์ „ ๊ณ ์ • + ์ถœ์ฒ˜ ๊ฒ€์ฆ
dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web:3.4.1")
    // ๋ฒ„์ „์„ ๋ช…์‹œ์ ์œผ๋กœ ๊ณ ์ • (latest, + ๊ฐ™์€ ๋™์  ๋ฒ„์ „ ๊ธˆ์ง€)
}

๋Œ€์‘ ์š”์•ฝ: ์˜์กด์„ฑ ๋ฒ„์ „์„ ๊ณ ์ •ํ•˜๊ณ , CI์— ์ทจ์•ฝ์  ์Šค์บ”(Dependency-Check, Snyk, Dependabot)์„ ๋„ฃ๋Š”๋‹ค.
SBOM(์†Œํ”„ํŠธ์›จ์–ด ์ž์žฌ ๋ช…์„ธ์„œ)์„ ๊ด€๋ฆฌํ•ด ๋ฌด์—‡์„ ์“ฐ๊ณ  ์žˆ๋Š”์ง€ ์ถ”์ ํ•œ๋‹ค.


A04. Cryptographic Failures — ์•”ํ˜ธํ™” ์‹คํŒจ

๋ฏผ๊ฐ ๋ฐ์ดํ„ฐ๋ฅผ ํ‰๋ฌธ์œผ๋กœ ์ €์žฅํ•˜๊ฑฐ๋‚˜, ์•ฝํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์“ฐ๋Š” ๊ฒฝ์šฐ๋‹ค. ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋‹จ์ˆœ ํ•ด์‹ฑํ•˜๋Š” ๊ฒŒ ๋Œ€ํ‘œ์  ์‹ค์ˆ˜๋‹ค.

// ์ทจ์•ฝ: SHA-256 ๋‹จ์ˆœ ํ•ด์‹ฑ (๋ ˆ์ธ๋ณด์šฐ ํ…Œ์ด๋ธ”์— ์ทจ์•ฝ, ๋„ˆ๋ฌด ๋น ๋ฆ„)
String hashed = DigestUtils.sha256Hex(password);
// ๋Œ€์‘: bcrypt ๊ฐ™์€ ๋А๋ฆฐ ํ•ด์‹œ + ์ž๋™ ์†”ํŠธ
@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();   // ์†”ํŠธ ์ž๋™ ์ƒ์„ฑ, ์˜๋„์ ์œผ๋กœ ๋А๋ฆผ
}

// ์‚ฌ์šฉ
String hashed = passwordEncoder.encode(rawPassword);
boolean matches = passwordEncoder.matches(rawPassword, hashed);

๋Œ€์‘ ์š”์•ฝ: ๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” bcrypt/Argon2 ๊ฐ™์€ ์ ์‘ํ˜• ํ•ด์‹œ๋กœ ์ €์žฅํ•œ๋‹ค.
์ „์†ก ๊ตฌ๊ฐ„์€ TLS, ์ €์žฅ ๋ฐ์ดํ„ฐ๋Š” AES-256์œผ๋กœ ์•”ํ˜ธํ™”ํ•œ๋‹ค.
MD5·SHA-1·DES ๊ฐ™์€ ์•ฝํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์“ฐ์ง€ ์•Š๋Š”๋‹ค.


A05. Injection — ์ธ์ ์…˜

SQL Injection, XSS ๋“ฑ์„ ํฌํ•จํ•œ๋‹ค. ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ ์ฝ”๋“œ/์ฟผ๋ฆฌ์˜ ์ผ๋ถ€๋กœ ์‹ ๋ขฐํ•  ๋•Œ ๋ฐœ์ƒํ•œ๋‹ค.

// ์ทจ์•ฝ: ๋ฌธ์ž์—ด ๊ฒฐํ•ฉ์œผ๋กœ ์ฟผ๋ฆฌ ์ƒ์„ฑ
String sql = "SELECT * FROM users WHERE email = '" + email + "'";
// email์— "' OR '1'='1" ๋ฅผ ๋„ฃ์œผ๋ฉด ์ „์ฒด ํ–‰์ด ๋…ธ์ถœ๋œ๋‹ค
// ๋Œ€์‘: ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ (PreparedStatement / JPA)
@Query("SELECT u FROM User u WHERE u.email = :email")
User findByEmail(@Param("email") String email);   // ๊ฐ’์œผ๋กœ๋งŒ ์ฒ˜๋ฆฌ๋จ

๋Œ€์‘ ์š”์•ฝ: ์ฟผ๋ฆฌ๋Š” ํ•ญ์ƒ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ”์ธ๋”ฉ์œผ๋กœ ๋งŒ๋“ ๋‹ค.
๋ฌธ์ž์—ด ๊ฒฐํ•ฉ ๊ธˆ์ง€. ORM์„ ์จ๋„ ๋„ค์ดํ‹ฐ๋ธŒ ์ฟผ๋ฆฌ·JPQL ๋™์  ๊ฒฐํ•ฉ์—์„œ ๋šซ๋ฆด ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ฃผ์˜ํ•œ๋‹ค. XSS๋Š” ์ถœ๋ ฅ ์‹œ ์ด์Šค์ผ€์ดํ”„ ์ฒ˜๋ฆฌํ•œ๋‹ค.


A06. Insecure Design — ์•ˆ์ „ํ•˜์ง€ ์•Š์€ ์„ค๊ณ„

์ฝ”๋“œ ๋ฒ„๊ทธ๊ฐ€ ์•„๋‹ˆ๋ผ ์„ค๊ณ„ ์ž์ฒด์˜ ๊ฒฐํ•จ์ด๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์„ค์ •์— ํšŸ์ˆ˜ ์ œํ•œ์ด ์—†์œผ๋ฉด, ๊ตฌํ˜„์ด ์™„๋ฒฝํ•ด๋„ ๋ฌด์ฐจ๋ณ„ ๋Œ€์ž…์— ๋šซ๋ฆฐ๋‹ค.

// ๋Œ€์‘ ์˜ˆ: ๋ฏผ๊ฐํ•œ ๊ธฐ๋Šฅ์— ๋น„์œจ ์ œํ•œ(rate limit) ์„ค๊ณ„ ๋ฐ˜์˜
@RateLimiter(name = "passwordReset", fallbackMethod = "tooManyRequests")
public void requestPasswordReset(String email) {
    // ๋ถ„๋‹น NํšŒ๋กœ ์ œํ•œ → ๋ฌด์ฐจ๋ณ„ ์‹œ๋„ ์ฐจ๋‹จ
}

๋Œ€์‘ ์š”์•ฝ: ์„ค๊ณ„ ๋‹จ๊ณ„์—์„œ ์œ„ํ˜‘ ๋ชจ๋ธ๋ง(threat modeling)์„ ํ•œ๋‹ค.
"์ด ๊ธฐ๋Šฅ์ด ์•…์šฉ๋˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ"๋ฅผ ๋จผ์ € ๋ฌป๊ณ , ๋น„์œจ ์ œํ•œ·๋‹ค๋‹จ๊ณ„ ์ธ์ฆ·์ตœ์†Œ ๊ถŒํ•œ์„ ์„ค๊ณ„์— ํฌํ•จํ•œ๋‹ค.


A07. Authentication Failures — ์ธ์ฆ ์‹คํŒจ

์•ฝํ•œ ๋น„๋ฐ€๋ฒˆํ˜ธ ํ—ˆ์šฉ, ์„ธ์…˜ ๊ด€๋ฆฌ ๋ฏธํก, ๋ฌด์ฐจ๋ณ„ ๋Œ€์ž… ๋ฐฉ์–ด ๋ถ€์žฌ ๋“ฑ. ์ด์ „ ๊ธ€์˜ JWT ์ธ์ฆ๊ณผ๋„ ์ง๊ฒฐ๋œ๋‹ค.

// ๋Œ€์‘: ๋กœ๊ทธ์ธ ์‹คํŒจ ํšŸ์ˆ˜ ์ œํ•œ + ๊ณ„์ • ์ž ๊ธˆ
public void login(String email, String password) {
    if (loginAttemptService.isBlocked(email)) {
        throw new LockedException("๋กœ๊ทธ์ธ ์‹œ๋„๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์Šต๋‹ˆ๋‹ค. ์ž ์‹œ ํ›„ ๋‹ค์‹œ ์‹œ๋„ํ•˜์„ธ์š”");
    }
    if (!passwordEncoder.matches(password, user.getPassword())) {
        loginAttemptService.recordFailure(email);  // ์‹คํŒจ ์นด์šดํŠธ
        throw new BadCredentialsException("์ธ์ฆ ์‹คํŒจ");
    }
    loginAttemptService.reset(email);
}

๋Œ€์‘ ์š”์•ฝ: ๋‹ค๋‹จ๊ณ„ ์ธ์ฆ(MFA)์„ ์ œ๊ณตํ•˜๊ณ , ๋กœ๊ทธ์ธ ์‹คํŒจ ์ œํ•œ·์„ธ์…˜ ํƒ€์ž„์•„์›ƒ·์•ˆ์ „ํ•œ ํ† ํฐ ๊ด€๋ฆฌ๋ฅผ ์ ์šฉํ•œ๋‹ค.
๊ฒ€์ฆ๋œ ์ธ์ฆ ํ”„๋ ˆ์ž„์›Œํฌ(Spring Security ๋“ฑ)๋ฅผ ์“ฐ๋Š” ๊ฒƒ์ด ์ง์ ‘ ๊ตฌํ˜„๋ณด๋‹ค ์•ˆ์ „ํ•˜๋‹ค.


A08. Software or Data Integrity Failures — ๋ฌด๊ฒฐ์„ฑ ์‹คํŒจ

๊ฒ€์ฆ๋˜์ง€ ์•Š์€ ์ถœ์ฒ˜์˜ ์ฝ”๋“œ·๋ฐ์ดํ„ฐ๋ฅผ ์‹ ๋ขฐํ•  ๋•Œ ๋ฐœ์ƒํ•œ๋‹ค.
์„œ๋ช… ๊ฒ€์ฆ ์—†๋Š” ์ž๋™ ์—…๋ฐ์ดํŠธ, ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ๋ฐ์ดํ„ฐ์˜ ์—ญ์ง๋ ฌํ™” ๋“ฑ์ด ํ•ด๋‹น๋œ๋‹ค.

// ์ทจ์•ฝ: ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊ทธ๋Œ€๋กœ ์—ญ์ง๋ ฌํ™”
ObjectInputStream in = new ObjectInputStream(untrustedInput);
Object obj = in.readObject();   // ์—ญ์ง๋ ฌํ™” ๊ฐ€์ ฏ ๊ณต๊ฒฉ์— ์ทจ์•ฝ

๋Œ€์‘ ์š”์•ฝ: ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ๋Š” ์—ญ์ง๋ ฌํ™”ํ•˜์ง€ ์•Š๊ฑฐ๋‚˜, ํ—ˆ์šฉ ๋ชฉ๋ก(allowlist) ๊ธฐ๋ฐ˜์œผ๋กœ๋งŒ ์ฒ˜๋ฆฌํ•œ๋‹ค.
์—…๋ฐ์ดํŠธ·์•„ํ‹ฐํŒฉํŠธ๋Š” ๋””์ง€ํ„ธ ์„œ๋ช…์œผ๋กœ ๋ฌด๊ฒฐ์„ฑ์„ ๊ฒ€์ฆํ•œ๋‹ค. CI/CD ํŒŒ์ดํ”„๋ผ์ธ์˜ ์ ‘๊ทผ ๊ถŒํ•œ๋„ ํ†ต์ œํ•œ๋‹ค.


A09. Security Logging & Alerting Failures — ๋กœ๊น…·์•Œ๋ฆผ ์‹คํŒจ

์ด๋ฒˆ์— ์ด๋ฆ„์ด "๋ชจ๋‹ˆํ„ฐ๋ง"์—์„œ "์•Œ๋ฆผ"์œผ๋กœ ๋ฐ”๋€Œ์—ˆ๋‹ค.
๋กœ๊ทธ๋งŒ ์Œ“๊ณ  ์•Œ๋ฆผ์ด ์—†์œผ๋ฉด ์นจํ•ด๋ฅผ ์ œ๋•Œ ๋ฐœ๊ฒฌํ•˜์ง€ ๋ชปํ•œ๋‹ค๋Š” ์ ์„ ๊ฐ•์กฐํ•œ ๊ฒƒ์ด๋‹ค.

// ๋Œ€์‘: ๋ณด์•ˆ ์ด๋ฒคํŠธ๋ฅผ ๊ตฌ์กฐํ™”ํ•ด์„œ ๊ธฐ๋ก + ์•Œ๋ฆผ ์—ฐ๋™
log.warn("AUTH_FAILURE user={} ip={} attempts={}",
         email, clientIp, attemptCount);
// ์ž„๊ณ„์น˜ ์ดˆ๊ณผ ์‹œ Slack/PagerDuty๋กœ ์•Œ๋ฆผ ๋ฐœ์†กํ•˜๋„๋ก ์—ฐ๋™

๋Œ€์‘ ์š”์•ฝ: ๋กœ๊ทธ์ธ ์‹คํŒจ, ๊ถŒํ•œ ๊ฑฐ๋ถ€, ์ž…๋ ฅ ๊ฒ€์ฆ ์‹คํŒจ ๊ฐ™์€ ๋ณด์•ˆ ์ด๋ฒคํŠธ๋ฅผ ๊ธฐ๋กํ•œ๋‹ค.
๋‹จ, ๋กœ๊ทธ์— ๋น„๋ฐ€๋ฒˆํ˜ธ·ํ† ํฐ·๊ฐœ์ธ์ •๋ณด๋ฅผ ๋‚จ๊ธฐ์ง€ ์•Š๋Š”๋‹ค.
๊ทธ๋ฆฌ๊ณ  ํ•ต์‹ฌ์€ ์ž„๊ณ„์น˜ ์ดˆ๊ณผ ์‹œ ์‹ค์ œ๋กœ ์•Œ๋ฆผ์ด ๊ฐ€๋„๋ก ์—ฐ๋™ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.


A10. Mishandling of Exceptional Conditions — ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๋ฏธํก (์‹ ๊ทœ)

์ด๋ฒˆ์— ์ƒˆ๋กœ ์ถ”๊ฐ€๋œ ํ•ญ๋ชฉ. ์ž˜๋ชป๋œ ์—๋Ÿฌ ์ฒ˜๋ฆฌ, ๋…ผ๋ฆฌ ์˜ค๋ฅ˜, "์‹คํŒจ ์‹œ ์—ด๋ฆผ(fail open)" ๊ฐ™์€ ๋น„์ •์ƒ ์ƒํ™ฉ ๋Œ€์‘ ๊ฒฐํ•จ์ด๋‹ค.

// ์ทจ์•ฝ: ๊ถŒํ•œ ๊ฒ€์‚ฌ ์ค‘ ์˜ˆ์™ธ๊ฐ€ ๋‚˜๋ฉด ํ†ต๊ณผ์‹œ์ผœ ๋ฒ„๋ฆผ (fail open)
public boolean hasPermission(User user, Resource res) {
    try {
        return permissionService.check(user, res);
    } catch (Exception e) {
        return true;   // ์˜ˆ์™ธ ์‹œ ํ—ˆ์šฉ → ์น˜๋ช…์ 
    }
}
// ๋Œ€์‘: ์‹คํŒจ ์‹œ ์•ˆ์ „ํ•œ ์ชฝ์œผ๋กœ ๋‹ซ๋Š”๋‹ค (fail secure)
public boolean hasPermission(User user, Resource res) {
    try {
        return permissionService.check(user, res);
    } catch (Exception e) {
        log.error("๊ถŒํ•œ ๊ฒ€์‚ฌ ์‹คํŒจ, ์ ‘๊ทผ ๊ฑฐ๋ถ€ ์ฒ˜๋ฆฌ", e);
        return false;   // ์˜ˆ์™ธ ์‹œ ๊ฑฐ๋ถ€ (fail closed)
    }
}

๋Œ€์‘ ์š”์•ฝ: ๋ณด์•ˆ ๊ฒฐ์ •์€ ์˜ˆ์™ธ๊ฐ€ ๋‚˜๋ฉด ๊ฑฐ๋ถ€ ์ชฝ์œผ๋กœ ๋‹ซ๋Š”๋‹ค(fail secure).
์—๋Ÿฌ ๋ฉ”์‹œ์ง€์— ๋‚ด๋ถ€ ์ •๋ณด๋ฅผ ๋…ธ์ถœํ•˜์ง€ ์•Š๊ณ , ๋ชจ๋“  ๋น„์ •์ƒ ๊ฒฝ๋กœ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค.


๋งˆ์น˜๋ฉฐ

OWASP Top 10:2025์˜ ๋ฉ”์‹œ์ง€๋Š” ๋ถ„๋ช…ํ•˜๋‹ค. ์ฆ์ƒ์ด ์•„๋‹ˆ๋ผ ๊ทผ๋ณธ ์›์ธ์„ ๋ณด๋ผ.
๊ณต๊ธ‰๋ง ์‹คํŒจ์™€ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๋ฏธํก์ด ์ƒˆ๋กœ ๋“ค์–ด์˜จ ๊ฒƒ๋„, ๊ฐœ๋ณ„ ๋ฒ„๊ทธ๋ณด๋‹ค "์„ค๊ณ„์™€ ํ”„๋กœ์„ธ์Šค ์ฐจ์›์˜ ๊ฒฐํ•จ"์ด ๋” ์œ„ํ—˜ํ•ด์กŒ๋‹ค๋Š” ์‹ ํ˜ธ๋‹ค.

10๊ฐ€์ง€๋ฅผ ๋‹ค ํ•œ ๋ฒˆ์— ์ ์šฉํ•  ํ•„์š”๋Š” ์—†๋‹ค. ์šฐ์„ ์ˆœ์œ„๋Š” ๋ถ„๋ช…ํ•˜๋‹ค.
์ ‘๊ทผ ์ œ์–ด(A01), ๋ณด์•ˆ ์„ค์ •(A02), ์˜์กด์„ฑ ๊ด€๋ฆฌ(A03)๋ถ€ํ„ฐ ์ ๊ฒ€ํ•˜๋Š” ๊ฒŒ ํšจ์œจ์ ์ด๋‹ค.
์ด ์…‹์ด ์ง€๊ธˆ ๊ฐ€์žฅ ํ”ํ•˜๊ฒŒ ๋šซ๋ฆฌ๋Š” ์ง€์ ์ด๋‹ค.

๋ณด์•ˆ์€ ํ•œ ๋ฒˆ ์งœ๊ณ  ๋๋‚˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ๊ณ„์† ์ ๊ฒ€ํ•˜๋Š” ๊ณผ์ •์ด๋‹ค.
์ƒˆ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ๋•Œ๋งˆ๋‹ค "์ด๊ฒŒ ์•…์šฉ๋˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ"๋ฅผ ํ•œ ๋ฒˆ์”ฉ ๋– ์˜ฌ๋ฆฌ๋Š” ์Šต๊ด€์ด, ๊ทธ ์–ด๋–ค ๋„๊ตฌ๋ณด๋‹ค ํšจ๊ณผ์ ์ธ ๋ฐฉ์–ด๋‹ค.


์ฐธ๊ณ  ์ถœ์ฒ˜