웹 오리진(RFC-6454) 개념을 바탕으로 한 ActivityPub 보안 프레임워크를 정립하고, 구현체를 위한 인증·인가 지침을 제시한다.
web origin 개념에 기반한 포괄적인 ActivityPub 보안 프레임워크를 개발한다.
ActivityPub 표준은 인증(authentication)과 인가(authorization) 메커니즘을 명시하지 않는다. 그러나 일부 경우에는 객체의 오리진의 중요성을 암시한다:
3. Objects
... Servers SHOULD validate the content they receive to avoid content spoofing attacks. (A server should do something at least as robust as checking that the object appears as received at its origin, but mechanisms such as checking signatures would be better if available).
7.3 Update Activity
... The receiving server MUST take care to be sure that the Update is authorized to modify its object. At minimum, this may be done by ensuring that the Update and its object are of same origin.
구현체는 활동과 객체의 유효성을 판단하기 위해 오리진 및 소유권 검사를 자주 활용하지만, 정확한 요구사항이 문서화되어 있지 않아 쉽게 간과될 수 있으며, 그 결과 GHSA-3fjr-858r-92rw와 같은 취약점으로 이어질 수 있다.
이 제안은 기존 관행을 정형화하고 구현자를 위한 지침을 제공하려 한다.
이 문서에서 “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, “OPTIONAL” 키워드는 RFC-2119에 기술된 대로 해석한다.
오리진 기반 보안 모델은 서버가 호스팅된 액터들 사이의 보안 경계를 강제하는 네트워크에서 사용되도록 설계되었다. 검증 없이 객체를 발행하는 서버는 지원하지 않는다.
객체 식별자는 HTTP(S) URI라고 가정한다. 이 모델은 다른 종류의 식별자에도 사용할 수 있지만, 이는 이 문서에서 다루지 않는다.
객체 식별자는 “오리진(origins)”이라 불리는 보호 도메인으로 묶을 수 있다. 이 개념은 RFC-6454에 설명된 “web origin” 개념과 유사하며, 객체 ID의 오리진은 동일한 알고리즘으로 계산된다.
동일 오리진 정책(same-origin policy)은 객체 간 관계를 언제 신뢰할 수 있는지를 결정한다. 서로 다른 오리진은 잠재적으로 적대적이라고 간주되며, 서로를 다양한 정도로 격리한다. 오리진을 공유하는 액터들은 단일 개인 또는 조직이 운영하는 단일 소프트웨어에 의해 모든 상호작용이 매개되므로 서로를 신뢰한다고 가정한다.
uri-scheme를 URI의 scheme 구성요소로 두고, 소문자로 변환한다.uri-host를 URI의 host 구성요소로 두고, 소문자로 변환한다.uri-port를 uri-scheme가 가리키는 프로토콜의 기본 포트로 둔다. 그렇지 않으면 uri-port를 URI의 port 구성요소로 둔다.(uri-scheme, uri-host, uri-port)를 반환한다.오리진은 scheme, host, port가 모두 동일할 때 동일하다.
인증은 ActivityPub 객체의 오리진을 검증하는 과정이다. 이는 애플리케이션을 spoofing 공격으로부터 보호하기 위해 수행된다.
객체는 다음 방법으로 인증할 수 있다:
객체를 인증할 수 없다면, MUST 폐기해야 한다.
오리진에서 가져오기는 기본 인증 방법이며, 이 문서에서 설명하는 다른 인증 방법들도 이에 의존한다. 다른 인증 방법을 사용할 수 없다면, 소비자(consumers)는 객체를 그 오리진에서 가져오기를 시도해야 한다.
비-익명(non-anonymous) ActivityPub 객체는 객체의 ID를 대상으로 하는 HTTP GET 요청을 수행하여 인증할 수 있다.
리다이렉트 체인에서 마지막 URI가 객체의 위치(location)이다. 위치는 검색된 객체의 ID와 일치하는 것이 SHOULD이다. 객체의 위치와 ID가 다르다면, 둘은 MUST 동일한 오리진을 가져야 한다.
객체가 보호됨 상태라면, 서버는 HTTP signature를 요구할 수 있다(MAY).
서버는 클라이언트로부터 수신한 모든 객체를 MUST 검증해야 한다. 액터가 수행하도록 인가되지 않은 행동을 나타내는 모든 activity는 MUST 거부되어야 한다. 특히 미디어 업로드에 주의를 기울여야 하는데, 악성 액터가 ActivityPub 문서를 미디어로 업로드하여 검증을 우회하려 할 수 있기 때문이다. 서버가 클라이언트가 임의의 파일을 업로드하도록 허용한다면, MUST 미디어를 다른 오리진(예: 다른 서브도메인)에서 제공해야 한다.
검증 우회에 공격자가 성공한 경우를 대비한 추가 보호로서, 소비자는 GET 요청의 응답이 application/ld+json; profile="https://www.w3.org/ns/activitystreams" 또는 application/activity+json 미디어 타입의 Content-Type 헤더를 포함하는지 MUST 확인해야 한다(자세한 내용은 GHSA-jhrq-qvrm-qr36 참고).
서버는 객체가 검증되기 전에는 MUST NOT 제공(serve)해야 한다.
서명 기반 인증은 다음 경우에 사용할 수 있다:
공개키(또는 검증 방법)의 ID는 객체의 ID와 MUST 동일한 오리진을 가져야 한다.
서버는 MUST NOT 비밀 키를 클라이언트와 공유해야 한다.
서버는 공개키를 나타내는 객체를 클라이언트가 생성하거나 갱신하도록 MUST NOT 허용해야 하며, 액터 및 다른 객체 안에 임베딩된 그러한 객체도 포함된다. 공개키는 publicKeyPem 및 publicKeyMultibase 속성으로 식별할 수 있다. 다른 오리진을 가진 임베딩된 공개키는 허용된다.
키 탈취 또는 불충분한 검증으로 인한 피해를 최소화하기 위해, 소비자는 서명 키가 서명된 객체와 동일한 소유자를 갖는지 MUST 검증해야 한다. 또한 소비자는 상호(claim) 검증을 통해 키의 소유권을 MUST 확인해야 한다.
[!WARNING] JSON-LD 소비자는
publicKeyPem및publicKeyMultibase속성이 없는 특수 제작된 JSON 객체를 공개키로 처리하도록 속을 수 있다. 이러한 종류의 공격에 대한 방어는 이 문서에서 설명하지 않는다.
일부 경우, 감싸는(wrapping) 객체가 신뢰될 때 임베딩된 객체도 신뢰할 수 있다:
인가란 객체를 create, read, update or delete할 권한을 검증하는 과정이다.
소유권은 ActivityPub 객체의 속성으로 표시된다. 이 속성의 이름은 객체 클래스에 따라 다르다:
id 속성으로 표시된다.actor 속성이 있으며, activity를 수행한 액터를 설명한다. 이 액터가 activity의 소유자로 간주된다.owner 및 controller 속성을 가진다.attributedTo 속성을 가질 수 있는데, 이는 객체가 귀속(attributed)되는 액터를 설명한다. 이 액터가 객체의 소유자로 간주된다.일부 경우 소유권은 암묵적일 수 있다. 예:
replies 컬렉션은 게시물이 귀속된 액터가 소유한다.익명 객체는 소유자를 갖지 않는 것이 원칙이다.
애플리케이션은 객체의 소유자를 결정하기 위해 다음 알고리즘을 SHOULD 사용한다:
Link이면 오류를 반환한다.Object도 Collection도 아니고, 객체에 attributedTo 속성이 있으면 오류를 반환한다.Actor이면 id 속성의 값을 반환한다.VerificationMethod이면 controller 속성의 값을 반환한다.PublicKey이면 owner 속성의 값을 반환한다.Activity이면 actor 속성의 값을 반환한다.Object 또는 Collection이면 attributedTo 속성의 값을 반환한다.객체의 소유자는 MUST 액터여야 한다.
객체의 식별자와 그 소유자의 식별자는 MUST 동일한 오리진을 가져야 한다.
[!WARNING] Activity Vocabulary에 따르면
actor및attributedTo속성은 여러 액터에 대한 참조를 포함할 수 있다. 이러한 시나리오는 이 문서에서 다루지 않으며, 구현자는 사례별로 적절한 인가 절차를 결정해야 한다.
소유자는 scheme과 host를 소문자로 변환한 뒤 식별자가 동일하면 동일한 것으로 본다.
객체를 생성하는 액터는 MUST 그 객체의 소유자여야 한다.
객체의 소유자는 이를 수정 및 삭제할 권한이 있다. 이 권한은 상호 claim으로도 지정될 수 있다.
객체를 수정 또는 삭제하는 activity의 소유자가 해당 작업을 수행할 권한이 없다면, 그 activity는 MUST 거부되어야 한다. 그러한 activity가 다른 서버로부터 수신되었고 권한을 검증할 수 없다면, 수신자는 activity의 액터와 영향을 받는 객체의 소유자가 동일한 오리진을 가질 경우 그 activity를 MAY 수락할 수 있다.
예:
Update 및 Delete activity와, object 속성이 가리키는 객체는 동일한 소유자를 가질 것으로 기대된다.Undo activity와, object 속성이 가리키는 객체는 동일한 소유자를 가질 것으로 기대된다.Add 및 Remove activity와, target 속성이 가리키는 객체는 동일한 소유자를 가질 것으로 기대된다.Announce 및 Like activity는 object 속성이 가리키는 객체를 수정하지 않으므로, 소유자가 달라도 된다.보호된 객체가 조회될 때, 서버는 GET 요청에 객체의 의도된 대상(intended audience)에 속한 소유자의 키로 생성된 HTTP signature가 포함되어 있는지 MUST 검증해야 한다.
서버는 객체가 공개(public)인 경우에도 서명을 요구할 수 있다(MAY). 이 경우 요청은 server actor가 소유한 키로 서명할 수 있다.
proxyUrl 엔드포인트를 구현하는 서버는 객체에 대한 접근이 그 객체의 의도된 대상에 속하는 액터로 제한되도록 MUST 보장해야 한다.
소유권이 변경될 때, 새 소유자 ID는 기존 소유자 ID와 MUST 동일한 오리진을 가져야 한다.
한 객체가 어떤 claim을 명시하고, 다른 객체가 그에 대한 역방향(reverse) claim을 명시할 때, claim들은 상호적(recursive/reciprocal)이라고 간주된다.
예:
서로 다른 오리진을 가진 객체들 사이의 관계도 가능하지만, MUST 두 오리진이 모두 수행한 상호 claim으로 확인되어야 한다. 이 경우 동일 오리진 정책을 우회할 수 있다.
예:
alsoKnownAs에 포함되어 있다면, 액터는 Move activity를 수행하여 한 서버에서 다른 서버로 마이그레이션할 수 있다.CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
법이 허용하는 범위 내에서, 이 Fediverse Enhancement Proposal의 저자들은 본 작업에 대한 모든 저작권 및 관련 권리 또는 인접권을 포기했다.