AI 보안 표현식
Spring Security의 SpEL 표현식 시스템을 AI 기반 위험 평가 함수로 확장합니다. Contexa의 AbstractAISecurityExpressionRoot는 URL 레벨 및 메서드 레벨 인가 결정에 실시간 Zero Trust 액션 평가를 제공합니다.
개요
Contexa는 Spring Security의 표현식 기반 접근 제어를 실시간으로 ZeroTrustAction 결과를 평가하는 AI 통합 함수로 확장합니다. 이 표현식은 URL 레벨 보안 구성과 메서드 레벨 어노테이션 모두에서 사용할 수 있습니다.
표현식 시스템은 두 개의 레벨로 구축됩니다:
- URL 레벨 — URL 정책에서 HTTP 요청 매칭을 위한
CustomWebSecurityExpressionRoot - 메서드 레벨 —
@Protectable을 사용한 어노테이션 기반 인가를 위한CustomMethodSecurityExpressionRoot
두 클래스 모두 공유 #ai.* 표현식 API를 제공하는 AbstractAISecurityExpressionRoot를 확장합니다. URL 레벨에서는 현재 사용자 기준의 ZeroTrustActionRepository 조회를 사용하고, 메서드 레벨에서는 요청 속성(contexa.zeroTrustAction)을 먼저 확인한 뒤 짧은 수명의 Caffeine 캐시와 저장소 조회를 순서대로 사용합니다.
Expression API 참조
모든 표현식은 SpEL에서 #ai 접두사를 통해 접근합니다. 이들은 AbstractAISecurityExpressionRoot에 정의되어 있으며 URL과 메서드 레벨 모두에서 사용할 수 있습니다.
| 표현식 | 반환 타입 | 설명 |
|---|---|---|
#ai.isAllowed() |
boolean |
AI 평가 결과가 ALLOW이면 true를 반환 |
#ai.isBlocked() |
boolean |
AI 평가 결과가 BLOCK이면 true를 반환 |
#ai.needsChallenge() |
boolean |
AI 평가 결과가 CHALLENGE이면 true를 반환 |
#ai.needsEscalation() |
boolean |
AI 평가 결과가 ESCALATE이면 true를 반환 |
#ai.isPendingAnalysis() |
boolean |
AI 평가 결과가 PENDING_ANALYSIS이면 true를 반환 |
#ai.hasAction(String) |
boolean |
현재 ZeroTrustAction이 특정 액션 문자열과 일치하는지 확인 |
#ai.hasActionIn(String...) |
boolean |
현재 액션이 제공된 액션 문자열 중 하나와 일치하면 true를 반환 |
#ai.hasActionOrDefault(defaultAction, actions...) |
boolean |
제공된 액션을 확인하며, ZeroTrustAction을 사용할 수 없는 경우 default boolean 값을 반환 |
URL 레벨 표현식
CustomWebSecurityExpressionRoot는 AbstractAISecurityExpressionRoot를 확장하고 HTTP 요청 평가에 필요한 웹 컨텍스트를 제공합니다. 현재 OSS 클라이언트 화면에서는 이 표현식이 주로 Policy Center의 수동/빠른 생성 흐름과 저장된 URL 정책 평가에 연결됩니다.
추가 URL 레벨 메서드
| 메서드 | 반환 타입 | 설명 |
|---|---|---|
hasIpAddress(String ipAddress) |
boolean |
요청이 주어진 IP 주소 또는 CIDR 범위에서 발생했는지 확인 |
getHttpMethod() |
String |
현재 요청의 HTTP 메서드(GET, POST 등)를 반환 |
사용 예제
이 표현식은 관리자 콘솔의 Policy Center에서 작성되거나 저장된 URL 정책 조건에서 사용됩니다:
// Allow only if AI approves AND user has USER role
#ai.isAllowed() and hasRole('USER')
// Allow if AI approves AND request is from internal network
#ai.isAllowed() and hasIpAddress('10.0.0.0/8')
// Deny only if AI explicitly blocks (permissive mode)
!(#ai.isBlocked())
// Allow or challenge actions only
#ai.hasActionIn('ALLOW', 'CHALLENGE')
메서드 레벨 표현식
CustomMethodSecurityExpressionRoot는 AbstractAISecurityExpressionRoot를 확장하고 소유권 검증 및 전체 hasPermission() 지원을 포함한 메서드 레벨 인가 기능을 추가합니다.
추가 메서드 레벨 메서드
| 메서드 | 반환 타입 | 설명 |
|---|---|---|
hasPermission(Object, Object) |
boolean |
CompositePermissionEvaluator를 통한 소유권 검사를 포함한 전체 권한 평가 |
hasPermission(Object, String, Object) |
boolean |
도메인별 라우팅이 포함된 대상 타입 기반 권한 평가 |
캐싱
메서드 레벨 표현식은 ZeroTrustAction 조회를 위해 2단계 캐시를 사용합니다:
- Caffeine 로컬 캐시 — 5초 TTL, 최대 10,000개 항목
- Redis — 기본 분산 저장소, 세션 범위
@Protectable과 함께 사용
메서드 레벨 AI 표현식은 일반적으로 @Protectable 어노테이션 및 @PreAuthorize와 함께 사용됩니다:
@PreAuthorize("#ai.isAllowed() and hasPermission(#id, 'USER', 'READ')")
@Protectable(ownerField = "userId")
public User getUser(Long id) { ... }
@PreAuthorize("#ai.isAllowed() and hasPermission(#orderId, 'ORDER', 'UPDATE')")
@Protectable(ownerField = "customerId", sync = true)
public void updateOrder(Long orderId, OrderDto dto) { ... }
@PreAuthorize("!(#ai.isBlocked()) and hasRole('ADMIN')")
@Protectable
public List<AuditLog> getAuditLogs() { ... }
URL vs 메서드 비교
두 표현식 루트는 서로 다른 인가 레이어를 담당하며 고유한 기능을 가집니다:
| 기능 | URL 레벨 | 메서드 레벨 |
|---|---|---|
| Expression Root | CustomWebSecurityExpressionRoot |
CustomMethodSecurityExpressionRoot |
| 캐시 | 요청 속성 + 저장소 조회 | 요청 속성 + Caffeine (5초 TTL) + 저장소 조회 |
| 소유권 검사 | 아니오 | 예 (ownerField 사용) |
hasPermission() |
제거됨 (URL 레벨 전용) | 전체 지원 |
hasIpAddress() |
예 | 아니오 |
| 트리거 | HTTP 요청 매칭 | @Protectable 어노테이션 |
| 일반적 사용 | Policy Center 기반 URL 정책 | 서비스 메서드 어노테이션 |
ZeroTrustAction 흐름
AI 보안 표현식은 AI 분석 파이프라인에서 생성된 ZeroTrustAction을 평가합니다. 다음 다이어그램은 초기 분석에서 인가 결정까지의 요청 흐름을 보여줍니다:
ZeroTrustActionRepository
액션 타입
| 액션 | 의미 | 일반적 응답 |
|---|---|---|
ALLOW |
AI 평가가 낮은 위험을 나타냄 | 정상적으로 접근 허용 |
BLOCK |
AI 평가가 높은 위험 또는 위협을 나타냄 | 접근 거부, 인시던트 기록 |
CHALLENGE |
AI 평가가 중간 위험을 나타냄 | 추가 검증 필요 (MFA, CAPTCHA) |
ESCALATE |
AI 평가가 사람의 검토를 필요로 함 | 수동 승인을 위해 보안 팀에 라우팅 |
PENDING_ANALYSIS |
AI 분석이 아직 진행 중 | 기본 정책 적용 또는 완료 대기 |
액션 해석 모델
공개 #ai API는 숫자형 위험 점수를 노출하지 않습니다. 현재 런타임은 Zero Trust 액션을 계산하고, 표현식은 그 액션을 기준으로 평가됩니다:
Resolved Zero Trust actions:
ALLOW -> #ai.isAllowed()
BLOCK -> #ai.isBlocked()
CHALLENGE -> #ai.needsChallenge()
ESCALATE -> #ai.needsEscalation()
PENDING_ANALYSIS -> #ai.isPendingAnalysis()
Fallback pattern:
#ai.hasActionOrDefault(''BLOCK'', ''ALLOW'')
실전 시나리오
시나리오 1: 위험 기반 접근 제어
AI 표현식을 사용하여 위험 수준에 따른 계층적 접근 제어를 구현합니다:
- 낮은 위험 — AI가
ALLOW를 반환, 접근 허용 - 중간 위험 — AI가
CHALLENGE를 반환, 추가 인증(MFA) 필요 - 높은 위험 — AI가
BLOCK을 반환, 접근 거부
// Strict mode: only allow if AI explicitly approves
#ai.isAllowed()
// Permissive mode: allow unless AI explicitly blocks
!(#ai.isBlocked())
// Challenge-aware: allow if permitted or after challenge completion
#ai.hasActionIn('ALLOW', 'CHALLENGE')
시나리오 2: AI + 역할 기반 하이브리드
심층 방어를 위해 AI 위험 평가와 전통적인 역할 기반 접근 제어를 결합합니다:
// Require both AI approval and appropriate role
#ai.isAllowed() and hasAnyAuthority('ROLE_USER', 'ROLE_ADMIN')
// Admin bypass with AI monitoring (AI can still block suspicious admin activity)
hasRole('ADMIN') and !(#ai.isBlocked())
// Elevated access requires both AI approval and specific authority
#ai.isAllowed() and hasAuthority('PERMISSION_SENSITIVE_DATA_READ')
시나리오 3: 소유권 + AI 검증
세밀한 접근 제어를 위해 AI 표현식을 @Protectable 소유권 검사 및 권한 평가와 결합합니다:
// AI + ownership + permission: triple-layered authorization
@Protectable(ownerField = "createdBy", sync = true)
@PreAuthorize("#ai.isAllowed() and hasPermission(#id, 'DOCUMENT', 'UPDATE')")
public void updateDocument(Long id, DocumentDto dto) { ... }
// AI + ownership for read operations
@Protectable(ownerField = "patientId")
@PreAuthorize("#ai.isAllowed() and hasPermission(#id, 'MEDICAL_RECORD', 'READ')")
public MedicalRecord getRecord(Long id) { ... }
// Fallback when AI is unavailable: default to deny
@Protectable(ownerField = "accountId")
@PreAuthorize("#ai.hasActionOrDefault('BLOCK', 'ALLOW') and hasPermission(#id, 'ACCOUNT', 'UPDATE')")
public void updateAccount(Long id, AccountDto dto) { ... }
Admin에서 AI 인식 정책 생성
AI 보안 표현식은 관리자 콘솔의 Policy Center에서 작성되는 정책 조건에 사용할 수 있습니다. 이를 통해 관리자는 코드 작성 없이 현재 Zero Trust 액션 결과를 정책 조건에 반영할 수 있습니다.
1단계: Policy Center 열기
관리자 콘솔에서 Policy Center를 연 뒤 Create 탭 또는 빠른 생성 흐름을 엽니다. 여기서 정책 대상 리소스와 HTTP 메서드 패턴을 선택합니다.
2단계: AI 조건 템플릿 선택
조건 편집기에서 사전 정의된 AI 표현식 템플릿 중 선택하거나 사용자 정의 SpEL 표현식을 작성합니다. 사용 가능한 템플릿:
- AI Approved —
#ai.isAllowed() - AI Not Blocked —
!(#ai.isBlocked()) - AI Approved + Role —
#ai.isAllowed() and hasRole('...') - Custom AI Expression —
#ai.*함수를 사용한 유효한 SpEL 작성
3단계: 승인 워크플로 구성
AI 생성 정책의 경우 승인 워크플로를 사용할 수 있습니다. AI 표현식이 포함된 정책은 다음과 같이 설정할 수 있습니다:
- 자동 승인 — 낮은 위험의 정책 변경에 즉시 적용
- 검토 필요 — 활성화 전 보안 팀 검토를 위해 대기열에 추가
- Shadow 모드 — 평가하되 적용하지 않음, AI 정책 효과 테스트용
4단계: 정책 효과 모니터링
활성화 후 관리자 콘솔에서 AI 정책 결과를 모니터링합니다:
- 정책별 허용/거부/챌린지 비율 확인
- 오탐(False Positive) 및 미탐(False Negative) 비율 추적
- 보호 리소스의 위험 점수 분포 분석
- 에스컬레이션 패턴 및 응답 시간 검토
캐시 아키텍처
AI 보안 표현식은 모든 표현식 평가마다 AI 분석을 다시 실행하지 않도록 캐시된 ZeroTrustAction 객체에 의존합니다. 캐싱 전략은 URL 레벨과 메서드 레벨 표현식 간에 다릅니다.
캐시 레이어
| 캐시 레이어 | 범위 | TTL | 최대 항목 | 사용 대상 |
|---|---|---|---|---|
| Request Attribute | 단일 HTTP 요청 | 요청 생명주기 | 요청당 1개 | URL 및 메서드 레벨 모두 |
| Caffeine | JVM 로컬 | 5초 | 10,000 | 메서드 레벨 전용 |
| Redis | 분산 (세션 범위) | 세션 TTL | 무제한 | URL 및 메서드 레벨 모두 |
Request Attribute 캐시는 단일 HTTP 요청 내에서 참조하는 표현식 수에 관계없이 ZeroTrustAction이 한 번만 해석되도록 보장합니다. 메서드 레벨의 Caffeine 캐시는 짧은 시간 내 반복 평가에 대해 저지연 접근을 제공합니다.