웹 사물(WoT) 디스커버리

W3C 권고안

이 문서에 대한 자세한 정보
이 버전:
https://www.w3.org/TR/2023/REC-wot-discovery-20231205/
최신 공개 버전:
https://www.w3.org/TR/wot-discovery/
최신 편집자 초안:
https://w3c.github.io/wot-discovery/
이력:
https://www.w3.org/standards/history/wot-discovery/
커밋 이력
구현 보고서:
https://w3c.github.io/wot-discovery/testing/report.html
편집자:
Andrea Cimmino (Universidad Politécnica de Madrid)
Michael McCool (Intel Corp.)
Farshid Tavakolizadeh (초청 전문가)
Kunihiko Toumura (Hitachi, Ltd.)
이전 편집자:
Farshid Tavakolizadeh (Fraunhofer-Gesellschaft) - 까지
피드백:
GitHub w3c/wot-discovery (풀 리퀘스트, 새 이슈, 열린 이슈)
public-wot-wg@w3.org로 제목 줄에 [wot-discovery] … 메시지 주제 …를 포함 (아카이브)
정오표:
정오표가 있습니다.
기여자
GitHub 저장소에 있음
저장소
GitHub에 있습니다
버그 보고

번역도 참조하십시오.


초록

W3C 웹 사물(WoT)은 IoT 플랫폼과 애플리케이션 도메인 전반의 상호운용성을 가능하게 하기 위한 것이다. 이 목표를 달성하기 위한 핵심 메커니즘 중 하나는 IoT 장치나 서비스가 적절한 추상화 수준에서 네트워크를 통해 제공하는 상호작용을 설명하는 메타데이터를 정의하고 사용하는 것이다. WoT 사물 설명 명세는 이 목표를 충족한다.

그러나 사물을 사용하려면 먼저 그 사물 설명을 얻어야 한다. 이 문서에서 설명하는 WoT 디스커버리 프로세스는 이 문제를 다룬다. WoT 디스커버리는 다양한 사용 사례에서 WoT 사물 설명의 배포를 지원해야 한다. 여기에는 임시 시스템과 설계된 시스템, 개발 중과 런타임, 그리고 로컬 네트워크와 전역 네트워크 모두가 포함된다. 또한 이 프로세스는 기존 디스커버리 메커니즘과 함께 동작하고, 보안을 갖추며, 개인정보를 보호하고, WoT 사물 설명에 대한 업데이트와 IoT 생태계의 동적이고 다양한 특성을 효율적으로 처리할 수 있어야 한다.

WoT 디스커버리 프로세스는 두 단계, 즉 도입(Introduction)과 탐색(Exploration)으로 나뉜다. 도입 단계는 기존 디스커버리 메커니즘을 활용하지만 메타데이터를 직접 노출하지 않는다. 이 단계는 단순히 탐색 서비스를 발견하는 데 사용되며, 탐색 서비스는 안전한 인증과 권한 부여 이후에만 메타데이터를 제공한다. 이 문서는 두 가지 탐색 서비스를 규범적으로 정의한다. 하나는 정규 웹 서비스에서 단일 WoT 사물 설명을 배포하는 서비스로, 자기 설명을 특별한 경우로 포함한다. 다른 하나는 사물 설명 컬렉션을 위한 검색 가능한 WoT 사물 설명 디렉터리 서비스이다. 또한 다양한 도입 서비스도 설명되며, 필요한 경우 이를 지원하기 위한 규범적 정의가 제공된다.

이 문서의 상태

이 섹션은 이 문서가 발행된 시점의 상태를 설명한다. 현재 W3C 발행물 목록과 이 기술 보고서의 최신 개정판은 https://www.w3.org/TR/의 W3C 기술 보고서 색인에서 확인할 수 있다.

이 명세의 향후 업데이트에는 새로운 기능이 포함될 수 있다.

이 문서는 웹 사물 워킹 그룹권고안 트랙을 사용하여 권고안으로 발행했다.

W3C는 웹 표준으로서 이 명세의 광범위한 배포를 권장한다.

W3C 권고안은 광범위한 합의 형성을 거친 후 W3C와 그 회원이 승인하고, 구현에 대해 워킹 그룹 구성원으로부터 로열티 없는 라이선스 약속을 받은 명세이다.

이 문서는 W3C 특허 정책에 따라 운영되는 그룹에 의해 작성되었다. W3C는 이 그룹의 산출물과 관련하여 이루어진 모든 특허 공개의 공개 목록을 유지하며, 해당 페이지에는 특허를 공개하기 위한 지침도 포함되어 있다. 실제로 해당 개인이 필수 청구항을 포함한다고 믿는 특허에 대해 알고 있는 개인은 W3C 특허 정책 제6절에 따라 해당 정보를 공개해야 한다.

이 문서는 2023년 11월 03일 W3C 프로세스 문서의 적용을 받는다.

1. 소개

웹 사물(WoT)은 웹 기술을 IoT 장치와 통합하고 사용하는 것을 지원하는 아키텍처를 정의한다. WoT 아키텍처 [wot-architecture11] 문서는 지원되는 기본 개념과 사용 패턴을 정의한다. 그러나 WoT 사물 설명 [wot-thing-description11]은 WoT 디스커버리의 목적이 WoT 사물 설명을 사용 가능하게 하는 것이므로 WoT 디스커버리의 핵심 명세이다. 구체적으로, WoT 디스커버리는 인증되고 권한이 부여된 엔터티(그리고 오직 그러한 엔터티)만이 특정 의미 체계를 갖거나 특정 상호작용을 포함하는 등 일련의 기준을 만족하는 WoT 사물 설명을 찾을 수 있도록 해야 한다. 반대로, 보안 및 개인정보 보호 목표를 지원하기 위해 WoT 디스커버리 프로세스는 권한이 없는 엔터티에 정보를 누설해서는 안 된다. 여기에는 사물 설명 자체에 배포된 정보뿐 아니라 특정 엔터티가 특정 정보를 요청하고 있다는 정보의 누설도 포함된다.

이미 여러 디스커버리 메커니즘이 정의되어 있으므로 [Discovery-Categorization-IoT], 우리가 새 메커니즘을 제안하는 이유를 명확히 해야 한다. 첫째, 많은 기존 디스커버리 메커니즘은 보안 및 개인정보 보호가 비교적 약하다. 우리의 목표 중 하나는 메타데이터를 보호하기 위해 모범 사례를 사용할 뿐 아니라 필요에 따라 미래의 모범 사례를 지원하도록 업그레이드할 수 있는 메커니즘을 수립하는 것이다. 둘째, 우리는 디스커버리를 로컬 및 비로컬 메커니즘을 모두 포함하는 넓은 의미로 사용한다. 로컬 메커니즘은 브로드캐스트 프로토콜을 사용할 수 있지만, 비로컬 메커니즘은 브로드캐스트가 확장 가능하지 않은 현재 네트워크 세그먼트를 넘어설 수 있으므로 검색 서비스와 같은 다른 접근 방식이 필요하다. 우리의 접근 방식은 필요에 따라 기존 메커니즘을 사용하여 더 일반적이고 안전한 메타데이터 배포 시스템으로 부트스트랩하는 것이다. 셋째, 우리가 배포하는 메타데이터인 WoT 사물 설명은 매우 구조화되어 있으며 데이터 스키마와 의미 주석 같은 풍부한 데이터를 포함한다. 단순한 키-값 쌍 목록에 기반한 기존 디스커버리 메커니즘은 적절하지 않다. 동시에 SPARQL [SPARQL11-OVERVIEW]과 같은 의미 데이터 질의를 위한 기존 표준의 사용은 일부 고급 사용 사례에는 적합할 수 있지만, 예상되는 많은 IoT 애플리케이션에는 너무 많은 노력이 필요할 수 있다. 따라서 더 기본적인 애플리케이션을 다루기 위해 더 단순한 질의 메커니즘도 정의한다.

몇 가지 기본 용어를 정의한 뒤, WoT 디스커버리의 기본 사용 사례와 요구사항을 요약한다. 이들은 WoT 사용 사례 [wot-usecases] 및 WoT 아키텍처 [wot-architecture11] 문서에 제시된 더 상세하고 포괄적인 사용 사례 및 요구사항의 하위 집합이다. 그런 다음 2단계 도입/탐색 접근 방식을 사용하는 WoT 디스커버리 프로세스의 기본 아키텍처를 설명한다. 이 아키텍처의 기본 목표는 기존 디스커버리 표준을 사용하여 보호된 디스커버리 서비스에 대한 접근을 부트스트랩하되, 상세한 메타데이터는 권한이 있는 사용자에게만 배포하고 질의를 수행하는 사용자를 도청자로부터 가능한 한 보호하는 것이다. 이어서 특정 도입 및 탐색 메커니즘의 세부사항을 설명한다. 특히, 사물 또는 그 대리 엔터티가 동적으로 등록할 수 있는 WoT 사물 설명 컬렉션에 대한 검색 메커니즘을 제공하는 WoT 사물 설명 디렉터리(WoT TDD) 서비스를 위한 규범적 API를 상세히 정의한다. 그러나 WoT 디스커버리 메커니즘은 정규 웹 서비스에서 단일 TD를 배포하는 것도 지원하며, 이의 특별한 경우가 자기 설명이다. 마지막으로, 잠재적 위험과 완화 방안의 집합을 포함하여 보안 및 개인정보 보호 고려 사항을 논의한다.

2. 적합성

비규범으로 표시된 섹션뿐 아니라, 이 명세의 모든 작성 지침, 도표, 예제 및 참고는 비규범이다. 이 명세의 그 밖의 모든 내용은 규범이다.

이 문서의 핵심 단어 MAY, MUST, OPTIONAL, RECOMMENDED, SHOULD, 및 SHOULD NOT은 여기에 표시된 것처럼 모두 대문자로 나타나는 경우에만 BCP 14 [RFC2119] [RFC8174]에 설명된 대로 해석되어야 한다.

3. 용어

이 섹션은 비규범이다.

사물, 사물 설명 (TD), 사물 모델 (TM), 속성, 액션, 이벤트, 익명 TD, 디스커버러, 디스커버리, 탐색, 도입, 사물 설명 서버 (TD 서버), 사물 설명 디렉터리 (TDD), 부분 TD, 보강된 TD와 같은 기본 WoT 용어는 WoT 아키텍처 1.1 명세의 섹션 3 [wot-architecture11]에 정의되어 있다.

4. 아키텍처

이 섹션은 비규범이다.

그림 1은 WoT 디스커버리 프로세스의 개요를 보여준다. 디스커버리는 개방적이면서도 메타데이터에 대한 접근을 권한 있는 엔터티로 제한해야 하는 상충되는 요구사항을 해결하기 위해 2단계 아키텍처를 사용한다. 첫 번째 단계에서는 비교적 개방적인 "도입" 메커니즘 집합 중 하나 이상을 사용하여 후보 URL 집합을 생성할 수 있다. 이러한 URL 자체에는 메타데이터가 포함되지 않지만, 두 번째 단계에서 인증 후 실제로 사물 설명의 형태로 메타데이터를 제공할 수 있는 "탐색" 서비스를 참조하는 데 사용된다.

디스커버리 프로세스 개요
그림 1 디스커버리 아키텍처 개요. 공개 도입 메커니즘 집합은 URL 집합을 제공하며, 이 URL은 적절한 인증 이후에만 메타데이터(TD)를 제공하는 탐색 서비스를 가리킨다. 사물 링크와 사물 설명 디렉터리는 추가적인 유연성을 제공하지만, 이들로부터 추가 결과를 검색할지는 애플리케이션의 재량에 달려 있다.

의도는 도입 메커니즘이 디스커버리 프로세스의 나머지 부분을 위한 시작점을 제공하는 비교적 개방적인 "첫 접촉" 메커니즘이 되는 것이다. 이 문서에서는 로컬 및 비로컬 시나리오를 포함하여 서로 다른 사용 사례에 적합한 여러 도입 메커니즘의 세부사항을 명시하지만, 도입은 실제로 URL을 반환할 수 있는 어떤 메커니즘으로도 제공될 수 있다. 그러나 도입은 보안 또는 개인정보 보호 제어를 포함하지 않으므로 메타데이터를 직접 제공해서는 안 된다. 대신, 도입 메커니즘이 제공하는 URL은 "탐색" 서비스를 참조한다. 탐색 서비스는 실제로 메타데이터를 제공하지만, 적절한 인증과 접근 제어가 적용된 후에만 제공한다.

디스커버리 프로세스는 하나의 도입 메커니즘만 사용하더라도 도입 단계의 출력으로 URL의 집합을 생성할 수 있다(일부 도입 메커니즘 자체가 여러 URL을 반환할 수 있다). 탐색 단계 이후의 최종 출력도 사물 설명의 집합일 수 있다.

도입 단계에서 제공되는 각 URL은 항상 단일 사물 설명을 반환하는 탐색 서비스 엔드포인트를 가리킨다. 가장 단순한 경우, 이 URL은 IoT 엔드포인트 장치를 설명하는 사물의 사물 설명을 제공하는 웹 서버의 일반 리소스를 참조한다. 이의 특별한 경우로, 자기 설명 사물의 경우 도입 URL이 자체 사물 설명을 제공하는 사물이 제공하는 엔드포인트를 직접 가리킬 수 있다.

일반적으로 사물 설명은 다양한 방식으로 제공될 수 있으며, 특히 자기 설명 방식이 아닐 수 있다. 예를 들어,

그러한 사물의 사물 설명은 별도의 서비스에서 제공되어야 한다.

이 문서는 더 큰 유연성을 허용하는 두 가지 특별한 경우를 명시한다:

디스커버리 프로세스가 사물 설명 디렉터리의 내용을 검색하여 결과의 일부로 반환하는 것은 필수 사항이 아니다. 일반적으로 이는 엄청난 결과 집합을 초래할 수 있기 때문이다. 대신 애플리케이션은 결과에서 사물 설명 디렉터리 TD를 찾아 이들로부터 TD를 검색할지, 가능하다면 선택적으로 검색할지를 결정해야 한다. 마찬가지로 사물 링크를 자동으로 따라가는 것도 요구되지 않는다. 대신 애플리케이션은 이를 선택적으로 따라갈 수 있다.

5. 디스커버러 프로세스

이 섹션에서는 클라이언트의 관점에서 WoT 디스커버리 프로세스를 설명하고, 클라이언트가 WoT 디스커버리를 지원한다고 말하는 것이 무엇을 의미하는지 설명한다. WoT 디스커버리 프로세스의 클라이언트인 엔터티를 가리키기 위해 디스커버러라는 용어를 사용한다. 디스커버러는 완전한 컨슈머일 수도 있고 아닐 수도 있다. 그러나 디스커버러는 디렉터리 및 사물 링크를 위한 특수 TD를 읽고 정보를 추출하며, 그 안에 제공된 특정 어포던스와 링크를 사용해야 한다. 반대로 컨슈머는 디스커버리를 지원하지 않을 수 있지만, 이는 권장된다 [wot-architecture11].

WoT 디스커버리 프로세스는 단일 URI가 주어졌을 때 단일 TD를 가져올 수 있는 거의 모든 클라이언트가 WoT 디스커버리를 지원한다고 할 수 있도록 설계되어 있다. 물론 디스커버러는 더 강력한 디스커버리 메커니즘을 지원할 수 있지만, 이들 중 일부는 추가 요구사항이 있다. 일부 도입 메커니즘은 여러 URL을 반환할 수 있으며, 각 URL은 차례로 적어도 하나의 TD를 가져오는 데 사용될 수 있다. 따라서 TDD가 없더라도 여러 TD를 발견할 수 있다.

