가이드라인

인증 및 권한 부여

인증(AuthN)과 권한 부여(AuthZ)는 둘 중 하나에 취약한 취약점이 자주 발생하기 때문에 매우 중요한 주제입니다. 너무 자주 발생하기 때문에 일반적으로 취약점의 정의나 원인에 대한 불확실성이 어느 정도 존재합니다. 

각 용어의 주요 내용은 다음과 같습니다:

  • 인증: 사용자는 누구인가요? 
  • 권한 부여: 사용자에게 어떤 액세스 권한이 있어야 하나요? 

아래에서 별도로 살펴보겠습니다.

인증(식별 및 인증 실패)

부적절한 인증은 다음과 같은 다양한 취약점을 야기할 수 있습니다:

  • 특정 페이지/엔드포인트에 인증이 없는 경우
  • 무차별 대입 공격(크리덴셜 스터핑)에 대한 보호 기능 부족
  • 안전하지 않은 계정/비밀번호 복구 프로세스
  • 안전하지 않은 인증 토큰 생성, 유효성 검사, 만료, 전송 또는 저장
  • 사용자가 2FA로 인증했다는 유효성 검사가 부적절하거나 누락되었습니다(해당되는 경우).

목록의 첫 번째 항목(인증 부재)은 실제로 관찰되는 가장 일반적인 문제입니다. 개발자가 페이지나 엔드포인트에 필요한 인증 수준을 명시적으로 주석 처리하거나 구성해야 하는 경우가 많은데, 이 단계를 놓치기 쉽습니다. 

시스템이 열리지 않는 것보다 닫히지 않도록 하는 것이 좋은 관행입니다. 따라서 각 엔드포인트에 인증된 사용자 세션이 필요하다는 정보를 주석으로 추가하는 대신, 특별히 재정의하지 않는 한 모든 경로에 인증된 사용자 세션이 필요하다는 것을 기본값으로 설정해야 합니다. 이렇게 하면 오류의 여지를 크게 줄일 수 있습니다.

권한 부여(액세스 제어 실패)

권한 부여 문제는 매우 일반적인 여러 가지 방식으로 나타날 수 있습니다:

  • 안전하지 않은 직접 객체 참조(IDOR)
  • 누락된 기능 수준 액세스 제어(누락된 AuthZ)
  • 권한 에스컬레이션(수평 또는 수직)

안전하지 않은 직접 객체 참조

객체에는 객체를 참조하기 위한 키로 사용되는 고유 식별자(ID)가 있는 경우가 많습니다. 사용자가 주문, 계정 또는 이와 유사한 것을 보기 위해 요청을 보내면 일반적으로 이 ID가 포함됩니다. '안전하지 않은 직접 개체 참조'는 애플리케이션이 사용자가 해당 특정 개체에 액세스할 수 있는지(또는 없는지) 검증하지 못할 때 발생합니다.

누락된 기능 수준 액세스 제어 

또 다른 일반적인 취약점은 페이지나 엔드포인트(객체가 아닌)에 대한 권한 확인이 없다는 것입니다. 

사용하는 프레임워크에 따라 개발자는 핸들러에서 권한을 확인하거나 엔드포인트에 주석을 달고 엔드포인트를 호출하는 데 필요한 요구 사항을 지정해야 하는 것이 일반적입니다. 

안타깝게도 이러한 추가 단계는 잊어버리기 쉽기 때문에 일부 인증 취약점이 발생하는 경우가 많습니다.

권장 사항

기본값은 열림이 아닌 닫힘입니다.

인증과 권한 부여의 경우 모두 개방형 대신 폐쇄형으로 기본 설정하는 원칙이 중요합니다. 

언어/프레임워크에 따라 애플리케이션에 대한 모든 경로의 기본값으로 가능한 가장 높은 역할 또는 권한을 가진 인증된 세션이 필요한지 확인하는 것이 좋습니다. 이렇게 하면 개발자가 경로에 대한 요구 사항을 재정의해야 합니다. 

cs

// Ensure the default behaviour is to authenticate requests, and check if they are admin
[Authenticate]
[Authorize("Admin")]
public class SecureController : Controller
{

}

public class MyController : SecureController
{

    // Overrides the Authorize attribute inherited to allow any user to access the page
    [Authorize("User")]
    public Page ShowUserProfile() {
        
    }   

    // Can only be accessed by an Admin user
    public Page ShowAdminPage() { 

   }

    // Overrides the Authenticate and Authorize attribute to allow ME
    [AllowAnonymous]
    public Page ShowLoginPage() {
       
    } 

}

서비스에서 권한 확인 적용

데이터에 액세스할 때 모든 데이터 액세스가 일관된 방식으로 관련 액세스 및 권한 확인을 시행하도록 하는 것이 매우 중요합니다. 이는 일반적으로 도메인 서비스를 사용하여 달성할 수 있습니다.

추가 예제

아래에는 안전한 인증과 안전하지 않은 인증 및 권한 부여의 차이점을 잘 보여 주는 짧은 예시가 나와 있습니다. 

C# - 안전하지 않음

누락된 인증

public class AdminController : Controller
{

    // INSECURE: Does not check whether the user is logged in before showing an Admin page
    public Page ShowAdminPage() {

    }

}

누락된 승인

[Authenticate]
public class AdminController : Controller
{

    // INSECURE: Does not check the Authorization of the user before showing an Admin page public Page ShowAdminPage() {

    }

}

C# - 보안

[Authenticate]
[Authorize("Admin")]
public class AdminController : Controller
{

    // SECURE: Both checks that the user is logged in, and has the Admin role
    public Page ShowAdminPage() {

    }

}