시스템, 애플리케이션, 또는 네트워크에 접근하려는 사용자의 신원을 확인하는 과정.
이 사용자가 '누구'인지 식별하는 보안의 핵심 요소이다.
아주 간략하게 말하자면, 일반 회원과 관리자가 접근할 수 있는 페이지가 다르다고 할 때. 이걸 어떻게 나누는지 기준이 되는 개념이라고 생각하면 이해가 빠르다.
더 정확하게 말하자면, 인증Authentication 뒤에 인가Authorization라는 개념이 같이 사용되는 것이 보안 시스템의 기본 구성.
인증Authentication은 이 사용자가 누구인가를 식별하는 것, 인가Authorization는 이 식별된 사용자에게 어떤 권한을 부여할 것인가를 결정하는 개념.
로그인 화면에서 이메일과 비밀번호를 입력하여 본인을 증명하는 과정이 인증Authentication.
신원이 확인되면, 시스템은 그 사용자에게 신뢰된 신원을 부여하는 것이 인가Authorization. 사용자 ID, 세션 ID, 토큰(JWT) 등을 발급하는 과정이 여기에 포함된다.
인증Authentication 과정은 구현이 간단하다. 사용자의 신원을 확인하기만 하는, 상대적으로 작은 과정으로 이루어지기만 하면 되기 때문.
이메일/비밀번호 입력, OTP 인증, 소셜 로그인 같은 과정 등등.. 단순히 "이 사용자가 주장하는 신분이 맞는지 확인"하는 데 초점이 맞춰져 있다.
정해진 입력 값(예: 이메일, 비밀번호)과 검증 프로세스(예: 비밀번호 비교, 토큰 발급)만 갖춰져 있으면 된다.
문제가 되는 것은 인가Authorization 과정의 구현. 시스템의 복잡도와 사용자 권한 구조에 따라 인가 과정이 한없이 복잡해진다.
사용자 권한이 몇 단계로 나누어져야 하는지, 각 권한에는 무슨 능력을 어디까지 부여해야하는지, 권한이 상위/하위로 나누어지는지 (상위 권한이 하위 권한을 포괄하고 있는지) 등등..
개인 블로그 정도면 인가 과정이 복잡할 이유가 없지만, 기업 등지에서 사용될 프로그램 수준만 되어도 상상 이상으로 로직이 많고 복잡해진다.
사용자에게 하나 이상의 역할(Role)을 부여하고, 역할에 따라 권한을 정의하는 방식.
"Admin", "Editor", "Viewer" 등등..
User: { id: 1, name: "Alice", role: "Admin" }
if (user.role === "Admin") {
// 관리자 작업 허용
} else {
// 접근 금지
}
간단하고 직관적이며, 유지보수가 간편하다.
접근 권한을 세부적으로 다룰수 없고, 역할이 많아지면 관리가 복잡해진다.
역할뿐만 아니라 속성(Attribute)을 기반으로 권한을 정의.
사용자 속성, 요청 속성, 환경 속성 등을 조합하여 권한 부여.
사용자 속성: age, department, location.
자원 속성: resourceType, ownerId.
환경 속성: time, IP.
if (user.department === "HR" && resource.type === "EmployeeData") {
// 허용
} else {
// 거부
}
많은 권한들을 세세하게 제어할 수 있다.
권한이 너무 많으면 관리가 힘들어진다.
ACL 테이블 설계
Resource | User/Group | Permission |
---|---|---|
File1 | Alice | Read, Write |
File2 | Bob | Read |
if (acl.checkPermission(user.id, resource.id, "read")) {
// 허용
} else {
// 거부
}
각 자원별로 개별적인 권한 제어가 가능.
자원과 사용자가 많을 수록 리스트 관리가 어려워진다.
정책 파일 작성
{
"policyId": "1",
"effect": "allow",
"action": "read",
"resource": "file1",
"conditions": {
"user.department": "Engineering"
}
}
이후 OPA(Open Policy Agent)같은 정책 엔진으로 요청을 검증하도록 하는 방식.
정책을 중앙에서 관리하므로 유연하고 확장성이 뛰어나다.
정책 엔진을 추가로 설정해야 하므로 초기 설정이 복잡해진다.
JWT에 권한 정보를 포함
{
"sub": "1234567890",
"role": "Admin",
"permissions": ["read", "write", "delete"]
}
요청 시 토큰을 디코딩하여 확인
const token = req.headers.authorization.split(" ")[1];
const decoded = jwt.verify(token, secretKey);
if (decoded.permissions.includes("write")) {
// 허용
} else {
// 거부
}
인증과 권한 부여를 하나의 토큰으로 처리할 수 있다.
토큰의 관리가 복잡하다. (토큰에 포함되는 정보가 많을 수록, 그리고 발급된 토큰을 일정시간마다 무효화하지 않으면 보안의 의미가 없어진다.)
애플리케이션 규모
- 소규모: RBAC 또는 간단한 ACL.
- 대규모: ABAC, PBAC, 또는 Hybrid 방식.
변경 빈도
- 권한 정책이 자주 변경되면 PBAC처럼 정책 기반 접근이 유리.
보안 요구사항
- 세부적인 제어가 필요한 경우 ABAC 또는 ACL을 선택.
확장성
- 분산 시스템에서는 JWT 기반 접근이 적합.
실무에서는 위 방법론 중 여러 개를 동시에 선택하곤 한다.
전체적으로는 사용자에게 역할 기반 권한을 부여하되, 특정 작업에 한해서는 속성 기반의 권한을 사용한다던지..
정책 기반으로 권한을 제어하지만, 특정 자원에 한해서는 접근 가능 리스트ACL를 만들어둔다던지..