다음 단언은 디스커버러의 구체적인 책임을 설명한다:

위 프로세스는 디렉터리가 자신의 TD를 복제하지 않고 다른 디렉터리를 참조할 수 있게 하는 방법을 지원한다. 다른 디렉터리를 참조하려는 디렉터리는 다른 디렉터리 서비스의 TD에 대한 "describedby" 관계를 가진 사물 링크를 포함해야 한다. 그러면 위 프로세스는 사물 링크를 확장하여 디렉터리의 실제 TD를 얻고, 그런 다음 (선택적으로) 적절한 디렉터리 어포던스를 사용하여 연결된 디렉터리의 내용에 접근한다. 이러한 사물 링크는 디렉터리 자체가 아니라 디렉터리의 TD를 가리킨다는 점에 유의한다. 이들은 같은 위치에 호스팅될 수도 있고 그렇지 않을 수도 있다.

그러한 연결된 디렉터리의 내용을 재귀적으로 가져오는 것, 특히 특정 질의나 필터 없이 그렇게 하는 것은 쉽게 많은 양의 데이터를 다운로드하는 결과를 낳을 수 있다. 이러한 재귀 확장은 인벤토리, 감사 또는 색인 작성처럼 이를 요구하는 사용 사례로 제한되어야 한다.

디렉터리 서비스의 URL은 아래에 언급된 SPARQL 질의의 페더레이션 기능과 함께 사용할 수도 있으며, 대부분의 경우 이는 분산된 디렉터리 서비스 집합에서 특정 정보를 수집하는 더 효율적인 방법이 될 것이다. 그러나 SPARQL은 이러한 페더레이션을 위해 SPARQL 엔드포인트의 URL을 필요로 하며, 이는 SPARQL 질의를 지원하는 디렉터리의 TD에서 찾을 수 있다. 이는 디렉터리의 TD를 가리키는 URL과 동일하지 않다.

6. 도입 메커니즘

이 장은 사물 또는 사물 설명 디렉터리와의 초기 접촉을 위한 메커니즘을 설명한다. 다음 메커니즘 중 어느 것이든 사물 또는 사물 설명 디렉터리가 컨슈머에게 제공할 수 있다. 도입 메커니즘의 결과는 항상 적절한 인증 이후 상세한 메타데이터(TD)를 얻는 데 사용할 수 있는 탐색 서비스의 URL(주소)이다. 여러 도입 메커니즘을 사용하고 그 결과를 병합하는 것도 가능하다. 적어도 하나의 탐색 서비스 URL을 어떤 방식으로든 얻는 한, 특정 도입 메커니즘은 필수가 아니다.

6.1 직접

탐색 서비스의 URL을 얻기 위해, 단일 URL을 생성하는 어떤 메커니즘도 사용할 수 MAY 있다. 여기에는 블루투스 비콘, QR 코드, 사용자가 입력할 서면 URL이 포함된다. 그러한 모든 URL에 대한 요청은 7. 탐색 메커니즘에 규정된 대로 TD를 결과로 반환해야 MUST 한다. 자기 설명 사물의 경우, 이는 사물 자체의 TD일 수 있다. URL이 사물 설명 디렉터리를 참조하는 경우, 이는 사물 설명 디렉터리의 사물 설명이어야 MUST 한다.

6.2 잘 알려진 URI

사물 또는 사물 설명 디렉터리는 자신의 존재를 알리기 위해 잘 알려진 통일 자원 식별자 [RFC8615]를 사용할 수 MAY 있다. 사물 또는 사물 설명 디렉터리가 자신의 존재를 알리기 위해 잘 알려진 통일 자원 식별자 [RFC8615]를 사용하는 경우, 다음 경로에 자신의 사물 설명을 등록해야 MUST 한다: /.well-known/wot.

위의 잘 알려진 URI에 요청이 이루어지면, 서버는 7. 탐색 메커니즘에 규정된 대로 사물 설명을 반환해야 MUST 한다.

6.3 DNS 기반 서비스 디스커버리

사물 또는 사물 설명 디렉터리는 DNS 기반 서비스 디스커버리(DNS-SD)[RFC6763]를 사용할 수 MAY 있다. 이는 멀티캐스트 DNS(mDNS)[RFC6762]와 함께 동일한 로컬 네트워크에서도 사용할 수 있다.

다음 표는 존재를 광고하기 위한 서비스 이름과 프로토콜을 나열한다. 각각이 기존 탐색 메커니즘과 함께 유효한 사용을 가지므로 이는 규범적이다:

서비스 이름 사물 또는 TDD 프로토콜
_wot._tcp 사물 TCP 위의 HTTP, TLS/TCP 위의 HTTP, TCP 위의 CoAP, 또는 TLS/TCP 위의 CoAP
_directory._sub._wot._tcp TDD TCP 위의 HTTP, TLS/TCP 위의 HTTP, TCP 위의 CoAP, 또는 TLS/TCP 위의 CoAP
_wot._udp 사물 UDP 위의 CoAP 또는 DTLS/UDP 위의 CoAP

다음 추가 서비스 이름은 향후 사용을 위해 정의되었다. 그러나 현재 UDP 위의 CoAP를 사용하는 정의된 디렉터리 서비스가 없으므로 이 정의는 정보 제공용이다:

서비스 이름 사물 또는 TDD 프로토콜
_directory._sub._wot._udp TDD UDP 위의 CoAP 또는 DTLS/UDP 위의 CoAP

TCP 기반 서비스의 경우, 서비스 인스턴스 이름이 가리키는 TXT 레코드에 다음 정보가 포함되어야 MUST 한다:

td
사물의 사물 설명 또는 사물 설명 디렉터리의 사물 설명에 대한 절대 경로명.
type
사물 설명의 유형, 즉 Thing 또는 Directory. 생략되면, 유형은 Thing으로 간주된다.
scheme
URL의 스킴 부분. 표준으로 등록된 URI 해석 [RFC7595]에 따라 다음 값 중 하나를 지정할 수 있다: http (TCP 위의 HTTP), https (TLS/TCP 위의 HTTP), coap+tcp (TCP 위의 CoAP), 또는 coaps+tcp (TLS/TCP 위의 CoAP). 생략되면, 스킴은 http로 간주된다.

UDP 기반 서비스의 경우, 서비스 인스턴스 이름이 가리키는 TXT 레코드에 다음 정보가 포함되어야 MUST 한다:

td
사물의 사물 설명 또는 사물 설명 디렉터리의 사물 설명에 대한 절대 경로명.
type
사물 설명의 유형, 즉 Thing 또는 Directory. 생략되면, 유형은 Thing으로 간주된다.
scheme
URL의 스킴 부분. 표준으로 등록된 URI 해석 [RFC7595]에 따라 다음 값 중 하나를 지정할 수 있다: coap (UDP 위의 CoAP) 또는 coaps (DTLS/UDP 위의 CoAP). 생략되면 스킴은 coap로 간주된다.

그림 2 그림 3은 DNS-SD와 mDNS를 사용하여 사물 또는 사물 설명 디렉터리의 디스커버리를 지원하는 예시 시퀀스를 보여준다.

DNS-SD와 mDNS를 사용한 사물 디스커버리의 예시 시퀀스
그림 2 mDNS를 사용한 사물의 사물 설명 디스커버리
DNS-SD와 mDNS를 사용한 디렉터리 서비스 디스커버리의 예시 시퀀스
그림 3 mDNS를 사용한 사물 설명 디렉터리(TDD)의 사물 설명 디스커버리

사물 또는 사물 설명 디렉터리는 Constrained RESTful Environment(CoRE) 링크 형식 [RFC6690]을 사용하여 자신의 존재를 광고할 수 MAY 있다. 사물 또는 사물 설명 디렉터리는 CoRE 리소스 디렉터리 [RFC9176]를 사용하여 해당 사물 설명에 대한 링크를 등록할 수 MAY 있다.

사물의 사물 설명을 대상으로 하는 링크의 리소스 유형(rt)은 wot.thing이어야 MUST 한다. 사물 설명 디렉터리의 사물 설명을 대상으로 하는 링크의 리소스 유형은 wot.directory이어야 MUST 한다.

6.5 DID 문서

분산 식별자 (DID) [DID-CORE]를 사용하는 사물 또는 사물 설명 디렉터리는 TD의 식별자가 해석되는 DID 문서에 각각 WotThing 또는 WotDirectory 유형의 DID 서비스 엔드포인트를 포함하여 자신의 TD 위치를 광고할 수 MAY 있다.

WoT 디스커버리를 위한 서비스 엔드포인트를 정의하기 위해, 사물 또는 사물 설명 디렉터리의 DID를 해석하여 얻은 DID 문서는 자신의 @context [did-spec-registries]에 URL https://www.w3.org/2022/wot/discovery-did를 포함해야 MUST 한다.

사물 또는 사물 설명 디렉터리의 DID를 해석하여 얻은 DID 문서가 각각 WotThing 또는 WotDirectory 유형의 서비스 엔드포인트를 포함하는 경우, 이 서비스 엔드포인트는 각각 그 사물을 설명하는 TD (WotThing 서비스 이름을 사용할 때) 또는 해당 사물 설명 디렉터리를 설명하는 TD (WotDirectory 서비스 이름을 사용할 때)를 참조해야 MUST 한다 [did-spec-registries].

7. 탐색 메커니즘

이 섹션은 몇 가지 공통 배경 자료를 제공한 뒤 지원되는 탐색 메커니즘을 정의한다.

7.1 개요

탐색 메커니즘 고수준 클래스 다이어그램
그림 4 탐색 메커니즘의 고수준 클래스 다이어그램으로, 사물 설명 서버와 사물 설명 디렉터리가 TD를 제공하는 방식을 나타낸다. 자기 설명 사물은 사물 설명 서버이면서 동시에 사물인 특별한 경우이다. 사물 설명 디렉터리는 그 안에 포함된 각 사물 설명에 대해 사물 설명 서버로 동작한다.

그림 4TD 서버(자기 설명을 위한 것을 포함해 단일 TD를 제공함)와 사물 설명 디렉터리 서비스를 위한 고수준 정보 모델을 보여준다. 사물 설명 디렉터리TD를 포함할 수 있으며 동시에 사물이기도 하다. 이는 자체 TD를 가진다는 의미이다. 또한 디렉터리는 다른 사물의 개별 TD를 가져오기 위한 웹 서비스 엔드포인트를 호스팅하며, 이들 각각은 TD 서버로 사용될 수 있다. 일반적으로 사물은 자체 TD를 호스팅할 수 있으며, 이 경우 자기 설명 사물이다. 디렉터리에 대해 자기 설명은 필수가 아니지만, 사물 설명 디렉터리이면서 자기 설명 사물인 자기 설명 사물 설명 디렉터리는 가능하다.

두 가지 기본 탐색 메커니즘은 7.2 사물 설명 서버7.3 사물 설명 디렉터리에 설명되어 있다.

7.1.1 온톨로지

디스커버리 컨텍스트의 TD 온톨로지
그림 5 디스커버리 컨텍스트에서의 사물 설명 온톨로지.

그림 5는 사물 온톨로지의 확장으로 디스커버리 온톨로지를 보여준다.

이 온톨로지는 디렉터리에 저장된 TD와 연결된 메타데이터를 위한 클래스를 포함한다. 이 클래스는 RegistrationInformation이라고 하며, 7.3.1.1 등록 정보에서 디렉터리 명세의 일부로 설명된다.

디스커버리 온톨로지는 또한 다음 섹션에서 설명하는 두 개의 새로운 사물 설명 클래스를 정의하며, 이들은 특수한 탐색 메타데이터를 모델링하는 데 사용될 수 있다: ThingDirectoryThingLink.

7.1.1.1 ThingDirectory
사물 설명 디렉터리 인스턴스를 설명하는 TD는 디스커버리 컨텍스트의 ThingDirectory 유형 또는 URI https://www.w3.org/2022/wot/discovery#ThingDirectory를 사용해야 MUST 한다.

이 클래스의 TD는 디렉터리의 사물 모델에서 파생될 수 있다. 7.3.2.4 API 명세(사물 모델)를 참조하라.

7.1.2 보안 부트스트래핑

탐색 서비스의 목적은 TD를 제공하는 것이지만, 적절한 인증 이후에만, 그리고 권한이 있는 당사자에게만 제공하는 것이다. 그러나 일부 경우, 특히 임시 시나리오에서 디스커버러는 탐색 서비스를 통해 TD에 접근하는 데 어떤 보안 자격 증명이 필요한지 알지 못할 수 있다. 탐색 서비스에 처음 접근할 때 적절한 인증 자격 증명이 제공되지 않으면 디스커버러는 아직 TD에 접근할 수 없으므로, 어떤 종류의 인증 및 권한 부여 정보가 필요한지 알기 위해 TD에 포함된 보안 메타데이터에 의존할 수 없다. 디스커버러에게 사전 지식이 없다면, 적어도 TD 자체에 접근하기 위해 기존 보안 협상 지원에 의존하여 접근을 부트스트랩해야 한다.

우리는 보안 협상 프로세스가 이미 존재하는 HTTP 프로토콜에 대해 다음을 정의한다. 그러나 대부분의 HTTP 협상 프로세스는 사람이 루프 안에 있다고 가정하지만, 이는 WoT 디스커버리에도 적절하다. 이 문제는 일반적으로 사용자가 공개 WoT 서비스에 접근하려 하거나 새 장치의 통합을 수행하려 할 때 발생하기 때문이다. 이 경우 협상의 목적은 시스템에 접근하기 위해 어떤 자격 증명이 필요한지에 대한 안내를 제공하는 것이다.

탐색 서비스가 시스템 관리를 자동화하는 데 사용되는 경우에는 관련 탐색 서비스에 접근하는 데 필요한 자격 증명 (및 인증 메커니즘)을 미리 수립하는 것이 가장 좋으며, 보안 부트스트래핑은 필요하지 않다. 이러한 이유로 보안 부트스트래핑은 필수 기능이 아니며, 미리 수립된 보안 메커니즘과 함께 사용될 장치에서는 생략하거나 비활성화할 수 있다.

보안 부트스트래핑은 TD에 대한 첫 번째 접근에서만 필요할 수도 있다. 디스커버러가 특정 탐색 서비스에 접근하는 데 필요한 자격 증명과 인증 메커니즘을 결정하면, 이 정보를 보관하고 향후 접근에 사용하려고 시도할 수 있다. 그러나 사용되는 보안 체계에 따라 자격 증명 자체가 만료될 수 있으며 주기적으로 다시 수립해야 할 수도 있다는 점에 유의한다.

보안 부트스트래핑은 TD를 제공하는 모든 HTTP 엔드포인트에서 제공될 수 MAY 있다. 위에서 언급했듯이, 보안 메커니즘이 이전에 수립되어 있다면 보안 부트스트래핑을 비활성화하거나 생략하는 것이 허용된다. 예를 들어, 어떤 설치가 OAuth2 client 흐름을 사용하고 잠재적 클라이언트에게 사용할 인증 서버의 주소를 미리 제공하려는 경우, 보안 부트스트래핑을 비활성화할 수 있다. 대안은 다른(그리고 잠재적으로 더 약한) 인증 형식을 포함하는 것이기 때문이다.

