OWASP API Security Top 10 2023. ์น์ฉ Top 10๊ณผ๋ ๋ค๋ฅธ, API์ ํนํ๋ ๋ณด์ ์ํ ํ์ค. ์์๊ถ์ ์ ๋ นํ ์ธ๊ฐ(Authorization) ๋ฌธ์ ๋ถํฐ ๋น์ฆ๋์ค ํ๋ฆ ์ ์ฉ๊น์ง, ๋ฐฑ์๋ API ๊ฐ๋ฐ์๊ฐ ์์์ผ ํ 10๊ฐ์ง๋ฅผ ๊ณต๊ฒฉ ์์์ ๋์ ์ฝ๋๋ก ์ ๋ฆฌํ๋ค.
๋ค์ด๊ฐ๋ฉฐ
์ง๋ ๊ธ์์ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ฉ OWASP Top 10:2025๋ฅผ ๋ค๋ค๋ค. ๊ทธ๋ฐ๋ฐ OWASP์๋ API์ ํนํ๋ ๋ณ๋์ Top 10์ด ์๋ค. ๋ฐ๋ก OWASP API Security Top 10์ด๋ค.
๋ ๋ฌธ์๋ ๋ค๋ฅด๋ค.
OWASP Top 10 (์น): ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฐ์ ์ํ. 2017 → 2021 → 2025.
OWASP API Security Top 10 (API): REST·GraphQL ๊ฐ์ API์ ํนํ๋ ์ํ. 2019 → 2023.
์ด๋ฆ์ด ๋น์ทํด ํท๊ฐ๋ฆฌ์ง๋ง, ๋์๊ณผ ํญ๋ชฉ์ด ๋ค๋ฅธ ๋ณ๊ฐ์ ๋ฌธ์๋ค. ์ด ๊ธ์ API ๋ฒ์ (2023)์ ๋ค๋ฃฌ๋ค.
์์ฆ์ฒ๋ผ ํ๋ก ํธ์ ๋ฐฑ์๋๊ฐ ๋ถ๋ฆฌ๋๊ณ , ๋ง์ดํฌ๋ก์๋น์ค์ ๋ชจ๋ฐ์ผ ์ฑ์ด API๋ก ํต์ ํ๋ ํ๊ฒฝ์์๋ API ๋ณด์์ด ๊ณง ์๋น์ค ๋ณด์์ด๋ค. ํฅ๋ฏธ๋ก์ด ์ ์, API ๋ณด์์ ํต์ฌ์ด ๋๋ถ๋ถ ์ธ๊ฐ(Authorization) ์ ์๋ค๋ ๊ฒ์ด๋ค. ์์ 5๊ฐ ์ค 3๊ฐ๊ฐ ์ธ๊ฐ ๊ด๋ จ ํญ๋ชฉ์ด๋ค.
์์๋ Java/Spring ๊ธฐ์ค์ด๋ค.
2019 → 2023, ๋ฌด์์ด ๋ฐ๋์๋
API ๋ฒ์ ์ 2019๋ ์ฒซ ๋ฐ๊ฐ ํ 4๋ ๋ง์ธ 2023๋ ์ ๊ฐ์ ๋๋ค. ์ฃผ์ ๋ณํ๋ ์ด๋ ๋ค.
- ์ ๊ท: API6(๋ฏผ๊ฐํ ๋น์ฆ๋์ค ํ๋ฆ ๋ฌด์ ํ ์ ๊ทผ), API7(SSRF), API10(์์ ํ์ง ์์ API ์๋น)
- ํตํฉ: ๊ธฐ์กด "๊ณผ๋ํ ๋ฐ์ดํฐ ๋ ธ์ถ"๊ณผ "Mass Assignment"๊ฐ API3(๊ฐ์ฒด ์์ฑ ์์ค ์ธ๊ฐ)๋ก ํฉ์ณ์ง
- ํ์ฅ: "๋ฆฌ์์ค ๋ถ์กฑ·์๋ ์ ํ"์ด API4(๋ฌด์ ํ ๋ฆฌ์์ค ์๋น)๋ก ๋ฒ์ ํ๋
์ ์ฒด ๋ชฉ๋ก์ ๋ค์๊ณผ ๊ฐ๋ค.
| ์์ | ํญ๋ชฉ | ๋ถ๋ฅ |
| API1 | Broken Object Level Authorization (BOLA) | ์ธ๊ฐ |
| API2 | Broken Authentication | ์ธ์ฆ |
| API3 | Broken Object Property Level Authorization | ์ธ๊ฐ |
| API4 | Unrestricted Resource Consumption | ์์ |
| API5 | Broken Function Level Authorization (BFLA) | ์ธ๊ฐ |
| API6 | Unrestricted Access to Sensitive Business Flows | ์ค๊ณ |
| API7 | Server Side Request Forgery (SSRF) | ์ ๋ ฅ |
| API8 | Security Misconfiguration | ์ค์ |
| API9 | Improper Inventory Management | ๊ด๋ฆฌ |
| API10 | Unsafe Consumption of APIs | ์ธ๋ถ์ฐ๋ |
API1. Broken Object Level Authorization (BOLA) — ๊ฐ์ฒด ์์ค ์ธ๊ฐ ์คํจ
API ๋ณด์์ ๋ถ๋์ 1์. ์์ฒญํ ์ฌ์ฉ์๊ฐ ๊ทธ ๊ฐ์ฒด์ ์ ๊ทผํ ๊ถํ์ด ์๋์ง ํ์ธํ์ง ์์ ๋ ๋ฐ์ํ๋ค. ์น Top 10์ IDOR์ ๊ฐ์ ๋ฟ๋ฆฌ๋ค.
// ์ทจ์ฝ: id๋ก ์กฐํ๋ง ํ๊ณ ์์ ์ ํ์ธ ์์
@GetMapping("/api/accounts/{accountId}")
public Account getAccount(@PathVariable Long accountId) {
return accountRepository.findById(accountId).orElseThrow();
// accountId๋ฅผ 1์ฉ ๋ฐ๊พธ๋ฉด ๋จ์ ๊ณ์ข๊ฐ ๊ทธ๋๋ก ์กฐํ๋๋ค
}
// ๋์: ์์ฒญ์๊ฐ ํด๋น ๊ฐ์ฒด์ ์์ ์์ธ์ง ํญ์ ๊ฒ์ฆ
@GetMapping("/api/accounts/{accountId}")
public Account getAccount(@PathVariable Long accountId,
@AuthenticationPrincipal UserDetails user) {
Account account = accountRepository.findById(accountId).orElseThrow();
if (!account.getOwnerId().equals(user.getId())) {
throw new AccessDeniedException("์ ๊ทผ ๊ถํ์ด ์์ต๋๋ค");
}
return account;
}
๋์ ์์ฝ: ๋ชจ๋ ๊ฐ์ฒด ์ ๊ทผ์ ์์ ๊ถ์ ๊ฒ์ฆํ๋ค.
์์ฐจ์ ์ ์ ID ๋์ ์ถ์ธกํ๊ธฐ ์ด๋ ค์ด UUID๋ฅผ ์ฐ๋ ๊ฒ๋ ๋ฐฉ์ด์ ๋์์ด ๋๋ค(๊ทผ๋ณธ ํด๊ฒฐ์ ์๋์ง๋ง).
API2. Broken Authentication — ์ธ์ฆ ์คํจ
์ธ์ฆ ๋ฉ์ปค๋์ฆ์ด ์๋ชป ๊ตฌํ๋ ๊ฒฝ์ฐ๋ค. ํ ํฐ ๊ฒ์ฆ ๋๋ฝ, ์ฝํ ๋น๋ฐ๋ฒํธ ํ์ฉ, JWT ๋ง๋ฃ ๋ฏธ๊ฒ์ฆ ๋ฑ์ด ํฌํจ๋๋ค.
// ์ทจ์ฝ: JWT ์๋ช
๋ง ๋ณด๊ณ ๋ง๋ฃ(exp)๋ฅผ ๊ฒ์ฆํ์ง ์์
Claims claims = Jwts.parser().verifyWith(key).build()
.parseSignedClaims(token).getPayload();
// ๋ง๋ฃ๋ ํ ํฐ๋ ํต๊ณผ → ํ์ทจ๋ ํ ํฐ์ด ์์ํ ์ ํจ
// ๋์: ๋ง๋ฃ ๊ฒ์ฆ์ jjwt๊ฐ ์๋์ผ๋ก ํ์ง๋ง, ์์ธ๋ฅผ ๋ช
์์ ์ผ๋ก ์ฒ๋ฆฌ
try {
Claims claims = Jwts.parser().verifyWith(key).build()
.parseSignedClaims(token).getPayload();
} catch (ExpiredJwtException e) {
throw new UnauthorizedException("ํ ํฐ์ด ๋ง๋ฃ๋์์ต๋๋ค");
} catch (JwtException e) {
throw new UnauthorizedException("์ ํจํ์ง ์์ ํ ํฐ์
๋๋ค");
}
๋์ ์์ฝ: ๊ฒ์ฆ๋ ์ธ์ฆ ํ๋ ์์ํฌ๋ฅผ ์ฐ๊ณ , ํ ํฐ ๋ง๋ฃ·์๋ช
์ ๋น ์ง์์ด ๊ฒ์ฆํ๋ค.
๋ก๊ทธ์ธ ๋ฌด์ฐจ๋ณ ๋์
์ ์๋ ์ ํ์ ๊ฑธ๊ณ , ๋ฏผ๊ฐ ์ ๋ณด ๋ณ๊ฒฝ ์ ์ฌ์ธ์ฆ์ ์๊ตฌํ๋ค. (์ด์ JWT ์ธ์ฆ ๊ธ ์ฐธ๊ณ )
API3. Broken Object Property Level Authorization — ๊ฐ์ฒด ์์ฑ ์์ค ์ธ๊ฐ ์คํจ
๊ฐ์ฒด ์ ๊ทผ์ ํ์ฉ๋์ง๋ง, ๊ทธ ๊ฐ์ฒด์ ํน์ ์์ฑ๊น์ง๋ ํต์ ํ์ง ์๋ ๊ฒฝ์ฐ๋ค.
2019๋
์ "๊ณผ๋ํ ๋ฐ์ดํฐ ๋
ธ์ถ"๊ณผ "Mass Assignment"๊ฐ ์ฌ๊ธฐ๋ก ํฉ์ณ์ก๋ค.
// ์ทจ์ฝ: ์์ฒญ ๋ณธ๋ฌธ์ ์ํฐํฐ์ ๊ทธ๋๋ก ๋ฐ์ธ๋ฉ (Mass Assignment)
@PatchMapping("/api/users/{id}")
public User update(@PathVariable Long id, @RequestBody User body) {
User user = userRepository.findById(id).orElseThrow();
user.setName(body.getName());
user.setRole(body.getRole()); // ์ฌ์ฉ์๊ฐ role=ADMIN ์ ๋ณด๋ด๋ฉด ๊ถํ ์์น!
return userRepository.save(user);
}
// ๋์: ์์ ๊ฐ๋ฅํ ์์ฑ๋ง ๋ฐ๋ ์ ์ฉ DTO ์ฌ์ฉ
public record UpdateUserRequest(String name) {} // role์ ์์ ๋ฐ์ง ์์
@PatchMapping("/api/users/{id}")
public User update(@PathVariable Long id, @RequestBody UpdateUserRequest req) {
User user = userRepository.findById(id).orElseThrow();
user.setName(req.name()); // ํ์ฉ๋ ํ๋๋ง ๋ณ๊ฒฝ
return userRepository.save(user);
}
๋์ ์์ฝ: ์๋ต์ ํ์ํ ์์ฑ๋ง ๋ด์ DTO๋ก ๋ด๋ณด๋ด๊ณ (๊ณผ๋ํ ๋
ธ์ถ ๋ฐฉ์ง),
์์ฒญ๋ ์์ ํ์ฉ ์์ฑ๋ง ๋ฐ๋ DTO๋ก ๋ฐ๋๋ค(Mass Assignment ๋ฐฉ์ง). ์ํฐํฐ๋ฅผ ๊ทธ๋๋ก ์
์ถ๋ ฅ์ ๋
ธ์ถํ์ง ์๋๋ค.
API4. Unrestricted Resource Consumption — ๋ฌด์ ํ ๋ฆฌ์์ค ์๋น
์๋ ์ ํ์ด ์์ด API๊ฐ ์์์ ๋ฌด์ ํ์ผ๋ก ์๋นํ๋ ๊ฒฝ์ฐ๋ค. DoS ๊ณต๊ฒฉ์ด๋ ๊ณผ๊ธ ํญํ์ผ๋ก ์ด์ด์ง๋ค.
// ๋์: Resilience4j ๋ฑ์ผ๋ก ์๋ ์ ํ
@RateLimiter(name = "api", fallbackMethod = "fallback")
@GetMapping("/api/search")
public List<Result> search(@RequestParam String query,
@RequestParam(defaultValue = "20") int size) {
int limited = Math.min(size, 100); // ํ์ด์ง ํฌ๊ธฐ ์ํ๋ ๊ฐ์
return searchService.search(query, limited);
}
๋์ ์์ฝ: ์์ฒญ ํ์·ํ์ด๋ก๋ ํฌ๊ธฐ·ํ์ด์ง ํฌ๊ธฐ·์คํ ์๊ฐ์ ์ํ์ ๋๋ค.
๋ฌด๊ฑฐ์ด ์ฐ์ฐ(ํ์ผ ์
๋ก๋, ์ธ๋ถ ํธ์ถ)์๋ ํ์์์๊ณผ ์ฟผํฐ๋ฅผ ์ ์ฉํ๋ค.
API5. Broken Function Level Authorization (BFLA) — ํจ์ ์์ค ์ธ๊ฐ ์คํจ
๊ฐ์ฒด๊ฐ ์๋๋ผ ๊ธฐ๋ฅ(์๋ํฌ์ธํธ) ์์ฒด์ ๋ํ ๊ถํ ๊ฒ์ฆ์ด ๋น ์ง ๊ฒฝ์ฐ๋ค. ์ผ๋ฐ ์ฌ์ฉ์๊ฐ ๊ด๋ฆฌ์ API๋ฅผ ํธ์ถํ ์ ์๋ ์ํฉ์ด๋ค.
// ์ทจ์ฝ: ๊ด๋ฆฌ์ ์๋ํฌ์ธํธ์ ๊ถํ ๊ฒ์ฌ ์์
@DeleteMapping("/api/admin/users/{id}")
public void deleteUser(@PathVariable Long id) {
userRepository.deleteById(id); // ๋๊ตฌ๋ ํธ์ถ ๊ฐ๋ฅ
}
// ๋์: ๋ฉ์๋ ์์ค ๊ถํ ๊ฒ์ฌ
@PreAuthorize("hasRole('ADMIN')")
@DeleteMapping("/api/admin/users/{id}")
public void deleteUser(@PathVariable Long id) {
userRepository.deleteById(id);
}
๋์ ์์ฝ: ๊ด๋ฆฌ์/์ผ๋ฐ ๊ธฐ๋ฅ์ ๋ช
ํํ ๋ถ๋ฆฌํ๊ณ , ์๋ํฌ์ธํธ๋ง๋ค ์ญํ ๊ธฐ๋ฐ ๊ถํ์ ๊ฒ์ฆํ๋ค.
๊ธฐ๋ณธ์ ๊ฑฐ๋ถ(deny by default), ๊ถํ์ด ์๋ ์ญํ ๋ง ๋ช
์์ ์ผ๋ก ํ์ฉํ๋ค.
API6. Unrestricted Access to Sensitive Business Flows — ๋ฏผ๊ฐํ ๋น์ฆ๋์ค ํ๋ฆ ๋ฌด์ ํ ์ ๊ทผ (์ ๊ท)
๊ธฐ์ ์ ์ทจ์ฝ์ ์ ์์ง๋ง, ๋น์ฆ๋์ค ํ๋ฆ์ด ์๋ํ๋ก ์
์ฉ๋๋ ๊ฒฝ์ฐ๋ค.
ํ์ ํ ์ํ์ ๋ด์ด ์น์ธ์ดํ๊ฑฐ๋, ์์ฝ์ ๋๋ ์ ์ ํ๋ ์์ด๋ค.
// ๋์ ์: ๋ฏผ๊ฐ ํ๋ฆ์ ๋ด ๋ฐฉ์ด + ๊ตฌ๋งค ์๋ ์ ํ
@PostMapping("/api/orders/limited-edition")
public Order purchase(@AuthenticationPrincipal UserDetails user,
@RequestBody OrderRequest req) {
if (!captchaService.verify(req.captchaToken())) { // ๋ด ์ฐจ๋จ
throw new BadRequestException("์ธ์ฆ์ ์คํจํ์ต๋๋ค");
}
if (orderService.countToday(user.getId()) >= 2) { // 1์ธ๋น ์๋ ์ ํ
throw new BusinessException("๊ตฌ๋งค ํ๋๋ฅผ ์ด๊ณผํ์ต๋๋ค");
}
return orderService.create(user, req);
}
๋์ ์์ฝ: ํ๋ฆ์ด ์
์ฉ๋ ๊ฐ๋ฅ์ฑ์ ์ค๊ณ ๋จ๊ณ์์ ์๋ณํ๋ค.
๋ด ํ์ง(CAPTCHA, ๋๋ฐ์ด์ค ํ๊ฑฐํ๋ฆฐํ
), 1์ธ๋น ์๋·๋น๋ ์ ํ, ๋น์ ์ ํจํด ํ์ง๋ฅผ ์ ์ฉํ๋ค.
API7. Server Side Request Forgery (SSRF) — ์๋ฒ ์ธก ์์ฒญ ์์กฐ (์ ๊ท)
API๊ฐ ์ฌ์ฉ์๊ฐ ์ค URL๋ก ์๋ฒ๊ฐ ์์ฒญ์ ๋ณด๋ด๊ฒ ๋ง๋๋ ๊ณต๊ฒฉ์ด๋ค.
๋ด๋ถ๋ง์ด๋ ํด๋ผ์ฐ๋ ๋ฉํ๋ฐ์ดํฐ ์ฃผ์์ ์ ๊ทผ๋นํ ์ ์๋ค. (์น 2025ํ์์๋ ์ ๊ทผ ์ ์ด๋ก ํก์๋์ง๋ง, API์์๋ ๋ณ๋ ํญ๋ชฉ์ด๋ค.)
// ์ทจ์ฝ: ์ฌ์ฉ์๊ฐ ์ค URL์ ๊ทธ๋๋ก ํธ์ถ
@PostMapping("/api/fetch-image")
public byte[] fetchImage(@RequestBody String imageUrl) {
return restClient.get().uri(imageUrl).retrieve().body(byte[].class);
// imageUrl=http://169.254.169.254/... → ํด๋ผ์ฐ๋ ์๊ฒฉ์ฆ๋ช
ํ์ทจ
}
// ๋์: ํ์ฉ๋ ๋๋ฉ์ธ๋ง ํต๊ณผ + ๋ด๋ถ IP ์ฐจ๋จ
private static final Set<String> ALLOWED = Set.of("cdn.example.com");
@PostMapping("/api/fetch-image")
public byte[] fetchImage(@RequestBody String imageUrl) {
URI uri = URI.create(imageUrl);
if (!ALLOWED.contains(uri.getHost()) || isInternalAddress(uri.getHost())) {
throw new BadRequestException("ํ์ฉ๋์ง ์์ ์ฃผ์์
๋๋ค");
}
return restClient.get().uri(uri).retrieve().body(byte[].class);
}
๋์ ์์ฝ: ์ธ๋ถ URL์ ํ์ฉ ๋ชฉ๋ก(allowlist)์ผ๋ก๋ง ๋ฐ๊ณ , ๋ด๋ถ๋ง·๋ฉํ๋ฐ์ดํฐ ์ฃผ์(169.254.169.254, localhost, ์ฌ์ค IP ๋์ญ)๋ฅผ ์ฐจ๋จํ๋ค. ๋ฆฌ๋ค์ด๋ ํธ๋ ๋ฐ๋ผ๊ฐ์ง ์๋๋ก ํ๋ค.
API8. Security Misconfiguration — ๋ณด์ ์ค์ ์ค๋ฅ
๋ถํ์ํ๊ฒ ์ด๋ฆฐ ๋ฉ์๋, ๋๋ฝ๋ ๋ณด์ ํค๋, ๊ณผ๋ํ CORS ํ์ฉ, ์์ธ ์๋ฌ ๋ ธ์ถ ๋ฑ. ์น ๋ฒ์ ๊ณผ ๊ฐ์ ๋งฅ๋ฝ์ด์ง๋ง API์์ ํนํ CORS๊ฐ ์์ฃผ ๋ฌธ์ ๋ค.
// ์ทจ์ฝ: ๋ชจ๋ ์ถ์ฒ ํ์ฉ
config.setAllowedOrigins(List.of("*"));
config.setAllowCredentials(true); // ์์ผ๋์นด๋ + ์ธ์ฆ์ ๋ณด = ์ํ
// ๋์: ์ ๋ขฐํ๋ ์ถ์ฒ๋ง ๋ช
์
config.setAllowedOrigins(List.of("https://app.example.com"));
config.setAllowedMethods(List.of("GET", "POST"));
config.setAllowCredentials(true);
๋์ ์์ฝ: CORS๋ ์ ๋ขฐ ์ถ์ฒ๋ง ํ์ฉํ๊ณ , ๋ถํ์ํ HTTP ๋ฉ์๋๋ฅผ ๋ง๋๋ค.
๋ณด์ ํค๋๋ฅผ ์ ์ฉํ๊ณ , ์๋ฌ ์๋ต์ ์คํํธ๋ ์ด์ค๋ ๋ด๋ถ ์ ๋ณด๋ฅผ ๋
ธ์ถํ์ง ์๋๋ค.
API9. Improper Inventory Management — ๋ถ์ ์ ํ ์ธ๋ฒคํ ๋ฆฌ ๊ด๋ฆฌ
์ด๋ค API๊ฐ ์ด๋์ ๋๊ณ ์๋์ง ํ์
์ด ์ ๋๋ ๊ฒฝ์ฐ๋ค.
๋ฌธ์ํ ์ ๋ ์ ๋ฒ์ (/api/v1), ํ
์คํธ ์๋ฒ, ํ๊ธฐํ์ด์ผ ํ ์๋ํฌ์ธํธ๊ฐ ๋ฐฉ์น๋๋ฉฐ ๊ณต๊ฒฉ ํ๋ฉด์ด ๋๋ค.
์ทจ์ฝ ์:
/api/v3/users ← ์ต์ , ๋ณด์ ํจ์น ์ ์ฉ๋จ
/api/v1/users ← ์ ๋ฒ์ , ์ธ์ฆ ์ฝํจ, ์์ง ์ด์ ์์ ← ๊ณต๊ฒฉ ๋์
๋์ ์์ฝ: ๋ชจ๋ API ์๋ํฌ์ธํธ์ ๋ฒ์ ์ ๋ฌธ์ํ(OpenAPI/Swagger)ํ๊ณ ๋ชฉ๋ก์ ๊ด๋ฆฌํ๋ค.
๋ ์ด์ ์ ์ฐ๋ ๋ฒ์ ์ ๋ช
์์ ์ผ๋ก ํ๊ธฐ(deprecate)ํ๊ณ ์ข
๋ฃํ๋ค. ์ด์/ํ
์คํธ ํ๊ฒฝ์ ๋ถ๋ฆฌํ๋ค.
API10. Unsafe Consumption of APIs — ์์ ํ์ง ์์ API ์๋น (์ ๊ท)
๋ด๊ฐ ๋ง๋ API๊ฐ ์๋๋ผ, ๋ด๊ฐ ํธ์ถํ๋ ์ธ๋ถ(์๋ํํฐ) API๋ฅผ ๋๋ฌด ์ ๋ขฐํ ๋์ ์ํ์ด๋ค.
๊ณต๊ฒฉ์๋ ์ง์ ๊ณต๊ฒฉํ๊ธฐ ์ด๋ ค์ด ๋์ ๋์ , ๊ทธ ๋์์ด ์ฐ๋ํ ์ธ๋ถ ์๋น์ค๋ฅผ ๋
ธ๋ฆฐ๋ค.
// ์ทจ์ฝ: ์ธ๋ถ API ์๋ต์ ๊ฒ์ฆ ์์ด ๊ทธ๋๋ก ์ ๋ขฐ
ExternalResponse res = restClient.get().uri(thirdPartyUrl)
.retrieve().body(ExternalResponse.class);
processPayment(res.getAmount()); // ์ธ๋ถ ์๋ต์ ๊ทธ๋๋ก ๊ฒฐ์ ์ ์ฌ์ฉ
// ๋์: ์ธ๋ถ ์๋ต๋ ๋ด ์
๋ ฅ์ฒ๋ผ ๊ฒ์ฆ
ExternalResponse res = restClient.get().uri(thirdPartyUrl)
.retrieve().body(ExternalResponse.class);
if (res.getAmount() == null || res.getAmount().signum() < 0) {
throw new IntegrationException("์ธ๋ถ ์๋ต์ด ์ฌ๋ฐ๋ฅด์ง ์์ต๋๋ค");
}
processPayment(res.getAmount());
๋์ ์์ฝ: ์ธ๋ถ API์๋ TLS๋ก๋ง ํต์ ํ๊ณ , ๋ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉ์ ์ ๋ ฅ๊ณผ ๋๊ฐ์ด ๊ฒ์ฆํ๋ค. ์ธ๋ถ ์๋น์ค๋ก์ ๋ฆฌ๋ค์ด๋ ํธ๋ฅผ ๋งน๋ชฉ์ ์ผ๋ก ๋ฐ๋ผ๊ฐ์ง ์๋๋ค.
๋ง์น๋ฉฐ
์น Top 10๊ณผ API Top 10์ ๋๋ํ ๋ณด๋ฉด ๊ฐ์กฐ์ ์ด ๋ค๋ฅด๋ค๋ ๊ฒ ๋ณด์ธ๋ค.
์น์ ์ธ์ ์
·์ํธํ·์ค์ ์ด ๊ณจ๊ณ ๋ฃจ ๋ถํฌํ๋ ๋ฐ๋ฉด, API๋ ์ธ๊ฐ(Authorization)์ ์ํ์ด ์ง์ค๋ผ ์๋ค.
API1·API3·API5๊ฐ ๋ชจ๋ "๊ถํ ๊ฒ์ฆ์ ๋น ๋จ๋ ค์" ์๊ธฐ๋ ๋ฌธ์ ๋ค.
์ด์ ๋ ๋จ์ํ๋ค. API๋ ํ๋ฉด(UI)์ด๋ผ๋ ๋ฐฉ์ด๋ง ์์ด ๋ฐ์ดํฐ์ ์ง์ ์ ๊ทผํ๋ ํต๋ก์ด๊ธฐ ๋๋ฌธ์ด๋ค.
UI์์ ๋ฒํผ์ ์จ๊ธฐ๋ ๊ฒ๋ง์ผ๋ก๋ ์๋ฌด ์๋ฏธ๊ฐ ์๋ค.
๋ชจ๋ ์์ฒญ์ ๋ํด "์ด ์ฌ์ฉ์๊ฐ ์ด ๊ฐ์ฒด/๊ธฐ๋ฅ์ ๊ถํ์ด ์๋๊ฐ"๋ฅผ ์๋ฒ์์ ๊ฒ์ฆํ๋ ๊ฒ, ๊ทธ๊ฒ API ๋ณด์์ 9ํ ์ด๋ค.
์น๊ณผ API, ๋ Top 10์ ํจ๊ป ์์๋๋ฉด ์๋น์ค ์ ์ฒด์ ๊ณต๊ฒฉ ํ๋ฉด์ด ๋ณด์ธ๋ค. ํ๋ก ํธ์ ๋ฐฑ์๋๊ฐ ๋ถ๋ฆฌ๋ ์์ฆ ๊ตฌ์กฐ์์๋ ๋ ๋ค ์ฑ๊ฒจ์ผ ํ๋ค.
์ฐธ๊ณ ์ถ์ฒ
- OWASP API Security Top 10 2023 ๊ณต์ — https://owasp.org/API-Security/editions/2023/en/0x11-t10/
- OWASP API Security Project — https://owasp.org/www-project-api-security/
- OWASP Cheat Sheet Series — https://cheatsheetseries.owasp.org/
'๐ก๏ธ Security Notes' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| XSS์ CSRF โ ํท๊ฐ๋ฆฌ๋ ๋ ๊ณต๊ฒฉ, ๋ฌด์์ด ๋ค๋ฅธ๊ฐ (0) | 2026.06.08 |
|---|---|
| OWASP Top 10(2025) (0) | 2026.06.02 |