권한 부여
권한 확인은 어디에서 해야 하나요?
권한을 확인할 위치를 결정할 때에는, 여러 층에서 다중 확인을 통해 방어를 실시하여 다양한 층에서 여러 확인을 수행함으로써 다층 방어를 적용합니다. 저수준 층에서 시작해서 찾기기능과 서비스 등과 같은 층을 거쳐 GraphQL, 공개 REST API 및 컨트롤러와 같은 고수준 층까지 이어집니다.
자세한 정보는 추상화 재사용 가이드라인을 참조하세요.
동일한 리소스를 여러 지점에서 보호하는 것은, 하나의 방어층이 손상되거나 누락되더라도 추가적인 층에 의해 고객 데이터가 여전히 보호받을 수 있다는 것을 의미합니다.
권한에 대한 자세한 정보는 보안 코딩 가이드라인의 권한 섹션을 참조하세요.
고려 사항
서비스나 찾기 기능은 적합한 위치입니다. 왜냐하면:
- 여러 엔드포인트가 서비스나 찾기 기능을 공유하기 때문에 하류 로직이 재사용될 가능성이 높습니다.
- 때로는 권한 확인 논리를 레코드 필터링을 위해 DB 쿼리에 통합해야 할 수도 있습니다.
- 디스플레이 층에서 권한 확인을 제공하는 것은 좋지 않으며, 이는 더 나은 사용자 경험을 제공하는 것이지 보안 확인이 아닙니다. 예를 들어, 버튼과 같은 비데이터 요소의 표시 및 숨김 기능이 있습니다.
다층 방어의 단점은 다음과 같습니다:
- ‘DeclarativePolicy’ 규칙은 비교적 성능이 우수하지만 조건부 문은 데이터베이스 호출을 수행할 수 있습니다.
- 더 높은 유지보수 비용.
예외 사항
개발자는 특정 사례에 대한 위험과 단점을 따져본 후에 권한을 한 곳에서만 확인하기로 선택할 수 있습니다.
예외 사례를 처리할 때에는 도메인 논리(서비스 또는 찾기 기능)를 예외처리의 근거로 삼는 것이 좋습니다.
백엔드 워커 논리와 같은 경우에는 현재 사용자를 기반으로 한 권한 확인이 필요하지 않을 수 있습니다. 서비스나 찾기 기능의 생성자가 ‘current_user’를 예상하지 않는 경우에는 일반적으로 권한 확인을 수행하지 않습니다.
프론트엔드
UI 요소에서 어빌리티 확인을 사용할 때, 해당 기능을 사용하기 전에 백엔드 코드에 대한 어빌리티 확인도 반드시 수행하십시오. 이렇게 하면 사용자가 적절한 액세스 권한이 있는 경우를 제외하고는 해당 기능을 사용할 수 없도록 보장할 수 있습니다.
UI 요소가 HAML인 경우, Ability.allowed?(user, action, subject)
를 확인하기 위해 내장 루비를 사용할 수 있습니다.
UI 요소가 JavaScript나 Vue인 경우, ApplicationController
에서 상속받는 모든 컨트롤러에서 사용할 수 있는 push_frontend_ability
메서드를 사용하세요. 이 메서드를 사용하여 어빌리티를 노출시킬 수 있습니다. 예를 들어 다음과 같이 사용할 수 있습니다:
before_action do
push_frontend_ability(ability: :read_project, resource: @project, user: current_user)
end
그런 다음 JavaScript에서 어빌리티의 상태를 다음과 같이 확인할 수 있습니다:
if ( gon.abilities.readProject ) {
// ...
}
JavaScript에서의 어빌리티의 이름은 항상 카멜 케이스입니다. 따라서 gon.abilities.read_project
를 확인하는 것은 작동하지 않습니다.
Vue 템플릿에서 어빌리티를 확인하려면, Vue에서 Vue에서 권한에 액세스하는 방법의 개발자 문서를 참조하세요.
팁
클래스가 current_user
를 수용하는 경우, 해당 클래스가 권한 부여에 책임이 있을 수 있습니다.
예시: 새로운 API 엔드포인트 추가
기본적으로 엔드포인트에서 권한을 확인합니다. 기존의 어빌리티 확인이 합리적일 수 있습니다. 그렇지 않은 경우에는 아마도 새로운 어빌리티를 추가해야 합니다.
덧붙여 말하자면, 대부분의 엔드포인트는 리소스에 대한 CRUD(생성, 읽기, 업데이트, 삭제) 동작으로 깔끔하게 분류할 수 있습니다. 이에 따라 서비스와 어빌리티 역시 비슷한 패턴을 따르는데, 이것이 많은 것들이 ‘Projects::CreateService’ 또는 :read_project
와 같은 이름을 가지는 이유입니다.
예를 들어, 기존의 엔드포인트 전체를 서비스로 추출한다고 가정해보겠습니다. 이제 can?
확인은 서비스 내부에 있을 것입니다. 서비스가 목적에 맞게 수정하려는 기존의 찾기기능을 재사용한다고 가정해보겠습니다. 그럴 경우에 찾기기능이 어빌리티 확인을 수행해야 할까요?
- 만약 찾기기능이
current_user
를 받아들이지 않으며 따라서 권한 확인을 수행하지 않는 경우에는 아마도 아닐 것입니다. - 찾기기능이
current_user
를 받아들이고 권한 확인을 수행하지 않는 경우에는 찾기기능의 다른 사용 사례를 다시 확인하고 권한 부여를 추가할지 고려해 보아야 합니다. - 찾기기능이
current_user
를 받아들이고 이미 권한 확인을 수행한다면, 새로운 케이스를 추가해야 하거나 기존의 확인이 적절한지를 다시 확인해야 할 것입니다.