HTTP 프로토콜에서 사용할 인증 및 권한 부여 메커니즘은 일반적으로 HTTP 서버가 필요한 정보를 지정하는 WWW-Authenticate 헤더와 함께 "401 (Unauthorized)" 응답 코드를 반환함으로써 협상될 수 있다. 접근 권한을 얻기 위해 클라이언트는 필요한 정보를 포함하여 또 다른 요청을 해야 한다. IANA에 등록된 여러 인증 체계가 있다. 그러나 이들 모두가 널리 사용되는 것은 아니며, 일부는 실험적이고, TD가 지원하는 체계와는 부분적으로만 겹친다. 또한 IANA 등록의 oauth 체계는 폐기된 OAuth1을 가리키므로 사용해서는 안 된다는 점에 유의한다. 관련 OAuth2 흐름인 code 흐름은 401 응답 대신 인증 서버로의 리디렉션으로 시작하며, 최종적으로 접근에 사용할 수 있는 자격 증명(WoT의 경우 bearer 토큰)을 생성한다.

이러한 고려 사항을 바탕으로, 다양한 장치와 브라우저에서 보안 부트스트래핑을 가능하게 하려면 다음 제약 조건을 준수해야 한다:

  • 탐색 서비스에서 보안 부트스트래핑이 활성화되어 있고 도입 메커니즘이 제공한 URL을 사용해 초기 접촉한 뒤 인증 정보가 제공되지 않았지만 제공되면 접근을 허용할 수 있는 경우, 탐색 서비스는 Basic, Bearer, Digest 또는 OAuth2 보안 체계 중 하나에 적절한 HTTP 응답 코드로 응답해야 MUST 한다. 탐색 서비스가 어떤 이유로 접근을 제공하고 싶지 않거나 보안 부트스트래핑이 비활성화되어 있는 경우, 요청을 무시하거나 404 또는 403 같은 다른 코드로 응답할 수 있음에 유의한다. 또한 인증이 필요하지 않다면, 시스템은 인증 정보가 제공된 것처럼 요청된 TD로 즉시 응답할 수 있다. 그러나 인증을 우회하는 것은 응답으로 제공되는 TD가 개인 식별 정보를 포함하지 않고 이를 추론하는 데도 사용될 수 없는 경우에만 적절하다. 9. 개인정보 보호 고려 사항을 참조하라.
  • Basic, Bearer 또는 Digest 중 하나의 IANA 등록 HTTP 인증 체계를 사용하여 탐색 서비스에서 보안 부트스트래핑이 활성화된 경우, (이러한 인증 체계에 대한 표준에 따라) TD를 제공하도록 의도된 API 엔드포인트에서 401 HTTP 응답은 WWW-Authenticate 헤더와 필요한 권한 부여를 설명하는 기타 헤더를 포함해야 한다. 요구사항의 세부사항은 위 인증 체계 각각에 대해 IANA 레지스트리를 참조해야 한다. 마찬가지로 OAuth2 명세에 따라, 보안 부트스트래핑 중 OAuth2 code 흐름이 사용되는 경우 인증 서버로 리디렉션하기 위해 "302 (Found)" 또는 "303 (See Other)" 응답 코드를 사용해야 하며, 접근 자격 증명은 최종적으로 bearer 토큰으로 표현된다. WoT 사물 설명 1.1에서 지원되는 다른 OAuth2 흐름인 client는 초기 접근이 최종 엔드포인트가 아니라 인증 서버로 이루어질 것을 기대하므로 보안 부트스트래핑을 통해 사용할 수 없다는 점에 유의한다. 이러한 요구사항은 보안 부트스트래핑을 지원해야 할 수도 있는 탐색 서비스의 엔드포인트, 즉 TD를 제공하는 엔드포인트에만 적용되며, 동일한 탐색 서비스가 제공할 수 있는 다른 엔드포인트에는 적용되지 않는다. 특히 이러한 요구사항은 도입 메커니즘이 참조할 수 있는 URL에만 적용되며, 예를 들어 이벤트 구독 엔드포인트에는 적용되지 않는다.

[wot-architecture11] 및 [wot-thing-description11]에는 TD 접근에 인증이 필요한 경우와 보안 전송의 사용에 관한 관련 보안 및 개인정보 보호 고려 사항이 있다. 9. 개인정보 보호 고려 사항도 참조하라. 요약하면, 보안 전송(예: TLS)은 공개 서비스에 필요하며, 사설 네트워크에서도 (인증 요구사항이 없더라도 질의의 기밀성을 보호하기 위해) 강력히 권장된다. 또한 인증과 권한 부여 없이 요청을 제공하는 것은 개인 식별 정보가 존재하지 않거나 추론될 수 없는 제한된 상황에서만 고려해야 한다.

7.2 사물 설명 서버

URL로 참조될 수 있고 적절한 인증과 접근 제어를 통해 TD를 반환할 수 있는 모든 웹 서비스는 탐색 메커니즘으로 사용될 수 있다. 이를 사물 설명 서버 또는 TD 서버라고 부른다. TD 서버는 사물일 필요가 없다. 특히 TD는 일반 웹 서버에 호스팅되고 그 URL로 참조될 수 있다.

TD 서버는 자기 설명을 지원하는 데 사용될 수 있다. 자기 설명의 경우, 사물은 자신의 TD를 호스팅하고 URL로 식별되는 웹 리소스를 통해 사용할 수 있게 한다. 그러나 이러한 웹 리소스는 TD 자체의 어포던스에는 포함되지 않는다. 이 웹 리소스는 6.2 잘 알려진 URI에 정의된 도입 메커니즘으로 사용되는 잘 알려진 URL과 같을 수도 있고 다를 수도 있다.

보안 전송의 사용은 [wot-architecture11] 및 [wot-thing-description11] 명세의 보안 고려 사항 및 개인정보 보호 고려 사항 섹션에 제시된 단언의 적용을 받는다. 이들 명세는 보안 전송이 권장되거나 필수인 시나리오와 상호 인증이 권장되는 시나리오를 정의한다.

다음 프로토콜을 사용하여 TD를 배포하는 TD 서버는 다음 제약 조건의 적용을 받는다:

HTTP

HTTP 기반 TD 서버가 TD를 제공하는 경우 그 리소스를 GET 메서드로 제공해야 MUST 한다. HTTP 기반 TD 서버가 TD를 제공하는 경우 성공 응답은 200 (OK) 상태와 본문 안의 TD를 가져야 MUST 한다. JSON 직렬화를 포함한 성공 응답은 Content-Type 헤더에 application/json 또는 application/td+json 중 하나를 포함해야 MUST 한다. 여기서 application/td+json은 더 구체적이고 application/json을 함의하므로 선호된다. 성공 응답 본문의 기본 직렬화 형식은 JSON-LD 1.1 [JSON-LD11] 구문을 사용하는 JSON이어야 MUST 한다. JSON-LD 구문은 의미 확장과 처리를 허용한다. HTTP 기반 TD 서버가 TD를 제공하는 경우, 서버 주도 콘텐츠 협상, 즉 요청의 Accept 및 Accept-Encoding 헤더를 존중하고 지원되는 TD 직렬화 및 이에 상응하는 Content-Type과 Content-Encoding 헤더로 응답함으로써 대체 표현을 제공할 수 MAY 있다. 또한 WoT 사물 설명 1.1 명세 [wot-thing-description11]에서 규범적으로 정의된 절차에 따라, HTTP 기반 TD 서버가 TD를 제공하는 경우 서버 주도 콘텐츠 협상, 즉 요청의 Accept-Language 헤더를 존중함으로써 다른 기본 언어를 사용한 수정된 TD 또는 오류 응답을 제공할 수 있다.

HTTP 기반 TD 서버가 TD를 제공하는 경우, 동일한 엔드포인트에 대한 GET 요청에서 반환되는 것과 동등한 헤더만 반환하여 HEAD 요청에 응답해야 MUST 한다. 이를 통해 클라이언트는 Content-Length 같은 HTTP 헤더를 미리 가져와 TD의 크기(바이트 단위)를 알고 효율적인 질의 전략을 결정할 수 있다.

제약된 환경에서는 단일 TD가 서버나 클라이언트가 처리하기에 너무 클 수 있다. 요청된 페이로드의 점진적 전송에 대한 프로토콜별 권장 사항은 10.1 점진적 전송을 참조하라.

오류 응답:

  • 401 (Unauthorized): 인증 없음.
  • 403 (Forbidden): 리소스에 대한 권한 부족.
CoAP

CoAP 기반 TD 서버가 TD를 제공하는 경우 그 리소스를 GET 메서드로 제공해야 MUST 한다. CoAP 기반 TD 서버가 TD를 제공하는 경우 성공 응답은 2.05 (Content) 상태를 가져야 MUST 하며, 값 50 (application/json) 또는 432 (application/td+json)의 Content-Format 옵션과 페이로드 안의 TD를 포함해야 한다. Content-Format 432는 더 구체적이고 Content-Format 50을 함의하므로 선호된다. 페이로드는 블록 단위 전송 [RFC7959]을 사용하여 여러 메시지 교환으로 분할될 수 있음에 유의한다. CoAP 기반 TD 서버가 TD를 제공하는 경우, 서버 주도 콘텐츠 협상, 즉 요청의 Accept 옵션을 존중하고 지원되는 TD 직렬화 및 이에 상응하는 Content-Format 옵션으로 응답함으로써 대체 표현을 제공할 수 MAY 있다.

CoAP 기반 TD 서버가 TD를 제공하는 경우, Size2 옵션을 포함하는 요청에 대해 다음 응답에 TD의 크기 추정치를 포함하여 응답하는 것이 좋다 SHOULD. 이는 블록 단위 전송을 사용하여 TD를 얻을 때 관련이 있으며, 전체 페이로드 크기가 클라이언트가 처리하기에 너무 클 경우 클라이언트가 검색을 중단할 수 있게 한다.

제약된 환경에서는 단일 TD가 서버나 클라이언트가 처리하기에 너무 클 수 있다. 요청된 페이로드의 점진적 전송에 대한 프로토콜별 권장 사항은 10.1 점진적 전송을 참조하라.

오류 응답:

  • 4.01 (Unauthorized): 인증 없음.
  • 4.03 (Forbidden): 리소스에 대한 권한 부족.

7.3 사물 설명 디렉터리

사물 설명 디렉터리(줄여서 TDD 또는 디렉터리)는 다른 사물을 설명하는 TD 집합을 관리하는 서비스를 제공하는 사물이다.

7.3.1 정보 모델

그림 4에 표시된 것처럼, 사물 설명 디렉터리는 0개 이상의 TD를 포함할 수 있다. 각 TD에 대해 디렉터리는 장부 관리 및 검색 목적을 위한 추가 메타데이터를 유지한다. 이는 7.3.1.1 등록 정보7.3.1.3 익명 TD 식별자에서 설명된다. 디렉터리와의 상호작용 일부로 그러한 추가 메타데이터를 포함하는 TD보강된 TD라고 한다.

7.3.1.1 등록 정보

디스커버리 컨텍스트에서의 TD 온톨로지는 그림 5에서 소개되었다. RegistrationInformation 클래스는 디렉터리에 저장된 TD와 연결된다. 다음 표는 디스커버리 컨텍스트를 포함하거나 참조하는 TD 내에서 사용할 등록 정보 속성을 나열한다. 등록 정보를 포함하는 것은 보강된 TD뿐이라는 점에 유의한다. 보강된 TD는 자신의 @context에 URI https://www.w3.org/2022/wot/discovery를 포함해야 MUST 한다. 이 표에서 클라이언트는 TD의 생산자 또는 소비자를 가리키며, 서버는 사물 설명 디렉터리를 가리킨다.

절대 시간이 dateTime을 사용하여 표현될 때마다, 이는 [RFC3339]에 명시된 date-time으로 해석되어야 MUST 한다. 구체적으로, 시간대 오프셋은 선택 사항이 아니다.

편집자 주: dateTime 대 date-time

온톨로지를 업데이트하여 date-time과 RFC3339만 사용하고 dateTime과 date-time의 이상한 조합은 사용하지 않도록 해야 하지만, 이는 TD 명세에서도 해결되어야 한다. 그러나 이 추가 제한을 가진 새로운 SHACL shape가 필요할 것이다.

어휘 용어 설명 클라이언트 할당 서버 할당 유형
created TD 인스턴스가 디렉터리 내부에서 생성된 절대 시간을 제공한다.

이는 디렉터리가 설정하고 소비자에게 반환할 수 MAY 있다.

읽기 전용 선택 사항 dateTime
modified TD 인스턴스가 디렉터리 내부에서 마지막으로 수정된 절대 시간을 제공한다.

이는 디렉터리가 설정하고 소비자에게 반환할 수 MAY 있다.

읽기 전용 선택 사항 dateTime
expires TD 인스턴스 등록이 만료되는 절대 시간을 제공한다.

생산자는 등록 중 절대 만료 시간을 나타내기 위해 이를 설정할 수 MAY 있다.

만료 가능한 TD를 지원하는 서버의 경우: ttl(상대 만료)이 존재하면, 서버는 expires에 대한 클라이언트 할당을 무시해야 MUST 하며 대신 이를 내부적으로 계산하고 설정해야 한다.

선택 사항 선택 사항 dateTime
ttl Time-to-live: 등록 시간부터 TD 인스턴스 등록이 만료될 때까지의 상대 시간(초 단위).

생산자는 등록 중 상대 만료 시간을 나타내기 위해 이를 설정할 수 MAY 있다.

만료 가능한 TD를 지원하는 서버의 경우: 서버는 expires(절대 만료) 값을 계산하기 위해 ttl을 사용해야 MUST 한다.

선택 사항 읽기 전용 number
retrieved TD가 서버에서 검색된 절대 시간.

이는 다른 절대 타임스탬프를 처리하려 하지만 내부 시계나 현재 시간을 획득할 다른 수단이 없는 클라이언트에게 유용하다.

읽기 전용 선택 사항 dateTime
7.3.1.2 등록 만료
7.3.1.1 등록 정보 섹션은 등록된 TD의 만료 시간을 지정하고 발견하기 위한 몇 가지 속성을 소개한다.

생산자는 만료 시간을 설정하여 디렉터리와 다른 소비자에게 TD 등록의 유효성을 알릴 수 있다. 만료는 동적 TD의 만료를 소비자에게 알리는 데에도 유용한 지표이다. 예를 들어 지리적 위치나 속성 같은 메타데이터 변경 사항이 제한된 기간 동안 유효할 것으로 예상되는 경우가 이에 해당한다. 소비자는 만료 시간에 의존하여 검색한 TD가 얼마나 오래 유효할지, 그리고 언제 더 최신의 TD를 요청해야 하는지를 알 수 있다. 만료된 TD를 검색한 소비자는 이를 비활성 클라이언트의 메타데이터로 간주할 수 있다.

