InfoGrab DocsInfoGrab Docs

권한 확인 위치

요약

권한을 확인할 위치를 결정할 때는, 서로 다른 레이어에서 다중 검사를 구현하는 심층 방어(defense-in-depth) 원칙을 적용하세요. 자세한 내용은 추상화 재사용 지침을 참고하세요. 동일한 리소스를 여러 지점에서 보호하면, 방어 레이어 중 하나가 침해되거나 누락되더라도 고객 데이터가 추가 레이어에 의해 여전히 보호됩니다.

권한은 어디서 확인해야 하나요?#

권한을 확인할 위치를 결정할 때는, 서로 다른 레이어에서 다중 검사를 구현하는 심층 방어(defense-in-depth) 원칙을 적용하세요. finder와 서비스 같은 저수준 레이어를 시작으로, GraphQL, 공개 REST API, 컨트롤러 같은 고수준 레이어 순으로 진행합니다.

자세한 내용은 추상화 재사용 지침을 참고하세요.

동일한 리소스를 여러 지점에서 보호하면, 방어 레이어 중 하나가 침해되거나 누락되더라도 고객 데이터가 추가 레이어에 의해 여전히 보호됩니다.

권한에 대한 자세한 내용은 보안 코딩 가이드라인의 권한 섹션을 참고하세요.

고려사항#

공유 비즈니스 로직 레이어(즉, 서비스 및 finder)에서 최대한 인가(authorization)를 강제해야 합니다. 이렇게 하면 REST, GraphQL, 컨트롤러 전반에서 인가가 일관되게 유지됩니다. 서비스 또는 finder가 적절한 위치인 이유는 다음과 같습니다:

  • 여러 엔드포인트가 서비스나 finder를 공유하므로, 다운스트림 로직이 재사용될 가능성이 높습니다.

  • 경우에 따라 레코드를 필터링하기 위해 인가 로직이 DB 쿼리에 포함되어야 합니다.

  • 보안 검사가 아닌 더 나은 UX를 제공하는 경우에만 표시 레이어에서 권한 검사를 사용해야 합니다. 예를 들어, 버튼과 같은 비데이터 요소를 표시하거나 숨기는 경우가 이에 해당합니다.

심층 방어의 단점은 다음과 같습니다:

  • DeclarativePolicy 규칙은 상대적으로 성능이 좋지만, 조건이 데이터베이스 호출을 수행할 수 있습니다.

  • 유지보수 비용이 높아집니다.

예외 사항#

개발자는 특정 케이스의 위험과 단점을 고려한 후, 단일 영역에서만 인가를 수행하도록 선택할 수 있습니다.

예외를 만들 때는 도메인 로직(서비스 또는 finder)을 진실의 단일 공급원(Single Source of Truth)으로 사용하는 것을 권장합니다.

백엔드 워커 로직과 같은 로직은 현재 사용자를 기반으로 한 인가가 필요하지 않을 수 있습니다. 서비스 또는 finder의 생성자가 current_user를 받지 않는 경우, 일반적으로 권한을 확인하지 않습니다.

프론트엔드#

UI 요소에서 ability 검사를 사용할 때는, 관련 백엔드 코드가 있다면 반드시 해당 코드에도 ability 검사를 사용하세요. 이렇게 하면 사용자가 적절한 접근 권한을 갖기 전까지 해당 기능을 사용할 수 없도록 보장합니다.

UI 요소가 HAML인 경우, 내장 Ruby를 사용하여 Ability.allowed?(user, action, subject)를 확인할 수 있습니다.

UI 요소가 JavaScript 또는 Vue인 경우, push_frontend_ability 메서드를 사용하세요. 이 메서드는 ApplicationController를 상속하는 모든 컨트롤러에서 사용 가능합니다. 다음과 같이 이 메서드를 사용하여 ability를 노출할 수 있습니다:

