객체 속성 수준 권한 검증 실패

객체 속성 수준 권한 검증 실패 (API3: Broken Object Property Level Authorization, BOPLA)

객체가 아니라 객체의 개별 속성(프로퍼티) 단위에서 권한 검증이 깨지는 리스크가 바로 객체 속성 수준 권한 검증 실패(BOPLA)예요. 공격자가 읽으면 안 되는 속성까지 응답에 실려 나오거나, 바꾸면 안 되는 속성(예: 관리자 여부, 차단 상태)을 공격자가 직접 바꿀 수 있는 상황을 말해요. 이 항목은 2019년판의 "과도한 데이터 노출(Excessive Data Exposure)"과 "대량 할당(Mass Assignment)"을 하나로 합쳐서, 그 근본 원인인 속성 수준 권한 검증 부재에 초점을 맞춘 것이에요. REST API처럼 객체 전체 속성을 통째로 돌려주는 설계에서 특히 흔하게 나타나요.

출처: OWASP API Security Top 10 — API3:2023 Broken Object Property Level Authorization

어떤 API가 취약한가요?

객체에 접근을 허용할 때는 사용자가 접근하려는 그 특정 속성에 대한 접근 권한까지 함께 검증해야 해요. 다음 경우에 해당하면 취약해요.

  • 사용자가 읽어선 안 되는 민감한 속성(예: 신고 대상 사용자의 fullName, recentLocation)을 객체 응답에 함께 노출하는 경우. 이것이 2019년판의 Excessive Data Exposure에 해당해요.
  • 사용자가 객체 속성의 값을 변경·추가·삭제할 수 있는데, 그에 대한 권한 검증이 없는 경우. 클라이언트 입력이 코드 변수나 내부 객체 속성에 자동으로 바인딩되는 대량 할당(Mass Assignment)이 대표적이에요.

공격 시나리오

시나리오 #1

사용자 신고 기능이 GraphQL mutation으로 제공된다고 해볼게요. 아래 요청은 reportUser mutation에 userIdreason을 실어 보내요.

POST /graphql
{
  "operationName":"reportUser",
  "variables":{
    "userId": 313,
    "reason":["offensive behavior"]
  },
  "query":"mutation reportUser($userId: ID!, $reason: String!) {
    reportUser(userId: $userId, reason: $reason) {
      status
      message
      reportedUser {
        id
        fullName
        ...

이때 응답이 신고 대상 사용자의 fullName 같은 민감한 속성을 돌려준다면, 다른 사용자가 그 속성을 읽을 수 있게 되므로 취약한 엔드포인트예요.

시나리오 #3

API가 사용자가 접근해선 안 되는 내부 속성 blocked에 대한 접근 권한을 검증하지 않는다면, 사용자가 이 값을 true에서 false로 바꿔 자신의 차단된 콘텐츠를 해제할 수 있어요. 이 역시 속성 수준 권한 검증 실패에 해당해요.

예방 방법

  • 엔드포인트에서 객체를 노출할 때, 사용자가 접근해도 되는 속성인지 항상 확인해요.
  • to_json()이나 to_string() 같은 범용 메서드 대신 돌려줄 속성을 골라서(cherry-pick) 명시해요.
  • 가능하면 클라이언트 입력이 코드 변수·내부 객체·객체 속성에 자동 바인딩되는 함수(Mass Assignment)를 쓰지 않아요.
  • 클라이언트가 업데이트할 수 있는 속성만 변경을 허용해요.
  • 스키마 기반 응답 검증 메커니즘을 보안 레이어로 추가해, 모든 API 메서드가 돌려주는 데이터를 정의하고 강제해요.
  • 엔드포인트의 비즈니스·기능 요구사항에 맞춰 응답 데이터 구조를 최소한으로 유지해요.

더 알아보기