서버의 경우, 만료 시간은 오래되었거나 우발적인 등록의 자동 제거를 구현하는 데 유용하다. 서버는 만료 시간이 지난 TD를 주기적으로 제거하는 것이 좋다 SHOULD. 만료 시간에 대해 전역적인 의무사항이나 상한을 규정하는 것은 애플리케이션별 사항이며 이 명세의 범위를 벗어난다. 서버는 만료 시간에 대한 구성 가능한 상한을 의무화하거나 설정할 수 있으며, 준수하지 않는 요청을 거부할 수 있다. 서버에 의한 제거는 자신의 TD를 명시적으로 등록 해제할 수 없는 클라이언트(예: IoT 장치)와 상호작용할 때 특히 유익하다. 이는 프로토콜별 제한, 장애, 파손 또는 비정상적인 폐기 때문일 수 있다. 그러한 클라이언트는 합리적으로 짧은 만료 시간을 설정하고 정상 동작 중에 이를 주기적으로 연장해야 한다. 만료는 TD에 변경을 가하지 않는 업데이트를 포함하여, 등록을 전체적으로 또는 부분적으로 업데이트함으로써 연장할 수 있다. 7.3.2.1.3 업데이트를 참조하라. 클라이언트가 동작을 중단하면, 제거 기능을 가진 디렉터리가 그 등록을 자동으로 제거한다.

7.3.1.3 익명 TD 식별자
디렉터리는 그러한 TD를 디렉터리에서 관리하고 검색할 수 있도록 익명 TD에 로컬 식별자를 할당한다. 서버가 익명 TD를 노출하는 상황(예: 검색, 목록화, 탐색)에서는, 로컬 참조를 허용하기 위해 TD의 id로 로컬 식별자를 추가해야 MUST 한다. 로컬 식별자는 URN [RFC4122]으로 표현된 UUID 버전 4인 것이 좋다 SHOULD. UUID 버전 4는 호스트나 리소스에 대한 의도하지 않은 정보를 포함하지 않는 난수 또는 의사 난수이다.

7.3.2 디렉터리 서비스 API

디렉터리 서비스는 시스템 사용자 데이터에 대한 접근을 제공하므로 적절한 보안 및 개인정보 보호를 제공해야 한다. WoT 디렉터리 서비스 API 구현에서 진정성과 기밀성을 위한 보안 전송 프로토콜 및 접근 제어의 사용은 [wot-architecture11]에 제시된 보안 고려 사항 및 개인정보 보호 고려 사항의 적용을 받는다.

HTTP API 응답은 이 섹션에서 성공 및 오류 응답에 대해 설명한 적절한 상태 코드를 사용해야 한다. HTTP API는 HTTP 클라이언트 오류(4xx) 및 서버 오류(5xx) 응답에서 오류 세부 정보를 전달하기 위해 Problem Details [RFC7807] 형식을 사용해야 MUST 한다. 이를 통해 기계와 사람이 모두 고수준 오류 클래스와 세부 정보를 알 수 있다. Problem Details를 사용하여 설명되는 모든 HTTP API 오류 응답은 UTF-8로 인코딩되어야 MUST 한다. HTTP API 오류 응답은 HTTP 요청에서 Accept-Language 헤더 필드가 설정된 경우, 사전 협상을 사용하여 다른 언어로 세부 정보를 보고할 수 MAY 있다 [RFC7231].

API는 [RFC7231]의 섹션 6에 정의된 HTTP 상태 코드를 설정한다. 사용되는 오류 코드 목록에는 다음이 포함된다(이에 국한되지는 않음):

  • 400 (Bad Request): 본문, 질의 또는 헤더의 잘못된 클라이언트 입력. 이는 적절한 응답 메시지를 동반한다.
  • 401 (Unauthorized): 요청에 유효한 인증 자격 증명이 없다. 7.1.2 보안 부트스트래핑에서 언급했듯이, 이는 TD에 대한 안전한 접근을 부트스트랩하는 데 필요한 인증 협상의 첫 단계이다. 필요한 자격 증명에 대한 정보는 WWW-Authenticate 헤더에 포함된다.
  • 403 (Forbidden): 리소스에 접근할 권한이 부족함.
  • 404 (Not Found): TD 또는 엔드포인트가 존재하지 않음. 이는 적절한 응답 메시지를 동반한다.

GET 메서드에 응답하는 각 HTTP 엔드포인트에 대해, 서버는 HEAD 요청을 수락하고 헤더만 반환해야 MUST 한다. 이를 통해 클라이언트는 본문을 수신하지 않고 Content-Length 같은 헤더를 검색하고 정보를 질의하기 위한 적절한 전략을 결정할 수 있다. 예를 들어 제약된 클라이언트는 객체의 필요한 부분만 요청하거나 (적절한 검색 질의를 사용하여) 항목 목록을 작은 하위 집합으로 검색할 수 있다.

제약된 환경에서는 단일 TD가 서버나 클라이언트가 처리하기에 너무 클 수 있다. 이는 읽기(즉, 하나 이상의 TD 또는 TD 조각 검색) 작업과 쓰기(즉, TD 또는 부분 TD 제출) 작업 모두에 영향을 준다. 페이로드의 점진적 전송에 대한 프로토콜별 권장 사항은 10.1 점진적 전송을 참조하라.

URL을 통한 안전한 데이터 전송을 보장하기 위해, 클라이언트와 서버 모두 URL의 나머지 부분에서 구분자와 충돌하는 문자를 퍼센트 인코딩/디코딩할 것으로 기대된다. 이러한 문자는 [RFC1738]의 섹션 2.2에서 안전하지 않은 문자로 정의된다. 안전하지 않은 문자가 URL에 나타나면, 예를 들어 경로에 포함된 리소스 ID가 그 자체로 URL이거나 검색 질의 문자열에 포함되는 경우, 예상치 못한 동작이 발생할 수 있다.

디렉터리 API에는 필수, 권장 및 선택 기능이 포함된다. 디렉터리가 지원하지 않는 권장 또는 선택 기능 때문에 요청에 응답할 수 없는 경우, 적절한 HTTP 오류를 반환하여 해당 기능이 없음을 클라이언트에게 알려야 SHOULD 한다. 다음 예제는 구현을 위한 지침으로 사용할 수 있다:

  • 누락된 기능이 기존 API의 기능을 사용자 지정하는 것이라면 400 (Bad Request) 또는 501 (Not Implemented)를 사용한다.
  • API 엔드포인트가 제공되지 않는 경우(예: /search/sparql 엔드포인트), 404 (Not Found)를 사용한다.
  • 기존 API 엔드포인트에서 메서드가 지원되지 않는 경우 (예: /things 엔드포인트의 PATCH), 405 (Method Not Allowed)를 사용한다.

TD에 이미 제공된 번역을 사용하여 TD의 기본 언어를 수정하는 절차는 WoT 사물 설명 1.1 명세 [wot-thing-description11]에서 규범적으로 설명된다. 이 절차를 사용하면, 디렉터리 서버는 서버 주도 콘텐츠 협상, 즉 요청의 Accept-Language 헤더를 존중함으로써 다른 기본 언어를 사용한 수정된 TD 또는 자신의 TD를 제공할 수 있다.

7.3.2.1 사물 API

사물 API는 /things 엔드포인트에서 제공되는 RESTful HTTP API로, TD를 생성, 조회, 업데이트, 삭제 및 목록화(CRUDL)하기 위한 인터페이스를 제공한다. 이 API의 설계는 [RFC7231] 및 [REST-IOT]에 따른다.

HTTP API는 다음 일반 규칙을 따른다:

  • API는 TD를 목록화하는 인터페이스를 제공해야 MUST 한다. 검색 API는 이 목록에서 필터링과 선택을 허용한다. 7.3.2.3 검색 API를 참조하라.
  • API는 개별 TD를 생성, 읽기, 업데이트 및 삭제(CRUD)하는 인터페이스를 제공할 수 MAY 있다.
  • HTTP를 통한 읽기와 쓰기를 모두 제공하는 디렉터리는 완전한 HTTP 디렉터리로 간주된다. 완전한 HTTP 디렉터리는 모든 CRUDL (생성, 읽기, 업데이트, 삭제 및 목록화) 인터페이스를 구현하는 것이 좋다 SHOULD. 디렉터리가 정적인 TD 컬렉션을 제공하는 경우, 읽기와 목록화 인터페이스만 구현하는 것도 실용적이다. 이는 HTTP를 통해 검색 작업만 노출하고, 다른 작업은 대역 외 메커니즘을 통해 수행하려는 디렉터리에도 유용하다. 읽기 전용 접근을 노출하려면, 디렉터리는 생성, 업데이트 및 삭제 인터페이스에 대한 접근 제어를 강제해야 MUST 한다.
  • 모든 요청 및 성공 응답 본문의 기본 직렬화 형식은 확장과 의미 처리를 지원하기 위해 JSON-LD 1.1 [JSON-LD11] 구문을 사용하는 JSON이어야 MUST 한다.
  • 디렉터리는 요청이 나타내는 Content-Type 또는 Content-Encoding 헤더에 기반한 대체 표현을 수락할 수 MAY 있다. 이는 디렉터리에 원시 JSON 이외의 표현을 입력으로 제공해야 하는 애플리케이션에 유용하다.
  • 디렉터리는 서버 주도 콘텐츠 협상, 즉 요청의 Accept 및 Accept-Encoding 헤더를 존중하고 지원되는 TD 표현 및 이에 상응하는 Content-Type과 Content-Encoding 헤더로 응답함으로써 대체 표현을 제공할 수 MAY 있다. 이는 Gzip 압축 JSON과 같이 원시 JSON 이외의 표현을 디렉터리에서 검색해야 하는 애플리케이션에 유용하다.

CRUDL 작업은 다음 섹션에서 설명된다:

7.3.2.1.1 생성

생성은 디렉터리 내부에 새로운 TD를 등록하는 것을 의미한다.

TD 객체는 7.3.2.1.6 유효성 검사에 따라 검증된다. TD는 그것이 설명하는 사물에 의해 생성될 수도 있고 그렇지 않을 수도 있음에 유의한다. 특히 브라운필드 장치의 경우, 해당 장치를 대신하여 사물에 대한 TD를 생성하고 등록하는 별도의 디스커버러 프로세스 또는 서비스가 필요할 수 있다.

id 속성으로 식별되는 TD는 식별자가 없는 TD(익명 TD)와 다르게 처리되어야 MUST 한다. 생성 작업은 아래에서 자세히 설명된다:

  • id를 가진 TD는 HTTP PUT 요청의 본문으로 /things/{id} 엔드포인트에 제출되어야 MUST 하며, 여기서 id는 TD 객체 내부에 존재하는 고유 TD 식별자이다. 익명 TD는 다르게 처리된다. 아래를 참조하라. 요청은 TD의 JSON 직렬화를 위해 application/td+json Content-Type 헤더를 포함하는 것이 좋다 SHOULD. TD 객체는 7.3.2.1.6 유효성 검사에 따라 검증된다. 성공적으로 처리되면, 서버는 201 (Created) 상태로 응답해야 MUST 한다.

    참고: 대상 위치가 기존 TD에 해당하는 경우, 요청은 대신 업데이트 작업으로 진행되고 적절한 상태 코드로 응답해야 한다(업데이트 섹션 참조).

    식별자를 가진 TD의 생성 작업은 7.3.2.4 API 명세(사물 모델)createThing 액션으로 지정된다.

  • 익명 TD는 HTTP POST 요청의 본문으로 /things 엔드포인트에 제출되어야 MUST 한다. 요청은 TD의 JSON 직렬화를 위해 application/td+json Content-Type 헤더를 포함하는 것이 좋다 SHOULD. TD 객체는 7.3.2.1.6 유효성 검사에 따라 검증된다. 디렉터리는 디렉터리에서 로컬 관리와 검색을 가능하게 하기 위해 모든 익명 TD에 로컬 식별자를 할당해야 MUST 한다. 시스템 생성 ID의 체계는 7.3.1.3 익명 TD 식별자에 설명되어 있다. 성공적으로 처리되면, 서버는 201 (Created) 상태와 생성된 TD 리소스의 시스템 생성 URI를 포함하는 Location 헤더로 응답해야 MUST 한다. 시스템 생성 URI에는 TD의 시스템 생성 식별자가 포함되며, 이후 디렉터리에서 TD를 질의하는 데 사용할 수 있다.

    익명 TD의 생성 작업은 7.3.2.4 API 명세(사물 모델)createAnonymousThing 액션으로 지정된다.

만료 가능한 TD를 지원하는 서버는 7.3.1.2 등록 만료에 설명된 대로 이러한 기능을 실현한다. 특히 생성 중에 ttl(상대 만료)이 주어지면, 그러한 서버는 expires 값을 계산하고 저장한다.

7.3.2.1.2 조회

기존 TD의 조회는 HTTP GET 요청을 사용하여 /things/{id} 엔드포인트에서 수행되어야 MUST 하며, 여기서 id는 고유 TD 식별자이다. 성공 응답은 200 (OK) 상태와 본문의 요청된 TD를 가져야 MUST 한다. JSON 직렬화를 포함한 성공 응답은 Content-Type 헤더에 application/json 또는 application/td+json 중 하나를 포함해야 MUST 한다. 여기서 application/td+json은 더 구체적이고 application/json을 함의하므로 선호된다. 기본 직렬화는 JSON-LD 구문을 사용하는 JSON이며, 대체 직렬화는 협상할 수 있음에 유의한다. 7.3.2.1 사물 API를 참조하라.

조회 작업은 7.3.2.4 API 명세(사물 모델)retrieveThing 액션으로 지정된다.

다음은 조회된 TD의 예이다:

이는 디렉터리 내 TD의 생성 및 수정 시간과 같은 등록 정보를 포함하는 보강된 TD이다.

아래 예제는 익명 TD보강된 TD 형식으로 조회되었고 로컬 식별자 urn:uuid:48951ff3-4019-4e67-b217-dbbf011873dc를 가진 경우를 보여준다.

다음은 3600초(1시간)의 상대 만료 시간으로 등록된 조회 TD의 예이다. 서버는 수정 시간으로부터 1시간 뒤를 절대 만료 시간으로 계산했다.

가독성을 위해 이 예제의 시간 값은 정확한 숫자로 설정되어 있다. 실제 설정에서는 시간 값에 소수부가 포함될 수 있다.

7.3.2.1.3 업데이트

업데이트 작업은 기존 TD를 대체하거나 부분적으로 수정하는 것이다.