before_action do
  push_frontend_ability(ability: :read_project, resource: @project, user: current_user)
end

그런 다음 JavaScript에서 다음과 같이 ability 상태를 확인할 수 있습니다:

if ( gon.abilities.readProject ) {
  // ...
}

JavaScript에서 ability 이름은 항상 camelCase이므로, gon.abilities.read_project를 확인하면 작동하지 않습니다.

Vue 템플릿에서 ability를 확인하는 방법은 Vue에서 ability 접근에 관한 개발자 문서를 참고하세요.

#

  • 클래스가 current_user를 받는 경우, 해당 클래스가 인가를 담당할 수 있습니다.

예시: 새 API 엔드포인트 추가#

기본적으로 엔드포인트에서 인가를 수행합니다. 기존 ability를 확인하는 것이 합리적일 수 있으며, 그렇지 않다면 새 ability를 추가해야 할 수 있습니다.

참고로, 대부분의 엔드포인트는 리소스에 대한 CRUD(create, read, update, destroy) 작업으로 명확하게 분류할 수 있습니다. 서비스와 ability도 이에 따르므로, 많은 경우 Projects::CreateService 또는 :read_project와 같이 명명됩니다.

예를 들어, 전체 엔드포인트를 서비스로 추출한다고 가정해 봅시다. can? 검사는 이제 서비스 안에 위치합니다. 서비스가 기존 finder를 재사용하고 우리가 해당 finder를 수정하는 경우, finder에도 ability 검사를 추가해야 할까요?

  • finder가 current_user를 받지 않아 권한을 확인하지 않는 경우라면, 아마도 추가할 필요가 없습니다.

  • finder가 current_user를 받지만 권한을 확인하지 않는 경우라면, 해당 finder의 다른 사용 위치를 재확인하고 인가 추가를 고려해야 합니다.

  • finder가 current_user를 받고 이미 권한을 확인하는 경우라면, 우리의 케이스를 추가해야 하거나 기존 검사가 적절합니다.

권한 확인 위치

GitLab v19.1
원문 보기
요약

권한을 확인할 위치를 결정할 때는, 서로 다른 레이어에서 다중 검사를 구현하는 심층 방어(defense-in-depth) 원칙을 적용하세요. 자세한 내용은 추상화 재사용 지침을 참고하세요. 동일한 리소스를 여러 지점에서 보호하면, 방어 레이어 중 하나가 침해되거나 누락되더라도 고객 데이터가 추가 레이어에 의해 여전히 보호됩니다.

권한은 어디서 확인해야 하나요?#

권한을 확인할 위치를 결정할 때는, 서로 다른 레이어에서 다중 검사를 구현하는 심층 방어(defense-in-depth) 원칙을 적용하세요. finder와 서비스 같은 저수준 레이어를 시작으로, GraphQL, 공개 REST API, 컨트롤러 같은 고수준 레이어 순으로 진행합니다.

자세한 내용은 추상화 재사용 지침을 참고하세요.

동일한 리소스를 여러 지점에서 보호하면, 방어 레이어 중 하나가 침해되거나 누락되더라도 고객 데이터가 추가 레이어에 의해 여전히 보호됩니다.

권한에 대한 자세한 내용은 보안 코딩 가이드라인의 권한 섹션을 참고하세요.

고려사항#

공유 비즈니스 로직 레이어(즉, 서비스 및 finder)에서 최대한 인가(authorization)를 강제해야 합니다. 이렇게 하면 REST, GraphQL, 컨트롤러 전반에서 인가가 일관되게 유지됩니다. 서비스 또는 finder가 적절한 위치인 이유는 다음과 같습니다:

  • 여러 엔드포인트가 서비스나 finder를 공유하므로, 다운스트림 로직이 재사용될 가능성이 높습니다.

  • 경우에 따라 레코드를 필터링하기 위해 인가 로직이 DB 쿼리에 포함되어야 합니다.

  • 보안 검사가 아닌 더 나은 UX를 제공하는 경우에만 표시 레이어에서 권한 검사를 사용해야 합니다. 예를 들어, 버튼과 같은 비데이터 요소를 표시하거나 숨기는 경우가 이에 해당합니다.

