OWASP API 보안 톱 10은 무엇인가요?

OWASP(오픈 월드와이드 애플리케이션 보안 프로젝트)에서 발표한 API별 보안 위험 순위입니다. 2023년판은 API의 광범위한 채택으로 인해 증가한 위협을 반영한 최신 목록을 제공합니다.

1️⃣ API1:2023 - 브로큰 객체 수준 인증(BOLA)

Critical

개요

객체 ID를 조작하여 다른 사용자의 데이터에 무단으로 액세스할 수 있는 취약점입니다. 가장 빈번하게 발생하고 악용하기 가장 쉬운 취약점으로 알려져 있습니다.

위험

공격자는 URL 또는 요청 매개변수의 ID를 변경하는 것만으로 다른 사용자의 개인 정보, 결제 정보, 주문 내역 등에 액세스할 수 있습니다.

취약한 코드 예시

JavaScript (Express) ❌ Bad
// ID를 수신하고 데이터를 직접 반환 - 권한 확인 없음
app.get('/api/users/:id/orders', async (req, res) => {
  const orders = await Order.find({ userId: req.params.id });
  res.json(orders);
});

보안 코드 예시

JavaScript (Express) ✅ Good
// 권한 확인을 위해 인증된 사용자의 ID와 대조 확인
app.get('/api/users/:id/orders', authenticate, async (req, res) => {
  if (req.user.id !== req.params.id && !req.user.isAdmin) {
    return res.status(403).json({ error: 'Forbidden' });
  }
  const orders = await Order.find({ userId: req.params.id });
  res.json(orders);
});

완화 체크리스트

2️⃣ API2:2023 - 깨진 인증

Critical

개요

인증 메커니즘 구현 결함으로 인해 공격자가 합법적인 사용자 계정을 장악할 수 있는 취약점입니다.

일반적인 문제

취약한 비밀번호 정책, 부적절한 토큰 관리, 무차별 암호 대입 방지 기능 부족, 부적절한 세션 관리 등이 있습니다.

JavaScript ✅ 완화 예시: JWT 확인
const jwt = require('jsonwebtoken');

function authenticate(req, res, next) {
  const token = req.headers.authorization?.split(' ')[1];
  if (!token) return res.status(401).json({ error: 'Token required' });

  try {
    // 알고리즘을 명시적으로 지정(alg: none 공격 방지)
    const decoded = jwt.verify(token, process.env.JWT_SECRET, {
      algorithms: ['HS256'],
      issuer: 'your-app',
    });
    req.user = decoded;
    next();
  } catch (err) {
    res.status(401).json({ error: 'Invalid token' });
  }
}

3️⃣ API3:2023 - 깨진 객체 속성 수준 권한 부여

High

개요

API 응답에 포함된 객체의 속성(필드)에 대한 접근 제어가 불충분한 취약점입니다. 이 항목은 과도한 데이터 노출과 대량 할당을 결합한 항목입니다.

JavaScript ✅ 응답 필터링
// 사용자 객체에서 공개 필드만 반환
function sanitizeUser(user, requesterId) {
  const publicFields = { id: user.id, name: user.name, avatar: user.avatar };

  // 소유자만 추가 필드를 볼 수 있습니다.
  if (requesterId === user.id) {
    publicFields.email = user.email;
    publicFields.phone = user.phone;
  }

  return publicFields;
  // ❌ 반환 사용자; 비밀번호_해시 등이 유출될 수 있습니다.
}

4️⃣ API4:2023 - 제한 없는 리소스 소비

High

개요

API 요청 크기, 빈도 또는 리소스 소비에 제한이 없어 DoS 공격이나 비용 급증으로 이어질 수 있는 취약점입니다.

JavaScript (Express) ✅ 리소스 제한 구현
const rateLimit = require('express-rate-limit');

// 글로벌 요금 제한
app.use(rateLimit({
  windowMs: 15 * 60 * 1000, // 15분
  max: 100,                   // 최대 100건의 요청
  standardHeaders: true,
}));

// 페이로드 크기 제한
app.use(express.json({ limit: '10kb' }));

// 페이지 매김 상한
app.get('/api/items', (req, res) => {
  const limit = Math.min(parseInt(req.query.limit) || 20, 100);
  // ...
});

5️⃣ API5:2023 - 깨진 함수 수준 권한 부여

High

개요

관리자 기능 및 엔드포인트에 대한 적절한 액세스 제어가 구현되지 않아 일반 사용자가 관리 작업을 수행할 수 있는 취약점입니다.