업데이트 작업은 아래에 설명되어 있다:

  • 수정된 TD는 기존 TD의 식별자인 id가 있는 /things/{id} 엔드포인트에 HTTP PUT 요청으로 제출될 때 기존 TD를 대체해야 MUST 한다. 요청은 TD의 JSON 직렬화를 위해 application/td+json Content-Type 헤더를 포함하는 것이 좋다 SHOULD. TD 객체는 7.3.2.1.6 유효성 검사에 따라 검증된다. 성공 시 서버는 204 (No Content) 상태로 응답해야 MUST 한다.

    이 작업은 7.3.2.4 API 명세(사물 모델)updateThing 속성으로 지정된다.

    만료 가능한 TD를 지원하는 서버는 7.3.1.2 등록 만료에 설명된 대로 이러한 기능을 실현한다. 업데이트 작업 중 ttl (상대 만료)이 설정된 경우, 서버는 expires(절대 만료) 값을 계산하고 설정한다.

    참고: 대상 위치가 기존 TD에 해당하지 않는 경우, 요청은 대신 생성 작업으로 진행되고 적절한 상태 코드로 응답해야 한다(생성 섹션 참조). 즉, HTTP PUT 요청은 생성 또는 업데이트 작업으로 동작한다.

  • 수정된 부분이 기존 TD의 식별자인 id가 있는 /things/{id} 엔드포인트에 HTTP PATCH 요청으로 제출될 때 기존 TD는 부분적으로 수정되어야 MUST 한다. 부분 업데이트는 [RFC7396]에 설명된 JSON merge patch 형식을 사용하여 처리되어야 MUST 한다. 요청은 merge patch 문서의 JSON 직렬화를 위해 application/merge-patch+json Content-Type 헤더를 포함해야 MUST 한다. 입력은 부분 TD 형식이어야 MUST 하며 원래 TD 구조를 준수해야 한다. 입력에 원래 TD에 나타나는 멤버가 포함된 경우, 해당 값은 대체된다. 멤버가 원래 TD에 나타나지 않으면 그 멤버가 추가된다. 멤버가 null로 설정되어 있고 원래 TD에 나타나는 경우, 해당 멤버는 제거된다. 객체 값을 가진 멤버는 재귀적으로 처리된다. 수정을 적용한 후 TD 객체는 7.3.2.1.6 유효성 검사에 따라 검증된다. 성공 시 서버는 204 (No Content) 상태로 응답해야 MUST 한다.

    이 작업은 7.3.2.4 API 명세(사물 모델)partiallyUpdateThing 속성으로 지정된다.

    만료 가능한 TD를 지원하는 서버는 7.3.1.2 등록 만료에 설명된 대로 이러한 기능을 실현한다. 부분 업데이트 작업 중 결과 TDttl (상대 만료)이 있는 경우, 서버는 새 expires(절대 만료) 값을 계산하고 설정한다.

    패치 작업은 ttl(상대 만료) 값을 사용하는 등록의 만료를 효율적으로 연장하는 데 특히 유용하다. 이는 일반적으로 빈 merge patch 문서, 즉 빈 JSON 객체를 제출함으로써 수행된다. 이는 사실상 아무것도 업데이트하지 않지만 expires(절대 만료) 값의 재계산을 트리거하는 부분 업데이트 작업을 수행하는 것으로 해석된다. 이 만료 기능은 서버가 7.3.1.2 등록 만료에 정의된 대로 이를 지원하는 경우에만 동작한다.

    다음 예제는 TD의 base 및 등록 expires 필드만 업데이트하기 위한 merge patch 문서이다:

7.3.2.1.4 삭제

삭제 작업은 기존 TD의 식별자인 id가 있는 /things/{id}에서 HTTP DELETE 요청을 사용하여 수행되어야 MUST 한다. 성공 응답은 204 (No Content) 상태를 가져야 MUST 한다. 조회 작업은 7.3.2.4 API 명세(사물 모델)deleteThing 속성으로 지정된다.

7.3.2.1.5 목록화

목록화 엔드포인트는 디렉터리에서 전체 TD 객체 컬렉션을 질의하는 여러 방법을 제공한다.

많은 시나리오에서는 전체 TD 객체 대신 일부를 검색하는 것이 선호된다. 필요한 요소가 일부뿐이기 때문이며 (예: 모든 TD에 대한 속성의 idhref), 네트워크 자원을 절약하기 위해서이기도 하다. 검색 API는 TD 객체의 일부를 질의할 수 있게 한다. 7.3.2.3 검색 API를 참조하라.

디렉터리는 /things 엔드포인트에서 HTTP GET 요청을 사용하여 기존 TD를 검색할 수 있게 해야 MUST 한다. 성공 응답은 200 (OK) 상태와 본문의 TD 배열을 가져야 MUST 한다. JSON 직렬화를 포함한 성공 응답은 Content-Type 헤더에 application/json 또는 application/ld+json 중 하나를 포함해야 MUST 한다. 여기서 application/ld+json은 더 구체적이고 application/json을 함의하므로 선호된다. 기본 직렬화는 JSON-LD 구문을 사용하는 JSON이며, 대체 직렬화는 협상할 수 있음에 유의한다. 7.3.2.1 사물 API를 참조하라.

클라이언트가 TD의 작은 하위 집합으로 컬렉션을 검색해야 하는 시나리오가 있을 수 있다. 검색 API (7.3.2.3 검색 API)는 특정 범위를 질의하는 기능을 제공하지만, 이것이 최적이거나 개발자 친화적이지는 않을 수 있다. 서버는 컬렉션을 작은 하위 집합으로 반환하기 위해 페이지네이션을 지원할 수 MAY 있다. 페이지네이션은 다음 규칙을 기반으로 해야 한다:

  • limit 질의 매개변수가 양의 정수로 설정된 경우, 서버는 요청된 수 이하의 TD로 이루어진 하위 집합으로 응답할 수 MAY 있다.
  • 반환된 컬렉션의 하위 집합 뒤에 더 많은 TD가 있는 경우, 응답은 다음 하위 집합의 URL을 포함한 next Link 헤더 [RFC8288]를 포함해야 MUST 한다. next 링크는 동일한 데이터 집합과 그 순서를 생성하는 데 필요한 모든 인수를 포함해야 MUST 하며, 특히 초기 요청에서 주어진 동일한 limit 인수와 다음 하위 집합의 시작에 고정된 0 기반 offset 인수를 포함해야 한다. 링크는 절대 URL이거나 디렉터리 API의 기본 URL에 상대적이어야 MUST 한다. 또한 정렬 또는 세션 관리에 필요한 추가 인수를 포함할 수 있다.
  • 모든 페이지 응답은 컬렉션을 가리키고 컬렉션의 현재 상태를 나타내는 etag 매개변수를 포함한 canonical Link 헤더 [RFC8288]를 포함해야 MUST 한다. 링크는 절대 URL이거나 디렉터리 API의 기본 URL에 상대적일 수 있다. etag 값은 TD 컬렉션이 TD의 순서에 영향을 주는 방식으로 변경될 때마다 설정되는 개정 번호, 타임스탬프 또는 UUID 버전 4일 수 있다. 클라이언트는 컬렉션의 페이지별 검색 중 컬렉션이 일관된 상태를 유지하는지 알기 위해 etag 값에 의존할 수 있다. 예를 들어 TD의 생성 또는 삭제, 또는 정렬에 사용되는 TD 필드의 업데이트는 계산된 페이징 창을 이동시킬 수 있다.
  • 컬렉션은 TD의 고유 식별자를 기준으로 유니코드 코드 포인트 순서에 따라 오름차순으로 정렬되어야 MUST 한다.

위 명세는 JSON-LD 배열의 선택적 페이지네이션을 허용하기 위해 Linked Data Paging [LDP-Paging]의 하위 집합을 따른다. Linked Data Paging의 추가 부분은 예를 들어 클라이언트의 질의 선호를 존중하거나 의미 주석 및 대체 탐색 링크를 위한 다른 링크 관계를 추가하기 위해 구현될 수 있다.

다음 예제는 TD의 페이지별 검색 절차를 보여준다:

응답 본문의 TD 배열 대신, 서버는 실제 데이터 외에도 페이지네이션 정보와 같은 서버 측 정보를 포함할 수 있는 더 자세한 페이로드를 보낼 수 MAY 있다.

대체 페이지네이션 형식은 Hydra Advanced Concepts, 더 구체적으로 Partial Collection View에서 영감을 받은 것이다. 우리의 목적에 맞게 조정하고 TD 배열을 수용하기 위해 members 필드를 사용하면, 목록화 엔드포인트의 경우 다음과 같다:

서버에 어떤 형식을 보낼지 알리기 위해, 추가 질의 매개변수 ?format=array|collection을 요청에 추가할 수 있다. ?format=array는 기본 매개변수이며, 명시적으로 제공할 필요가 없고, 서버 응답으로 순수 TD 배열을 산출한다. ?format=collection예제 9에 설명된 형식의 서버 응답을 산출해야 한다.

목록화 작업은 7.3.2.4 API 명세(사물 모델)things 속성으로 지정된다.

7.3.2.1.6 유효성 검사

저장 전에 TD 객체의 구문적 유효성 검사를 수행하는 것은 흔한 잘못된 제출을 방지하기 위해 권장된다 RECOMMENDED. 서버는 TD를 검증하기 위해 [wot-thing-description11]에 정의된 최소 유효성 검사를 적어도 사용하고, 필요에 따라 WoT 사물 설명(1.0) JSON Schema 또는 WoT 사물 설명 1.1 JSON SchemaA. WoT 디스커버리 TD 확장을 위한 JSON Schema에 정의된 JSON 스키마를 보강된 TD에 대해 @context 값에 적절하게 사용해야 SHOULD 한다.

다양한 사용 사례를 지원하기 위해 추가적인 형태의 유효성 검사를 더할 수 있다. 예를 들어, 어떤 사용 사례는 version 값이 사전 정의된 규칙에 따라 초기화되고 업데이트되는지 보장하기 위해 입력 TD의 상태 기반 유효성 검사를 요구할 수 있다.

서버가 TD 객체의 유효성 검사에 실패한 경우, 오류를 식별하고 해결하는 데 필요한 세부 정보를 클라이언트에게 알려야 MUST 한다. 유효성 검사 오류는 validationErrors라는 확장 필드를 가진 Problem Details [RFC7807]로 설명되어야 MUST 하며, 이 필드는 fielddescription 필드를 가진 객체 배열로 설정된다. 이는 오류를 기계가 읽을 수 있는 방식으로 표현하기 위해 필요하다. Problem Details를 사용하여 설명되는 모든 유효성 검사 오류 응답은 UTF-8로 인코딩되어야 MUST 한다. 오류 보고에 대해 일반적으로 이미 언급했듯이, HTTP 요청에서 Accept-Language 헤더 필드가 설정된 경우 유효성 검사 오류 응답은 사전 협상을 사용하여 다른 언어로 세부 정보를 보고할 수 있다 [RFC7231].

예제 10은 두 개의 유효성 검사 오류를 포함한 오류 응답의 예이다.

7.3.2.2 이벤트 API

알림 API는 디렉터리 내에서 유지되는 TD의 변경 사항을 클라이언트에게 알리기 위한 것이다. 디렉터리는 알림 API를 구현할 수 MAY 있다.

알림 API는 /events 엔드포인트에서 클라이언트에게 이벤트를 제공하기 위해 Server-Sent Events(SSE) [HTML] 명세를 따라야 MUST 한다. 특히 서버는 성공 요청에 대해 200 (OK) 상태와 text/event-stream Content Type으로 응답한다. 다시 연결하는 클라이언트는 마지막 이벤트 ID를 Last-Event-ID 헤더 값으로 제공하여 마지막 이벤트부터 계속할 수 있다. 서버는 각 이벤트의 id 필드로 이벤트 ID를 제공하고, 다시 연결하는 클라이언트에게 누락된 모든 이벤트를 전달하는 것이 좋다 SHOULD.

이 섹션의 나머지 부분은 SSE 프로토콜 위에서의 구현 세부사항을 설명한다. MQTT와 같은 다른 프로토콜을 사용해 알림 기능을 실현하는 것도 가능하며, 이 명세의 향후 버전에서 공식화될 수 있다.

이벤트 유형
서버는 디렉터리 내 사물 설명의 수명 주기에 귀속되는 이벤트를 thing_created, thing_updated, 및 thing_deleted 이벤트 유형을 사용하여 생성해야 MUST 한다.
이벤트 필터링
API는 클라이언트가 필요로 하는 이벤트만 전달함으로써 자원 소비를 줄이기 위해 이벤트의 서버 측 필터링을 가능하게 한다. 클라이언트 라이브러리는 클라이언트 측에서 추가 필터링 기능을 제공할 수 있다.

서버는 구독 시 클라이언트가 제공한 이벤트 유형을 기반으로 이벤트 필터링을 지원해야 MUST 한다.

예를 들어 URI Template /events{/type}가 주어진 경우:

  • /events/thing_createdthing_created 유형의 이벤트만 전달하도록 서버에 지시한다
  • /events는 모든 이벤트를 전달하도록 서버에 지시한다

클라이언트는 서버에서 이벤트의 하위 집합(예: thing_createdthing_deleted만)을 받기 위해 별도로 구독해야 한다. HTTP/2를 사용할 때, 동일한 도메인의 여러 구독(HTTP 스트림)은 하나의 연결에서 다중화된다.

이벤트 데이터

이벤트 데이터는 이벤트 객체의 JSON 직렬화를 포함해야 MUST 한다. 이벤트 데이터 객체는 요청에 따라 부분 TD 또는 전체 TD 객체이다:

  • 이벤트 데이터 객체는 적어도 해당 이벤트에서 생성, 업데이트 또는 삭제된 TD의 식별자를 부분 TD 형식으로 포함해야 MUST 한다.
  • diff 질의 매개변수가 true로 설정되고 이벤트가 thing_created 유형인 경우, 서버는 전체 TD 객체를 이벤트 데이터로 반환할 수 MAY 있다.
  • diff 질의 매개변수가 true로 설정되고 이벤트가 thing_updated 유형인 경우, 서버는 JSON Merge Patch [RFC7396] 형식에 따라 업데이트된 부분을 클라이언트에게 알릴 수 MAY 있다. JSON Merge Patch [RFC7396]에 기반한 thing_updated 이벤트 데이터는 변경 여부와 관계없이 항상 TD의 식별자를 포함해야 MUST 한다.

    다음 예제는 예제 12의 TD 업데이트 시 트리거된 이벤트를 보여준다:

  • diff 질의 매개변수는 thing_deleted 이벤트에 대해 무시되어야 MUST 한다. 즉, difftrue로 설정된 경우에도 서버는 thing_deleted 이벤트의 페이로드에 추가 속성을 포함하지 않아야 한다.
  • diff 질의 매개변수를 지원하지 않는 서버가 그러한 질의 매개변수로 요청을 받은 경우, 요청을 거부해야 한다. 이는 연결 시점에 클라이언트에게 그러한 기능이 없음을 알리고, 이벤트 데이터 속성 누락으로 인한 런타임 예외를 피하기 위한 것이다.

알림 API는 7.3.2.4 API 명세(사물 모델)에서 세 가지 이벤트 어포던스로 지정된다. 즉: thingCreated, thingUpdated, 및 thingDeleted.

참고: SSE Authorization 헤더

일부 초기 SSE 구현(HTML5 EventSource 포함)은 초기 HTTP 요청에서 사용자 지정 헤더 설정을 허용하지 않는다. Authorization 헤더는 일부 OAuth2 흐름에서 필요하며, 이를 질의 매개변수로 전달하는 것은 권장되지 않는다. 브라우저용 폴리필과 Authorization 헤더 설정을 허용하는 현대적인 라이브러리가 있다.

7.3.2.4 API 명세 (사물 모델)

사물 설명 디렉터리의 API 템플릿은 여기에서 사물 모델로 제공된다. 사물 모델은 (명시된 경우를 제외하고) 규범적이지만, 사물 설명 디렉터리를 구현하거나 상호작용하기 위한 유일한 참조로 간주되어서는 안 된다. 또한 7.3.2 디렉터리 서비스 API에 제시된 명세도 참조하라.

이 사물 모델에 제공된 searchJSONPathsearchXPath 어포던스는 규범적이지 않으며 정보 제공용으로만 제공된다.

HTTP 응답의 본문이 비어 있어야 하는 경우에도 ExpectedResponse 클래스의 인스턴스(즉, form의 response 키에 해당하는 JSON 객체)에 대해 WoT TD 1.1 명세 [wot-thing-description11]가 contentType을 요구한다는 점에 유의한다. 이 경우 아래 TM에서 생성된 TD가 유효하도록 application/x-empty를 사용할 수 있다.