심층 방어의 단점은 다음과 같습니다:

  • DeclarativePolicy 규칙은 상대적으로 성능이 좋지만, 조건이 데이터베이스 호출을 수행할 수 있습니다.

  • 유지보수 비용이 높아집니다.

예외 사항#

개발자는 특정 케이스의 위험과 단점을 고려한 후, 단일 영역에서만 인가를 수행하도록 선택할 수 있습니다.

예외를 만들 때는 도메인 로직(서비스 또는 finder)을 진실의 단일 공급원(Single Source of Truth)으로 사용하는 것을 권장합니다.

백엔드 워커 로직과 같은 로직은 현재 사용자를 기반으로 한 인가가 필요하지 않을 수 있습니다. 서비스 또는 finder의 생성자가 current_user를 받지 않는 경우, 일반적으로 권한을 확인하지 않습니다.

프론트엔드#

UI 요소에서 ability 검사를 사용할 때는, 관련 백엔드 코드가 있다면 반드시 해당 코드에도 ability 검사를 사용하세요. 이렇게 하면 사용자가 적절한 접근 권한을 갖기 전까지 해당 기능을 사용할 수 없도록 보장합니다.

UI 요소가 HAML인 경우, 내장 Ruby를 사용하여 Ability.allowed?(user, action, subject)를 확인할 수 있습니다.

UI 요소가 JavaScript 또는 Vue인 경우, push_frontend_ability 메서드를 사용하세요. 이 메서드는 ApplicationController를 상속하는 모든 컨트롤러에서 사용 가능합니다. 다음과 같이 이 메서드를 사용하여 ability를 노출할 수 있습니다:

before_action do
  push_frontend_ability(ability: :read_project, resource: @project, user: current_user)
end

그런 다음 JavaScript에서 다음과 같이 ability 상태를 확인할 수 있습니다:

if ( gon.abilities.readProject ) {
  // ...
}

JavaScript에서 ability 이름은 항상 camelCase이므로, gon.abilities.read_project를 확인하면 작동하지 않습니다.

Vue 템플릿에서 ability를 확인하는 방법은 Vue에서 ability 접근에 관한 개발자 문서를 참고하세요.

#

  • 클래스가 current_user를 받는 경우, 해당 클래스가 인가를 담당할 수 있습니다.

예시: 새 API 엔드포인트 추가#

기본적으로 엔드포인트에서 인가를 수행합니다. 기존 ability를 확인하는 것이 합리적일 수 있으며, 그렇지 않다면 새 ability를 추가해야 할 수 있습니다.

참고로, 대부분의 엔드포인트는 리소스에 대한 CRUD(create, read, update, destroy) 작업으로 명확하게 분류할 수 있습니다. 서비스와 ability도 이에 따르므로, 많은 경우 Projects::CreateService 또는 :read_project와 같이 명명됩니다.

예를 들어, 전체 엔드포인트를 서비스로 추출한다고 가정해 봅시다. can? 검사는 이제 서비스 안에 위치합니다. 서비스가 기존 finder를 재사용하고 우리가 해당 finder를 수정하는 경우, finder에도 ability 검사를 추가해야 할까요?

  • finder가 current_user를 받지 않아 권한을 확인하지 않는 경우라면, 아마도 추가할 필요가 없습니다.

  • finder가 current_user를 받지만 권한을 확인하지 않는 경우라면, 해당 finder의 다른 사용 위치를 재확인하고 인가 추가를 고려해야 합니다.

  • finder가 current_user를 받고 이미 권한을 확인하는 경우라면, 우리의 케이스를 추가해야 하거나 기존 검사가 적절합니다.