침해된 웹 게이트웨이는 여전히 어디까지 도달할 수 있는가
웹 게이트웨이는 방문자가 무엇을 여는지 제한할 뿐, 침해된 호스트가 어디로 연결할 수 있는지는 제한하지 않는다. 두 가지 검토, 권한 표, 도달 범위를 재는 명령.
게이트웨이 호스트가 인증서가 아직 유효한 동안 침해되었다고 가정하자. 방문자가 어떤 페이지를 요청할 수 있는지 규정한 모든 규칙은 그대로 유효하며, 그 규칙 중 어느 것도 공격자가 이제 그 호스트에서 데이터베이스 서브넷을 향해 여는 연결을 제한하지 않는다. 이 간극이 웹 전용 진입점이 분할된 네트워크와 같은 주장이 아닌 이유다. 두 주장은 서로 다른 출발점에서 별도의 검토가 필요하며, 그 전에는 어느 쪽도 정직하게 말할 수 없다.
두 가지 주장, 그리고 그중 하나만 방문자에서 시작한다
첫 번째 주장은 사람에 관한 것이다. 브라우저와 유효한 세션을 가진 방문자는 하나의 애플리케이션만 열 수 있고 그 밖의 것은 열 수 없다. 웹 전용 진입점은 이 주장에 잘 답한다. 방문자가 경로가 아니라 페이지를 받기 때문이다. 그 답은 가치가 있으며, 대부분의 다이어그램이 기록하는 유일한 주장이기도 하다.
두 번째 주장은 구성 요소에 관한 것이다. 게이트웨이 또는 그 뒤의 애플리케이션 프로세스가 다른 사람의 통제 아래 있다고 가정한다. 그 가정에서 질문은 어떤 URL이 허용되는가에서 그 프로세스가 여전히 어떤 목적지와 ID에 도달할 수 있는가로 바뀐다.
두 주장은 소유자가 다르고, 다른 증거를 만들며, 독립적으로 실패한다. ID 팀은 세션 테스트로 첫 번째를 보여 줄 수 있다. 두 번째는 네트워크 정책, 서비스 계정 검토, 호스트 통제가 필요하다. 방문자의 절반만 기록하는 설계는 검토 슬라이드에서는 완전해 보이고 사고 중에는 빈약해 보인다. 침해 후에 중요한 통제가 처음부터 범위에 없었기 때문이다. 각 통제가 어느 주장을 뒷받침하는지 이름 붙여라. 그렇지 않으면 하나의 게이트웨이 규칙이 둘 모두의 공적으로 계산된다.
구체화한 경비 서비스, 그리고 그것이 잃는 두 가지 방식
경비 서비스를 예로 들어 보자. 10.60.4.10의 공개 게이트웨이가 직원을 인증하고 승인된 요청을 포트 8443의 애플리케이션 리스너로 전달하며, 그 애플리케이션은 expenses_app 역할로서 10.60.4.20:5432의 PostgreSQL 리스너 하나에 도달한다. 직원은 일반적인 내부 접근을 받도록 되어 있지 않다. 정상 운영에서 이 설계는 데이터베이스 리스너를 어디에도 공개하지 않고 애플리케이션 전용 진입점을 실제로 제공한다. 주소가 중요한 이유는 이 글의 이후 모든 검사가 그 주소를 지목하기 때문이다.
이제 게이트웨이를 신뢰 집합에서 제거한다. 프로세스가 공격자의 것이 되면 10.60.4.10은 어떤 목적지에 도달할 수 있는가. 방문자를 제한하던 URL 필터는 게이트웨이 호스트가 데이터베이스 서브넷을 향해 여는 연결에 대해 아무 말도 하지 않는다.
대신 애플리케이션 프로세스를 제거하면 권한의 형태가 바뀐다. expenses_app 역할, 그 서버가 도달할 수 있는 서비스, 그 계정이 읽을 수 있는 파일이다. 두 경우 모두 백엔드 경계가 없는 채로 앞문만 웹 전용으로 남을 수 있다. 따라서 앞문의 표시는 두 질문 중 어느 것에도 답이 아니다.
각 당사자가 실제로 보유한 권한을 지도화한다
의도된 허가로 쓰인 계약은 설계를 그대로 되풀이하는 경향이 있다. 보유한 권한, 초과를 반증하는 검사, 그 검사의 소유자로 쓰면 모든 행이 검증 가능해진다. 이 표는 위 예시에 대한 제안이며 제품 주장이 아니다.
| Component | Authority it actually holds | Check that proves the denial | Owner of the check |
|---|---|---|---|
| Identity provider | Issues assertions and session cookies, and holds no network path of its own | A request to the application URL without a session is redirected to the login page | Identity team |
| Public gateway host | TCP reachability to whatever its routing table and egress rules permit | An egress rule drops 10.60.4.20:5432 and the probe reports the port filtered | Network platform team |
| Application role | SQL privileges granted to expenses_app inside the expenses database | A privilege query shows no ownership or create right on any other schema | Application team |
| Database listener | Accepts connections only from the source ranges named in its host-based rules | A connection from an unlisted address is refused before authentication | Database administrator |
| Management path | Administrative access reserved for patching, monitoring and recovery | A staff workstation cannot reach the administrative port or jump through it | Platform owner |
소유는 권한을 따른다. ID 팀이 어서션을, 네트워크 플랫폼 팀이 경로를, 애플리케이션 팀이 데이터베이스 역할을, 데이터베이스 관리자가 리스너와 그 호스트 기반 규칙을, 플랫폼 소유자가 관리 평면을 소유한다. 소유자 없는 거부는 문서의 문장일 뿐 통제가 아니다.
이 분리는 이중 계산도 막는다. 포트 제한은 테이블 권한을 표현할 수 없고, 데이터베이스 역할은 호스트가 무관한 서브넷으로 소켓을 여는 것을 막을 수 없다.
주장하지 말고 게이트웨이가 도달할 수 있는 대상을 세어라
경계 주장은 그 뒤의 셈만큼만 좋다. 게이트웨이 호스트에서 세 명령이 경로 선택, 실시간 검사, 이그레스 정책을 다룬다.
ip route get 10.60.4.20
nc -zv 10.60.4.20 5432
sudo nft list chain inet filter output출력은 그 순서로 읽는다. 경로는 10.60.4.20이 그 호스트에서 애초에 선택되는지 말하고, 검사는 리스너가 응답하는지 말하며, 규칙 목록은 정책이 패킷을 막는지 아니면 경로에 처음부터 아무것도 없었는지를 보여 준다.
애플리케이션 호스트에서 셈을 반복한다. 거기서 데이터베이스 쪽은 애플리케이션 역할로 실행하는 하나의 질의다.
psql -h 10.60.4.20 -U expenses_app -d expenses -c 'select rolname, rolsuper, rolcreatedb from pg_roles'다른 스키마를 읽을 수 없는 역할 아래의 성공적인 연결은 소유자 역할 아래의 성공적인 연결과 다른 결과다. 발견은 두 번째뿐이다.
거부를 기록하고, 그다음 검토에 날짜를 붙인다
수용은 의도가 아니라 결과로 쓴다. 직원 세션은 리스너에 도달할 수 없고, 게이트웨이 호스트는 무관한 서브넷에 도달할 수 없으며, 애플리케이션 역할은 데이터베이스를 만들 수 없다. 각각은 이름 붙은 소유자와 날짜가 있는 별도의 검사다.
모니터링, 패치, 복구는 그것들을 위해 설계된 관리 경로로 도달 가능하게 유지한다. 소유자까지 차단하는 경계는 장애가 되고, 그 장애에 대한 흔한 첫 대응은 규칙을 다시 넓히는 것이다. CISA 경계 지침 은 내부 네트워크 사이의 트래픽을 포함해 정당화된 포트와 프로토콜로 인바운드와 아웃바운드 접근을 제한할 것을 요구한다. 이는 대부분의 다이어그램이 빠뜨리는 백엔드 시작 방향이다.
검토에 날짜를 붙이고 그 소유자를 지목한다. 게이트웨이 이미지, 라우팅 테이블, 애플리케이션 역할 중 무엇이든 바뀐 뒤에는 셈과 권한 질의를 다시 실행한다.