{
    "@context": [
        "https://www.w3.org/2022/wot/td/v1.1",
        "https://www.w3.org/2022/wot/discovery"
    ],
    "@type": [
        "tm:ThingModel",
        "ThingDirectory"
    ],
    "title": "Thing Description Directory (TDD) Thing Model",
    "version": {
        "model": "1.0.0"
    },
    "base": "{{DIRECTORY_BASE_URL}}",
    "tm:optional": [
        "/actions/createThing",
        "/actions/createAnonymousThing",
        "/actions/retrieveThing",
        "/actions/updateThing",
        "/actions/partiallyUpdateThing",
        "/actions/deleteThing",
        "/actions/searchJSONPath",
        "/actions/searchXPath",
        "/actions/searchSPARQL",
        "/events/thingCreated",
        "/events/thingUpdated",
        "/events/thingDeleted"
    ],
    "properties": {
        "things": {
            "description": "Retrieve all Thing Descriptions",
            "uriVariables": {
                "offset": {
                    "title": "Number of TDs to skip before the page",
                    "type": "number",
                    "default": 0
                },
                "limit": {
                    "title": "Number of TDs in a page",
                    "type": "number"
                },
                "format": {
                    "title": "Payload format",
                    "type": "string",
                    "enum": [
                        "array",
                        "collection"
                    ],
                    "default": "array"
                }
            },
            "forms": [
                {
                    "href": "/things{?offset,limit,format}",
                    "htv:methodName": "GET",
                    "response": {
                        "description": "Success response",
                        "htv:statusCodeValue": 200,
                        "contentType": "application/ld+json",
                        "htv:headers": [
                            {
                                "htv:fieldName": "Link"
                            }
                        ]
                    },
                    "additionalResponses": [
                        {
                            "description": "Invalid query arguments",
                            "contentType": "application/problem+json",
                            "htv:statusCodeValue": 400
                        }
                    ]
                }
            ]
        }
    },
    "actions": {
        "createThing": {
            "description": "Create a Thing Description",
            "uriVariables": {
                "id": {
                    "@type": "ThingID",
                    "title": "Thing Description ID",
                    "type": "string",
                    "format": "iri-reference"
                }
            },
            "input": {
                "description": "The schema is implied by the content type",
                "type": "object"
            },
            "forms": [
                {
                    "href": "/things/{id}",
                    "htv:methodName": "PUT",
                    "contentType": "application/td+json",
                    "response": {
                        "description": "Success response",
                        "htv:statusCodeValue": 201
                    },
                    "additionalResponses": [
                        {
                            "description": "Invalid serialization or TD",
                            "contentType": "application/problem+json",
                            "htv:statusCodeValue": 400
                        }
                    ]
                }
            ]
        },
        "createAnonymousThing": {
            "description": "Create an anonymous Thing Description",
            "input": {
                "description": "The schema is implied by the content type",
                "type": "object"
            },
            "forms": [
                {
                    "href": "/things",
                    "htv:methodName": "POST",
                    "contentType": "application/td+json",
                    "response": {
                        "description": "Success response including the system-generated URI",
                        "htv:headers": [
                            {
                                "description": "System-generated URI",
                                "htv:fieldName": "Location"
                            }
                        ],
                        "htv:statusCodeValue": 201
                    },
                    "additionalResponses": [
                        {
                            "description": "Invalid serialization or TD",
                            "contentType": "application/problem+json",
                            "htv:statusCodeValue": 400
                        }
                    ]
                }
            ]
        },
        "retrieveThing": {
            "description": "Retrieve a Thing Description",
            "uriVariables": {
                "id": {
                    "@type": "ThingID",
                    "title": "Thing Description ID",
                    "type": "string",
                    "format": "iri-reference"
                }
            },
            "output": {
                "description": "The schema is implied by the content type",
                "type": "object"
            },
            "safe": true,
            "idempotent": true,
            "forms": [
                {
                    "href": "/things/{id}",
                    "htv:methodName": "GET",
                    "response": {
                        "description": "Success response",
                        "htv:statusCodeValue": 200,
                        "contentType": "application/td+json"
                    },
                    "additionalResponses": [
                        {
                            "description": "TD with the given id not found",
                            "contentType": "application/problem+json",
                            "htv:statusCodeValue": 404
                        }
                    ]
                }
            ]
        },
        "updateThing": {
            "description": "Update a Thing Description",
            "uriVariables": {
                "id": {
                    "@type": "ThingID",
                    "title": "Thing Description ID",
                    "type": "string",
                    "format": "iri-reference"
                }
            },
            "input": {
                "description": "The schema is implied by the content type",
                "type": "object"
            },
            "forms": [
                {
                    "href": "/things/{id}",
                    "htv:methodName": "PUT",
                    "contentType": "application/td+json",
                    "response": {
                        "description": "Success response",
                        "htv:statusCodeValue": 204
                    },
                    "additionalResponses": [
                        {
                            "description": "Invalid serialization or TD",
                            "contentType": "application/problem+json",
                            "htv:statusCodeValue": 400
                        }
                    ]
                }
            ]
        },
        "partiallyUpdateThing": {
            "description": "Partially update a Thing Description",
            "uriVariables": {
                "id": {
                    "@type": "ThingID",
                    "title": "Thing Description ID",
                    "type": "string",
                    "format": "iri-reference"
                }
            },
            "input": {
                "description": "The schema is implied by the content type",
                "type": "object"
            },
            "forms": [
                {
                    "href": "/things/{id}",
                    "htv:methodName": "PATCH",
                    "contentType": "application/merge-patch+json",
                    "response": {
                        "description": "Success response",
                        "htv:statusCodeValue": 204
                    },
                    "additionalResponses": [
                        {
                            "description": "Invalid serialization or TD",
                            "contentType": "application/problem+json",
                            "htv:statusCodeValue": 400
                        },
                        {
                            "description": "TD with the given id not found",
                            "contentType": "application/problem+json",
                            "htv:statusCodeValue": 404
                        }
                    ]
                }
            ]
        },
        "deleteThing": {
            "description": "Delete a Thing Description",
            "uriVariables": {
                "id": {
                    "@type": "ThingID",
                    "title": "Thing Description ID",
                    "type": "string",
                    "format": "iri-reference"
                }
            },
            "forms": [
                {
                    "href": "/things/{id}",
                    "htv:methodName": "DELETE",
                    "response": {
                        "description": "Success response",
                        "htv:statusCodeValue": 204
                    },
                    "additionalResponses": [
                        {
                            "description": "TD with the given id not found",
                            "contentType": "application/problem+json",
                            "htv:statusCodeValue": 404
                        }
                    ]
                }
            ]
        },
        "searchJSONPath": {
            "description": "JSONPath syntactic search.  This affordance is not normative and is provided for information only.",
            "uriVariables": {
                "query": {
                    "title": "A valid JSONPath expression",
                    "type": "string"
                }
            },
            "output": {
                "description": "The schema depends on the given query",
                "type": "object"
            },
            "safe": true,
            "idempotent": true,
            "forms": [
                {
                    "href": "/search/jsonpath?query={query}",
                    "htv:methodName": "GET",
                    "response": {
                        "description": "Success response",
                        "contentType": "application/json",
                        "htv:statusCodeValue": 200
                    },
                    "additionalResponses": [
                        {
                            "description": "JSONPath expression not provided or contains syntax errors",
                            "contentType": "application/problem+json",
                            "htv:statusCodeValue": 400
                        }
                    ]
                }
            ]
        },
        "searchXPath": {
            "description": "XPath syntactic search.  This affordance is not normative and is provided for information only.",
            "uriVariables": {
                "query": {
                    "title": "A valid XPath expression",
                    "type": "string"
                }
            },
            "output": {
                "description": "The schema depends on the given query",
                "type": "object"
            },
            "safe": true,
            "idempotent": true,
            "forms": [
                {
                    "href": "/search/xpath?query={query}",
                    "htv:methodName": "GET",
                    "response": {
                        "description": "Success response",
                        "contentType": "application/json",
                        "htv:statusCodeValue": 200
                    },
                    "additionalResponses": [
                        {
                            "description": "XPath expression not provided or contains syntax errors",
                            "contentType": "application/problem+json",
                            "htv:statusCodeValue": 400
                        }
                    ]
                }
            ]
        },
        "searchSPARQL": {
            "description": "SPARQL semantic search",
            "uriVariables": {
                "query": {
                    "title": "A valid SPARQL 1.1. query",
                    "type": "string"
                }
            },
            "output": {
                "description": "The schema depends on the given query",
                "type": "object"
            },
            "safe": true,
            "idempotent": true,
            "forms": [
                {
                    "href": "/search/sparql?query={query}",
                    "htv:methodName": "GET",
                    "response": {
                        "description": "Success response",
                        "contentType": "application/json",
                        "htv:statusCodeValue": 200
                    },
                    "additionalResponses": [
                        {
                            "description": "SPARQL query not provided or contains syntax errors",
                            "contentType": "application/problem+json",
                            "htv:statusCodeValue": 400
                        }
                    ]
                },
                {
                    "href": "/search/sparql",
                    "htv:methodName": "POST",
                    "response": {
                        "description": "Success response",
                        "contentType": "application/json",
                        "htv:statusCodeValue": 200
                    },
                    "additionalResponses": [
                        {
                            "description": "SPARQL query not provided or contains syntax errors",
                            "contentType": "application/problem+json",
                            "htv:statusCodeValue": 400
                        }
                    ]
                }
            ]
        }
    },
    "events": {
        "thingCreated": {
            "description": "Registration of Thing Descriptions inside the directory",
            "uriVariables": {
                "diff": {
                    "description": "Receive the full created TD as event data",
                    "type": "boolean"
                }
            },
            "data": {
                "title": "Partial/Full TD",
                "type": "object"
            },
            "forms": [
                {
                    "op": "subscribeevent",
                    "href": "/events/thing_created{?diff}",
                    "subprotocol": "sse",
                    "htv:headers": [
                        {
                            "description": "ID of the last event for reconnection",
                            "htv:fieldName": "Last-Event-ID"
                        }
                    ],
                    "response": {
                        "contentType": "text/event-stream"
                    }
                }
            ]
        },
        "thingUpdated": {
            "description": "Updates to Thing Descriptions within the directory",
            "uriVariables": {
                "diff": {
                    "description": "Include TD changes inside event data",
                    "type": "boolean"
                }
            },
            "data": {
                "title": "Partial TD",
                "type": "object",
                "contentMediaType": "application/merge-patch+json"
            },
            "forms": [
                {
                    "op": "subscribeevent",
                    "href": "/events/thing_updated{?diff}",
                    "subprotocol": "sse",
                    "htv:headers": [
                        {
                            "description": "ID of the last event for reconnection",
                            "htv:fieldName": "Last-Event-ID"
                        }
                    ],
                    "response": {
                        "contentType": "text/event-stream"
                    }
                }
            ]
        },
        "thingDeleted": {
            "description": "Deletion of Thing Descriptions from the directory",
            "data": {
                "title": "Partial TD",
                "type": "object"
            },
            "forms": [
                {
                    "op": "subscribeevent",
                    "href": "/events/thing_deleted",
                    "subprotocol": "sse",
                    "htv:headers": [
                        {
                            "description": "ID of the last event for reconnection",
                            "htv:fieldName": "Last-Event-ID"
                        }
                    ],
                    "response": {
                        "contentType": "text/event-stream"
                    }
                }
            ]
        }
    }
}

8. 보안 고려 사항

보안은 모든 WoT 빌딩 블록과 WoT 구현에서 고려해야 하는 교차 영역 문제이다. 이 장은 구체적인 WoT 디스커버리 구현의 보안을 보존하는 데 도움이 되는 몇 가지 일반적인 문제와 지침을 요약한다. 보안 및 개인정보 보호 문제 모두에 대한 더 상세하고 완전한 분석은 WoT 보안 및 개인정보 보호 지침 명세 [WOT-SECURITY]를 참조하라. WoT 사물과 WoT TDD도 웹 서비스이므로 웹 서비스의 모범 사례를 사용하여 구현해야 한다. 아래의 특정 보안 고려 사항에 더하여, OWASP Top 10 [OWASP-Top-10] 같은 지침에서 논의되는 보안 위험과 완화책을 평가하고, 해당되는 경우 이를 처리해야 한다.

8.1 서비스 거부

디렉터리 서비스의 특정 기능, 특히 검색 질의는 실행하는 데 상당한 자원이 필요할 수 있으며, 이 사실은 WoT 사물 설명 디렉터리 서비스에 대한 서비스 거부(DoS) 공격을 시작하는 데 사용될 수 있다. 이러한 공격에서 WoT 디렉터리는 공격자의 요청으로 과부하되어 다른 요청을 처리할 수 없게 된다.

완화책:
  • WoT 사물 설명 디렉터리 구현은 동일 요청자로부터의 단위 시간당 질의 수를 제한해야 한다.
  • WoT 사물 설명 디렉터리 구현은 질의의 복잡도(예: 질의 표현식의 전체 길이 또는 깊이)를 제한해야 한다.
  • WoT 사물 설명 디렉터리 구현은 특정 최대 (구현에서 구성 가능한) 시간을 초과하는 질의를 중단하기 위해 워치독 타이머를 사용해야 한다.

8.2 증폭 및 분산 서비스 거부

WoT 디스커버리 메커니즘의 요소를 사용하여 다른 대상을 향한 분산 서비스 거부(DDoS) 공격을 시작하는 것도 가능할 수 있다. 이러한 공격에서 WoT 디스커버리 서비스 자체가 대상은 아니다. 대신 WoT 디스커버리 서비스의 어떤 측면이 악용되어 실제 대상인 제3자를 과부하시키는 증폭된 네트워크 트래픽을 생성한다. 이러한 공격에는 두 가지 요구사항이 있다. 첫째, 트래픽을 제3자로 리디렉션할 수 있는 능력이고, 둘째, 공격자의 네트워크 트래픽을 증폭하는 데 악용될 수 있는 중개 서비스이다. 안전하지 않은 CoAP와 같은 일부 프로토콜에서는 헤더의 출처 정보를 수정함으로써 네트워크 트래픽의 리디렉션이 가능하다. 증폭은 세 가지 곱셈 요인, 즉 요청 대 응답 페이로드 크기의 비율, CoAP 같은 프로토콜에서의 "observe" 사용(하나의 요청에 대해 여러 결과를 줄 수 있음), 그리고 멀티캐스트 사용 (하나의 요청에 대해 여러 서버가 응답할 수 있음)을 이용하여 가능하다. 인증을 지원하지 않는 서비스는 이러한 간접 공격에 이상적인 중개자이다. 불행히도 WoT 디스커버리의 도입 메커니즘은 디스커버리를 시작하기 위한 개방형 접근 메커니즘을 제공하도록 의도되어 있으며, 이 목적에 악용될 수 있다.

완화책:
  • 도입 메커니즘의 개방형 구현은 observe 또는 유사한 확장 결과 하위 프로토콜을 지원하지 않는 것이 좋다 SHOULD NOT.
  • 도입 메커니즘의 개방형 구현은 프로토콜에서 절대적으로 요구되지 않는 한 멀티캐스트 요청에 응답하지 않아야 한다. 멀티캐스트 지원이 필요한 경우, CoAP에서는 [AMPLIFICATION-ATTACKS]에서 제시된 관찰 사항이 관련된다. 디스커버리 중 멀티캐스트 요청에 응답할 수 있는 서버의 수는 일반적으로 사전에 알 수 없기 때문이다.
  • 응답 크기를 최소한으로 제한한다. 공개 인터넷 (보호된 로컬 네트워크 외부)에서의 도입에 대한 응답의 총 크기는 요청 총 크기의 3배보다 작아야 하며, 여기에는 모든 오류 응답도 포함되어야 한다. 이는 [RFC9000] (QUIC) 및 HTTP/3의 DDoS 완화와 일치한다. 여기서 "총 크기"에는 프로토콜 자체에 필요한 모든 헤더와 더 큰 응답을 허용하기 위한 요청의 패딩이 포함된다.
  • 도입은 특정 요청 출처에 대한 응답률을 제한해야 한다.
  • 방화벽 뒤의 분할된 네트워크 (예: LAN)에 있는 도입 메커니즘은 그 LAN 외부에서 온 것으로 보이는 요청에 응답하지 않는 것이 좋다 SHOULD NOT.