JavaScript ✅ 역할 기반 액세스 제어
function authorize(...roles) {
  return (req, res, next) => {
    if (!roles.includes(req.user.role)) {
      return res.status(403).json({ error: 'Insufficient permissions' });
    }
    next();
  };
}

// 관리자 전용 액세스
app.delete('/api/admin/users/:id', authenticate, authorize('admin'), deleteUser);

// 관리자 및 진행자
app.put('/api/posts/:id/moderate', authenticate, authorize('admin', 'moderator'), moderatePost);

6️⃣ API6:2023 - 민감한 비즈니스 흐름에 대한 제한 없는 액세스

Medium

개요

중요한 비즈니스 로직 흐름이 자동화된 공격으로부터 보호되지 않는 취약점입니다. 예: 티켓 스캘핑, 대량 쿠폰 수집, 스팸 게시 등

완화

7️⃣ API7:2023 - 서버 측 요청 위조(SSRF)

High

개요

서버가 유효성 검사 없이 사용자가 제공한 URL을 가져와 내부 네트워크에 무단으로 액세스할 수 있는 취약점입니다.

JavaScript ✅ SSRF 완화
const { URL } = require('url');

function isAllowedUrl(input) {
  try {
    const url = new URL(input);
    // 프로토콜 제한
    if (!['https:', 'http:'].includes(url.protocol)) return false;
    // 사설 IP 범위 차단
    const blocked = ['127.0.0.1', 'localhost', '0.0.0.0', '169.254.169.254'];
    if (blocked.includes(url.hostname)) return false;
    // 내부 네트워크 범위 확인(10.x, 172.16-31.x, 192.168.x)
    if (/^(10\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.)/.test(url.hostname)) return false;
    return true;
  } catch {
    return false;
  }
}

8️⃣ API8:2023 - 보안 구성 오류

Medium

개요

API 서버 또는 프레임워크의 부적절한 보안 설정. 불필요한 HTTP 메서드 허용, 지나치게 허용적인 CORS 정책, 디버그 정보 노출 등이 포함됩니다.

JavaScript (Express) ✅ 보안 헤더 구성
const helmet = require('helmet');
const cors = require('cors');

app.use(helmet());
app.use(cors({
  origin: ['https://app.example.com'], // 와일드카드 사용 금지
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  credentials: true,
}));

// 오류 처리기: 프로덕션에서 스택 추적을 반환하지 않음
app.use((err, req, res, next) => {
  res.status(500).json({
    error: process.env.NODE_ENV === 'production'
      ? 'Internal Server Error'
      : err.message,
  });
});

9️⃣ API9:2023 - 부적절한 재고 관리

Medium

개요

이전 API 엔드포인트 버전이 보안 패치가 적용되지 않은 채 노출된 상태입니다. 섀도 API 또는 좀비 API라고도 합니다.

완화

🔟 API10:2023 - 안전하지 않은 API 소비

Medium

개요

타사 API의 응답을 검증 없이 신뢰하는 취약점입니다. 외부 API가 손상되면 그 영향이 자체 시스템으로 전파됩니다.

JavaScript ✅ 외부 API 응답 유효성 검사
const Ajv = require('ajv');
const ajv = new Ajv();

// 스키마로 외부 API 응답 유효성 검사하기
const externalSchema = {
  type: 'object',
  required: ['id', 'status'],
  properties: {
    id: { type: 'string', maxLength: 50 },
    status: { type: 'string', enum: ['active', 'inactive'] },
  },
  additionalProperties: false,
};

const validate = ajv.compile(externalSchema);

async function fetchExternalData() {
  const res = await fetch('https://api.external.com/data');
  const data = await res.json();

  if (!validate(data)) {
    throw new Error('External API response validation failed');
  }
  return data;
}

📊 요약 표

ID 취약성 심각도 주요 완화
API1Broken Object Level AuthorizationCritical개체 수준 권한 확인
API2Broken AuthenticationCritical적절한 토큰 관리 및 무차별 암호 대입 보호
API3Broken Object Property Level AuthorizationHigh명시적 응답 필드 필터링
API4Unrestricted Resource ConsumptionHigh속도 제한 및 페이로드 크기 제한
API5Broken Function Level AuthorizationHigh역할 기반 액세스 제어
API6Unrestricted Access to Sensitive Business FlowsMedium캡차 및 비즈니스 수준 요금 제한
API7Server Side Request ForgeryHighURL 유효성 검사 및 비공개 IP 차단
API8Security MisconfigurationMedium보안 헤더 및 CORS 구성
API9Improper Inventory ManagementMediumAPI 인벤토리 관리 및 사용 중단 정책
API10Unsafe Consumption of APIsMedium외부 API 응답의 스키마 유효성 검사