특히 우려되는 것은 CoRE-RD 및 DID처럼 여러 결과를 반환할 수 있는 도입 메커니즘이다. 위의 다른 완화책이 충분하지 않다면 이러한 도입 메커니즘에도 인증/권한 부여를 사용하는 것이 필요할 수 있다. 권장되는 대안은 그러한 도입에서 나온 여러 결과를 WoT TDD로 옮기는 것이며, 그러면 WoT TDD는 적절한 인증 및 권한 부여 조치로 보호될 수 있다. 그러면 개방형 도입 메커니즘은 TDD의 URL이라는 하나의 결과만 반환하면 된다. 공개 인터넷에서 보이는 도입 메커니즘은 위의 완화책을 구현하는 데 특히 주의해야 하며, 여러 URL을 반환할 수 있는 도입 메커니즘을 완전히 피하는 것도 고려할 수 있다.

8.3 LAN에서의 자기 디스커버리

LAN에서는 브라우저가 공개적으로 보이는 URL을 가리키는 인증서를 기대하기 때문에, 인증서와 브라우저가 HTTPS용 TLS를 제대로 설정하지 못할 수 있다. LAN 내부에서 HTTP를 사용하는 것은 일반적인 관행이지만, 자기 설명과 결합되면 WoT 사물이 사설 LAN에 접근할 수 있는 모든 사람에게 TD를 본질적으로 노출하게 된다는 뜻이다. HTTP 비밀번호 같은 보안 메커니즘을 사용하더라도 전송 보안 없이는 효과적이지 않다(트래픽 분석기로 쉽게 발견될 수 있기 때문이다).

완화책:

LAN에서는 가능하다면 PSK(사전 공유 키)를 사용해야 하며 SHOULD, 이는 [RFC4279]의 암호군 중 하나를 의미한다. 이는 사물이 공통 보안 도메인에서 PSK를 할당받아야 함을 요구하며, 일반적으로 온보딩 프로세스를 따라 수행된다. 불행히도 구체적인 온보딩 프로세스는 현재 WoT 명세의 범위를 벗어난다.

대안은 로컬 네트워크 보안(즉, WEP)에 의존하는 것이다. 이는 보안 또는 개인정보 보호 관점에서 최선의 해결책은 아니지만 일부 맥락에서는 허용될 수 있다. 그러나 네트워크에 접근할 수 있는 모든 사용자가 자기 설명을 통해 모든 TD에 접근할 수 있다는 점에 유의한다. 사물을 전송 보안 및 인증과 권한 부여로 개별적으로 보호할 수 없다면, 별도의 네트워크, 즉 대체 SSID를 갖는 네트워크를 설정하고 IoT 장치에만 사용하는 것이 좋다 SHOULD. 분할된 네트워크를 사용하면 이 네트워크에 연결된 IoT 장치 집합에 접근해야 하는 사람에게 이 네트워크의 비밀번호를 배포해야 할 필요가 줄어든다.

또 다른 대안은 클라우드 기반 리버스 프록시 서비스를 사용하는 것이다. IoT 장치가 클라우드에 접근할 수 있다면, 프록시 서버는 공개 URL을 가질 수 있고 초기 연결은 HTTPS를 사용할 수 있으며, 이후 websocket을 통해 보안 터널을 열 수 있으므로 안전한 설정을 달성할 수 있다. 프록시는 다시 보안 엔드포인트를 노출할 수 있으며, 인증을 추가할 수도 있다. 이 접근법의 단점에는 외부 클라우드 서비스에 의존한다는 점과 외부 접근 지점을 노출해야 한다는 점 (그 자체가 보안 위험임)이 포함된다. 첫 번째 단점은 로컬 서버가 ISP를 통해 연결되어 있는 경우, 프록시 서비스를 로컬에 호스팅하고 예를 들어 동적 DNS를 사용하여 공개 URL을 노출함으로써 해결할 수 있다. 사물을 전송 보안 및 인증과 권한 부여로 개별적으로 보호할 수 없다면, 적절한 접근 제어를 제공할 수 있는 프록시를 통해 일반 접근이 가능하도록 만들 수 있다.

9. 개인정보 보호 고려 사항

개인정보 보호는 모든 WoT 빌딩 블록과 WoT 구현에서 고려해야 하는 교차 영역 문제이다. 이 장은 구체적인 WoT 디스커버리 구현의 개인정보 보호를 보존하는 데 도움이 되는 몇 가지 일반적인 문제와 지침을 요약한다. 보안 및 개인정보 보호 문제 모두에 대한 더 상세하고 완전한 분석은 WoT 보안 및 개인정보 보호 지침 명세 [WOT-SECURITY]를 참조하라.

WoT 디스커버리 아키텍처는 2단계 접근 방식을 사용하고 메타데이터 공개 전에 권한 부여를 강제할 수 있도록 함으로써 기존 디스커버리 체계의 개인정보 보호에 대한 의존을 피하도록 설계되었다. 그러나 여러 개인정보 보호 위험은 여전히 존재한다. 아래에는 이러한 위험과 가능한 완화책이 나열되어 있다. 개인정보 보호에 대한 위험 수준은 특히 사용 사례와 사람과 관련된 정보가 그 사람의 개인정보 보호 의사와 일치하지 않는 방식으로 배포될 위험이 있는지에 달려 있다. 개인정보 보호를 위해 우리는 다음과 같은 넓은 사용 사례 시나리오 클래스를 구분한다:

기관
메타데이터를 생성하는 사물과 그 메타데이터의 컨슈머가 모두 기관 또는 기관의 대표자가 소유하고 제어한다. 예: 제어 시스템이 품질 평가를 위해 조립 라인의 상태에 접근하는 공장의 자동화.
서비스
메타데이터를 생성하는 사물은 기관 또는 기관의 대표자가 소유하고 제어하지만, 컨슈머는 개인이다. 예: 전기 자동차 운전자가 충전 상태를 확인하기 위해 충전소의 TD에 접근하는 경우.
개인
메타데이터를 생성하는 사물과 그 메타데이터의 컨슈머가 모두 동일한 개인이 소유하고 제어한다. 예: 같은 사람이 소유한 집과 자동차에서, 집에 부착된 태양광 패널로 전기차를 충전하기 위한 스마트 홈 제어 시스템.
개인 피어 투 피어
메타데이터를 생성하는 사물과 그 메타데이터의 컨슈머가 서로 다른 개인이 소유하고 제어한다. 예: 손님의 전기차를 집에 부착된 태양광 패널로 충전하기 위한 스마트 홈 제어 시스템.
기관 피어 투 피어
메타데이터를 생성하는 사물과 그 메타데이터의 컨슈머가 서로 다른 기관이 소유하고 제어한다. 예: 전력 회사가 공장에 공급되는 전력을 제공하고 관리하며, 공장은 전력 회사가 주문형 전력 사용량 감소를 협상할 수 있는 인터페이스를 제공하는 경우.
클라이언트
메타데이터를 생성하는 사물은 개인이 소유하고 제어하지만, 컨슈머는 기관 또는 기관의 대표자이다. 예: 개인 전기차가 공용 충전소에 인터페이스를 노출하여 충전소가 차량의 충전 상태를 평가할 수 있게 하는 경우.

실제로 이 모든 경우에는 개인정보 보호 위험이 있다. 공장 자동화의 경우에도 직원 성과에 대한 데이터가 수집되어 적절히 관리되어야 할 가능성이 있다.

다음에서는 "추적"을 자주 언급한다. 이 용어는 위치 추적과 행동 프로파일링을 포함한 여러 개인정보 보호 위험을 포괄한다. 일반적으로 GDPR [GDPR-Defs] 제4조에 주어진 "프로파일링"의 정의는 이 문서에서 사용되는 "추적"과 동등한 것으로 간주해야 한다.

이러한 정의와 범주를 수립했으므로, 이제 몇 가지 특정 개인정보 보호 위험과 잠재적 완화책을 논의한다.

9.1 위치 추적 및 프로파일링

디스커버리 서비스는 잠재적으로 사람의 동의 없이 그 사람의 대략적인 위치를 확인할 수 있게 할 수 있다. 이 위험은 피하거나 완화할 수 있는 몇 가지 특정 상황에서 발생한다. 이는 DHCP 및 DNS 같은 다른 네트워크 서비스가 야기하는 위험과도 유사하다.

이 위험이 발생하려면 먼저 필수 의료 장치나 차량처럼 사람의 위치와 신뢰성 있게 연결될 수 있는 IoT 장치가 있어야 한다. 이 위험은 기관 사용 사례가 아니라 개인 사용 사례에만 적용된다는 점에 유의한다. 둘째, 장치가 가장 가까운 디렉터리 서비스에 자동으로 등록하도록 구성되어 있어야 한다. 이 경우, 디렉터리 서비스의 네트워크 범위에서 장치의 위치를 추론할 수 있고, 장치의 위치에서 사람의 위치를 추론할 수 있다.

여기에는 몇 가지 변형이 있다:

위치 추적만이 유일한 프로파일링 위험은 아니다. 일반적으로 "프로파일링"에는 경제적 상태, 건강, 선호, 관심사, 신뢰성 및 행동을 포함하여 사람에 관한 정보를 평가하는 데 사용되는 모든 메커니즘이 포함된다. TD의 일부 메타데이터는 설명된 사물이 사람과 연결될 수 있는 경우 이러한 종류의 정보를 추론하는 데 사용될 수 있다. 아래 완화책 중 일부는 이 더 일반적인 프로파일링 정의에도 적용 가능하다.

이러한 위험 중 일부는 유사한 서비스와 공유된다. 예를 들어 DCHP는 로컬 네트워크에서 IP 주소 요청에 자동으로 응답하며, 장치는 일반적으로 이 과정의 일부로 식별자(MAC 주소)를 제공하고 DHCP 서버는 레지스트리를 유지한다. 이론적으로 카페의 DHCP 서버에 접근할 수 있는 사람은 이 정보를 사용하여 누군가의 휴대폰을 추적하고 그 위치를 추론할 수 있다.

완화책:
이러한 위험을 완화하기 위한 몇 가지 선택지가 있다:
  • 위치 추적 및 기타 형태의 프로파일링을 피하기 위해, 사람과 연결된 WoT 사물은 공개 디렉터리에 대한 등록을 비활성화할 수 있다. 예를 들어 홈 게이트웨이 같은 개인 디렉터리에는 여전히 등록이 가능하지만, 사용자는 다른 위치에서의 등록을 비활성화할 수 있다. 이는 기능이 손실된다는 단점이 있다. 개인 장치는 공공 장소에서 발견될 수 없다. 이는 인터넷에서 접근 가능한 개인 디스커버리 서비스를 제공함으로써 해결할 수 있다. 예를 들어 사용자의 홈 게이트웨이는 인터넷 접근 가능 서비스를 제공하되, 접근 제어를 통해 사용을 권한 있는 사용자로 제한할 수 있다.
  • 위치 추적 및 기타 형태의 프로파일링을 피하기 위해, 사람과 연결된 WoT 사물은 공개 디렉터리에 등록할 때 익명 TD를 사용해야 한다. 어떤 경우에는 익명 TD를 사용하고 TDD에 제출되는 TD에서 명시적 ID를 생략할 수 있다. 이 경우 TDD는 해당 TDD에서만 유효한 로컬 ID를 생성한다. 그러나 이는 클라이언트가 TDD에서 할당한 로컬 ID를 기억해야 하므로 업데이트를 복잡하게 만든다. 익명 TD도 핑거프린팅과 같은 다른 수단에 의한 추적을 막지는 못한다.
  • 위치 추적 및 기타 형태의 프로파일링을 피하기 위해, 사람과 연결된 WoT 사물은 주기적으로 새 ID를 생성할 수 있다. 고정 ID를 사용하면 장치 추적이 매우 쉬워진다. 이 문제는 DHCP의 MAC 주소에서도 발생하며, 이와 유사한 부분적 완화책이 있다. 즉, 새 무작위 ID를 주기적으로 생성하는 것이다. 그러나 몇 가지 문제가 있다. 우선 TD의 다른 식별 정보는 숨겨져야 한다. 예를 들어 API 보안을 위해 CSP가 발급한 클라이언트 ID는 쉽게 변경할 수 없다면 TD에서 생략해야 한다. 둘째, 장치가 새 ID를 생성하면 사용자는 디스커버리를 통해 장치를 찾기 위해 현재 ID를 알아야 할 수도 있다. 그러나 이는 현재 시간의 함수인 결정론적 암호 생성기를 사용하여 새 ID를 생성함으로써 달성할 수 있다. 하지만 ID 재생성만으로 추적이 불가능해지는 것은 아니다. TD가 핑거프린팅될 수 있기 때문이다. 또한 ID 업데이트는 디렉터리 서비스 소유자에게 관찰될 수 있으며, 소유자는 업데이트된 ID를 추적하고 기록할 수 있다. TD가 삭제되고 다시 삽입되더라도 그 연관성은 추론될 수 있다. 이는 DHCP와 MAC 주소 회전 상황과 정확히 평행하다. 일반적으로 그러나 TD가 제공되는 각 서비스 또는 사람에 대해 새 식별자를 생성하는 것은 서로 다른 위치와 시간의 등록 이벤트를 연결하기 어렵게 만든다. 로컬 네트워크나 허브에서 등록 해제하고 새 네트워크나 허브에 등록하는 것과 같이 구성에 중대한 변화가 있을 때(이는 일반적으로 소유권 변경을 나타냄) 새 식별자를 생성하는 것도 신중한 방식이다. 추적 완화를 위해 주기적으로 업데이트가 필요할 수 있는 장기 IP 주소와 관련된 문제도 있다. ipv6의 맥락에서는 [RFC8981]에서 이를 논의한다. 마지막으로, 의료 장치처럼 특정 관할권에서 불변 식별자가 필요한 장치의 문제가 있다. 이는 [wot-thing-description11]에서 논의되지만, 요약하면 그러한 불변 식별자가 TD가 아니라 인증이 필요한 어포던스 등을 통해 보호된 속성으로만 제공되고, TD 식별자 자체(사용되는 경우)는 불변 식별자와 독립적이어서 변경 가능하게 만들 수 있다면 이 문제는 피할 수 있다.
  • 부정적 위치 추론의 위험을 줄이기 위해, 개인 디렉터리에 대한 접근은 접근 제어를 사용하여 제한하는 것이 좋다 SHOULD. 공격자가 서비스에 접근할 수 없다면, 위치를 추론하기 위한 정보를 검색할 수 없다. 게스트에게 제공되는 접근 권한(예: 개인 피어 투 피어 시나리오용)은 적절히 시간 제한되어야 한다. 다른 경우에는 긴 Time-to-Live 값을 사용하는 것이 적절할 수 있다. 또한 TD는 변경될 때만 디렉터리에서 업데이트되어야 한다. 예를 들어 자동차의 TD는 새 서비스를 제공하는 새 자동차 펌웨어가 있을 때만 업데이트될 수 있고, Time-to-Live는 한 달로 설정될 수 있다(대부분의 부재를 포괄함).
  • 명시적 위치 정보가 TD에 저장되어 있거나 속성에서 사용할 수 있는 경우, TD 및/또는 장치 접근을 디렉터리를 포함한 신뢰할 수 있는 파트너와만 공유하도록 추가적인 주의를 기울이는 것이 좋다 SHOULD. TD를 공개 디렉터리와 공유해야 하는 경우, 위치 정보는 제거될 수 있다.

9.2 질의 추적

디렉터리 서비스는 개인이 제공한 인증된 신원을 통해 그 개인을 식별하면서, 개인의 질의를 기록하고 추적할 수 있다. 그러면 개인과 연결된 질의 집합은 그 개인을 프로파일링하는 데 사용될 수 있으며, 특정 질의는 개인에 대한 개인정보를 드러낼 수도 있다.

완화책:

공개 디렉터리에 접근할 때, 다른 공개 웹 서비스와 마찬가지로 사용자와 구현은 익명 신원 제공자를 사용해야 한다. 특히 OAuth2는 특정 개인을 식별하지 않고 다른 곳에서 증명된 접근 권한만 단언하는 토큰을 제공할 수 있다.

10. 성능 고려 사항

이 섹션은 비규범이다.

10.1 점진적 전송

TD 객체는 크기에 제한이 없다. 개별적으로 또는 집합적으로 처리하고 전송하는 데 비용이 많이 들 수 있다. 단일 TD 또는 TD 목록은 자신의 TD를 컨슈머에게 제공하거나, 이를 디렉터리에 제출하거나, 다른 TD를 소비하는 제약된 장치에 너무 클 수 있다. 이러한 요구사항을 충족하기 위해 서버는 프로토콜별 메커니즘을 사용하여 페이로드의 점진적 전송을 지원해야 한다:

대부분의 HTTP 서버와 클라이언트는 청크로 전송되는 데이터를 자동으로 처리한다. 메모리 제약이 있는 클라이언트는 전체 객체를 메모리에 로드하여 역직렬화하려고 하기보다, 수신한 데이터를 점진적으로 소비하는 것을 고려해야 한다.

11. IANA 고려 사항

11.1 잘 알려진 URI 등록

IANA는 [RFC8615]에 정의된 잘 알려진 URI에 다음 값을 할당하도록 요청받을 것이다.

11.2 서비스 이름 등록

IANA는 [RFC6335]에 정의된 서비스 이름 및 전송 프로토콜 포트 번호 레지스트리에 다음 값을 할당하도록 요청받을 것이다.

11.3 CoRE 리소스 유형 등록

IANA는 [RFC6690]에 정의된 Constrained Restful Environments(CoRE) 매개변수 레지스트리의 Resource Type(rt=) Link Target Attribute Values 하위 레지스트리에 다음 값을 할당하도록 요청받을 것이다.

설명 참조
wot.thing 사물의 사물 설명 6.4 CoRE 링크 형식 및 CoRE 리소스 디렉터리
wot.directory 사물 설명 디렉터리의 사물 설명 6.4 CoRE 링크 형식 및 CoRE 리소스 디렉터리

12. 기타 이름 등록 고려 사항

12.1 DID 서비스 이름 등록

다음 값은 DID 문서에서 사용되는 서비스 유형에 할당될 것이다.

설명 참조
WotThing 사물의 사물 설명 6.5 DID 문서
WotDirectory 사물 설명 디렉터리의 사물 설명 6.5 DID 문서

A. WoT 디스커버리 TD 확장을 위한 JSON Schema

다음 JSON Schema는 보강된 TD에서 사용되는 확장을 지정한다. 이는 7.3.2.1.6 유효성 검사에 규정된 대로 TDDTD를 검증하는 데 사용할 수 있다.
{
  "title": "WoT Discovery TD-extensions Schema - 21 May 2021",
  "description": "JSON Schema for validating TD instances with WoT Discovery extensions",
  "$schema ": "https://json-schema.org/draft/2019-09/schema#",
  "type": "object",
  "properties": {
    "registration": {
      "type": "object",
      "properties": {
        "created": {
          "type": "string",
          "format": "date-time"
        },
        "expires": {
          "type": "string",
          "format": "date-time"
        },
        "retrieved": {
          "type": "string",
          "format": "date-time"
        },
        "modified": {
          "type": "string",
          "format": "date-time"
        },
        "ttl": {
          "type": "number"
        }
      }
    }
  }
}

B. 최근 명세 변경 사항

B.1 2023년 7월 11일 제안 권고안으로부터의 변경 사항

B.2 2023년 1월 19일 후보 권고안으로부터의 변경 사항

B.3 2022년 8월 10일 작업 초안으로부터의 변경 사항

B.4 2021년 6월 2일 작업 초안으로부터의 변경 사항

B.5 2020년 11월 24일 최초 공개 작업 초안으로부터의 변경 사항

C. 감사의 말

IoT의 기존 디스커버리 메커니즘에 대한 조사 작업을 해 준 Arne Broering, Soumya Kanti Datta, Christian Bonnet에게 특별한 감사를 전한다. 이 문서에 기여해 준 Philipp Blum, Victor Charpeney, Ben Francis, Christian Glomb, Daniel Peintner, Christine Perey, Jan Romann, Elodie Thieblin에게 특별한 감사를 전한다.

W3C 스태프, 특히 Kazuyuki Ashimura와 Dominique Hazael-Massieux, 그리고 이 문서의 개선으로 이어진 지원, 기술적 의견 및 제안을 제공한 W3C 웹 사물 관심 그룹(WoT IG) 및 워킹 그룹(WoT WG)의 모든 활동적인 참여자에게 깊이 감사한다.

D. 참고 문헌

D.1 규범적 참고 문헌

[AMPLIFICATION-ATTACKS]
Constrained Application Protocol(CoAP)을 사용한 증폭 공격. John Preuß Mattsson; Göran Selander; Christian Amsüss. IETF. DRAFT. URL: https://datatracker.ietf.org/doc/html/draft-irtf-t2trg-amplification-attacks
[DID-CORE]
분산 식별자(DID) v1.0. Manu Sporny; Amy Guy; Markus Sabadello; Drummond Reed. W3C. 2022년 7월 19일. W3C 권고안. URL: https://www.w3.org/TR/did-core/
[did-spec-registries]
DID 명세 레지스트리. Orie Steele; Manu Sporny. W3C. 2023년 9월 11일. W3C 워킹 그룹 노트. URL: https://www.w3.org/TR/did-spec-registries/
[Discovery-Categorization-IoT]
사물 인터넷을 위한 디스커버리 기술의 분류. Arne Broering; Soumya Kanti Datta; Christian Bonnet. Association of Computing Machinery (ACM): IoT'16 Proceedings. 2016년 11월 7-9일. URL: https://dl.acm.org/doi/10.1145/2991561.2991570
[GDPR-Defs]
일반 데이터 보호 규정(GDPR) 제4조 - 정의. European Union (EU) and the European Economic Area (EEA). URL: https://gdpr-info.eu/art-4-gdpr/
[HTML]
HTML 표준. Anne van Kesteren; Domenic Denicola; Ian Hickson; Philip Jägenstedt; Simon Pieters. WHATWG. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[JSON-LD11]
JSON-LD 1.1. Gregg Kellogg; Pierre-Antoine Champin; Dave Longley. W3C. 2020년 7월 16일. W3C 권고안. URL: https://www.w3.org/TR/json-ld11/
[OWASP-Top-10]
OWASP Top Ten. OWASP. URL: https://owasp.org/www-project-top-ten/
[RFC1738]
Uniform Resource Locators (URL). T. Berners-Lee; L. Masinter; M. McCahill. IETF. 1994년 12월. 제안 표준. URL: https://www.rfc-editor.org/rfc/rfc1738
[RFC2119]
RFC에서 요구 수준을 나타내기 위한 핵심 단어. S. Bradner. IETF. 1997년 3월. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc2119
[RFC3339]
인터넷상의 날짜와 시간: 타임스탬프. G. Klyne; C. Newman. IETF. 2002년 7월. 제안 표준. URL: https://www.rfc-editor.org/rfc/rfc3339
[RFC4122]
범용 고유 식별자(UUID) URN 네임스페이스. P. Leach; M. Mealling; R. Salz. IETF. 2005년 7월. 제안 표준. URL: https://www.rfc-editor.org/rfc/rfc4122
[RFC4279]
Transport Layer Security (TLS)를 위한 사전 공유 키 암호군. P. Eronen, Ed.; H. Tschofenig, Ed.. IETF. 2005년 12월. 제안 표준. URL: https://www.rfc-editor.org/rfc/rfc4279
[RFC6335]
서비스 이름 및 전송 프로토콜 포트 번호 레지스트리 관리를 위한 Internet Assigned Numbers Authority(IANA) 절차. M. Cotton; L. Eggert; J. Touch; M. Westerlund; S. Cheshire. IETF. 2011년 8월. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc6335
[RFC6690]
Constrained RESTful Environments(CoRE) 링크 형식. Z. Shelby. IETF. 2012년 8월. 제안 표준. URL: https://www.rfc-editor.org/rfc/rfc6690
[RFC6762]
멀티캐스트 DNS. S. Cheshire; M. Krochmal. IETF. 2013년 2월. 제안 표준. URL: https://www.rfc-editor.org/rfc/rfc6762
[RFC6763]
DNS 기반 서비스 디스커버리. S. Cheshire; M. Krochmal. IETF. 2013년 2월. 제안 표준. URL: https://www.rfc-editor.org/rfc/rfc6763
[RFC7231]
하이퍼텍스트 전송 프로토콜(HTTP/1.1): 의미와 콘텐츠. R. Fielding, Ed.; J. Reschke, Ed.. IETF. 2014년 6월. 제안 표준. URL: https://httpwg.org/specs/rfc7231.html
[RFC7396]
JSON Merge Patch. P. Hoffman; J. Snell. IETF. 2014년 10월. 제안 표준. URL: https://www.rfc-editor.org/rfc/rfc7396
[RFC7595]
URI 스킴을 위한 지침 및 등록 절차. D. Thaler, Ed.; T. Hansen; T. Hardie. IETF. 2015년 6월. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc7595
[RFC7807]
HTTP API를 위한 Problem Details. M. Nottingham; E. Wilde. IETF. 2016년 3월. 제안 표준. URL: https://www.rfc-editor.org/rfc/rfc7807
[RFC7959]
Constrained Application Protocol (CoAP)의 블록 단위 전송. C. Bormann; Z. Shelby, Ed.. IETF. 2016년 8월. 제안 표준. URL: https://www.rfc-editor.org/rfc/rfc7959
[RFC8174]
RFC 2119 핵심 단어에서 대문자와 소문자의 모호성. B. Leiba. IETF. 2017년 5월. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc8174
[RFC8288]
웹 링킹. M. Nottingham. IETF. 2017년 10월. 제안 표준. URL: https://httpwg.org/specs/rfc8288.html
[RFC8615]
잘 알려진 통일 자원 식별자(URI). M. Nottingham. IETF. 2019년 5월. 제안 표준. URL: https://www.rfc-editor.org/rfc/rfc8615
[RFC8981]
IPv6의 상태 비저장 주소 자동 구성을 위한 임시 주소 확장. F. Gont; S. Krishnan; T. Narten; R. Draves. IETF. 2021년 2월. 제안 표준. URL: https://www.rfc-editor.org/rfc/rfc8981
[RFC9000]
QUIC: UDP 기반 다중화 및 보안 전송. J. Iyengar, Ed.; M. Thomson, Ed.. IETF. 2021년 5월. 제안 표준. URL: https://www.rfc-editor.org/rfc/rfc9000
[RFC9176]
Constrained RESTful Environments(CoRE) 리소스 디렉터리. C. Amsüss, Ed.; Z. Shelby; M. Koster; C. Bormann; P. van der Stok. IETF. 2022년 4월. 제안 표준. URL: https://www.rfc-editor.org/rfc/rfc9176
[SPARQL11-OVERVIEW]
SPARQL 1.1 개요. The W3C SPARQL Working Group. W3C. 2013년 3월 21일. W3C 권고안. URL: https://www.w3.org/TR/sparql11-overview/
[wot-architecture11]
웹 사물(WoT) 아키텍처 1.1. Michael Lagally; Ryuichi Matsukura; Kunihiko Toumura; Michael McCool. W3C. 2023년 12월 5일. W3C 권고안. URL: https://www.w3.org/TR/wot-architecture11/
[wot-thing-description11]
웹 사물(WoT) 사물 설명 1.1. Sebastian Käbisch; Michael McCool; Ege Korkan. W3C. 2023년 12월 5일. W3C 권고안. URL: https://www.w3.org/TR/wot-thing-description11/
[wot-usecases]
웹 사물(WoT): 사용 사례. Michael Lagally; Michael McCool; Ryuichi Matsukura; Tomoaki Mizushima. W3C. 2020년 10월 15일. 편집자 초안. URL: https://w3c.github.io/wot-usecases/
[xpath-31]
XML Path Language (XPath) 3.1. Jonathan Robie; Michael Dyck; Josh Spiegel. W3C. 2017년 3월 21일. W3C 권고안. URL: https://www.w3.org/TR/xpath-31/

D.2 정보 참고 문헌

[JSONPATH]
JSONPath: JSON을 위한 질의 표현식. Stefan Gössner; Glyn Normington; Carsten Bormann. IETF. DRAFT. URL: https://datatracker.ietf.org/doc/html/draft-ietf-jsonpath-base
[LDP-Paging]
Linked Data Platform Paging 1.0. Steve Speicher; John Arwe; Ashok Malhotra. W3C. 2015년 6월 30일. W3C 워킹 그룹 노트. URL: https://www.w3.org/TR/ldp-paging/
[REST-IOT]
사물 인터넷 시스템을 위한 RESTful 설계. Ari Keranen; Matthias Kovatsch; Klaus Hartke. IETF. 2020년 5월 11일. URL: https://datatracker.ietf.org/doc/html/draft-irtf-t2trg-rest-iot-06
[RFC7230]
하이퍼텍스트 전송 프로토콜(HTTP/1.1): 메시지 구문 및 라우팅. R. Fielding, Ed.; J. Reschke, Ed.. IETF. 2014년 6월. 제안 표준. URL: https://httpwg.org/specs/rfc7230.html
[RFC7540]
하이퍼텍스트 전송 프로토콜 버전 2(HTTP/2). M. Belshe; R. Peon; M. Thomson, Ed.. IETF. 2015년 5월. 제안 표준. URL: https://httpwg.org/specs/rfc7540.html
[RFC8323]
TCP, TLS 및 WebSockets 위의 CoAP(Constrained Application Protocol). C. Bormann; S. Lemay; H. Tschofenig; K. Hartke; B. Silverajan; B. Raymor, Ed.. IETF. 2018년 2월. 제안 표준. URL: https://www.rfc-editor.org/rfc/rfc8323
[WOT-SECURITY]
웹 사물(WoT) 보안 및 개인정보 보호 지침. Elena Reshetova; Michael McCool. W3C. 2019년 11월 6일. W3C 워킹 그룹 노트. URL: https://www.w3.org/TR/wot-security/