# 로컬 보안

> LMSP 서비스의 보안 요구 사항. 루프백 바인딩, 페어링과 베어러 토큰, 스코프, 악성 웹 페이지에 대비한 Origin 및 Host 검사, LAN 모드, 로깅 규칙을 정의합니다.

Source: https://madeforagent.com/ko/lmsp/1.0/security/
Language: ko
Specification: LMSP 1.0 (draft)
Updated: 2026-11-08

## 10.1 기본 원칙 {#baseline}

localhost에서만 수신 대기한다고 절대적으로 안전한 것은 아니다. 악성 웹 페이지가 여전히 로컬 포트에 접근을 시도할 수 있기 때문이다. 그래서 LMSP는 여러 조치를 결합한다.

- 서비스는 기본적으로 루프백 주소에 바인딩해**야 한다**. LAN 모드가 켜져 있지 않은 한([10.5절](https://madeforagent.com/ko/lmsp/1.0/security.md#lan)) `0.0.0.0`이나 그 밖의 루프백이 아닌 주소에서 수신 대기해서는 **안 된다**.
- 서비스는 처음 실행할 때 엔트로피가 높은 임의의 서비스 비밀 값을 생성하고, 내장된 기본값이 아니라 그 값으로 토큰을 발급하고 검증하는 **것이 좋다**.
- 핵심 인터페이스에 대한 모든 요청은 [4.2절](https://madeforagent.com/ko/lmsp/1.0/endpoints.md#conventions)에 나열된 부트스트랩 엔드포인트를 제외하고 유효한 베어러 토큰을 담**아야 한다**. 루프백에서 왔다는 것만으로는 결코 충분하지 않다.

## 10.2 페어링과 토큰 {#pairing}

클라이언트는 로컬 페어링 코드로 자신만의 베어러 토큰을 얻는다. 사용자는 서비스가 제공하는 방법으로 서비스가 페어링 코드를 보여 주게 하고, 클라이언트는 그 코드를 제출한다.

```http
POST /lmsp/v1/pair
Content-Type: application/json
```

```json
{
  "client_name": "example-client",
  "pairing_code": "K7QD-4M2X",
  "scopes": ["inference"]
}
```

| 요청 필드 | 의미 |
| --- | --- |
| `client_name` | 클라이언트의 표시 이름. 사용자에게 보인다. |
| `pairing_code` | 사용자가 서비스에서 얻은 코드. |
| `scopes` | 요청하는 스코프의 선택적 목록. 기본값은 `["inference"]`. |

서비스는 토큰으로 답한다. `token_type`은 항상 `Bearer`이다.

```json
{
  "client_id": "cli_01J8MAT3W6X9B2D5F8H1K4N7QZ",
  "access_token": "lmsp_example_3f9a1c52e7d84b60",
  "token_type": "Bearer",
  "scopes": ["inference"]
}
```

그 뒤 클라이언트는 모든 요청에 `Authorization: Bearer <token>`을 보낸다.

- 페어링 코드는 일회용이어**야 하며** 5분 안에 만료되는 **것이 좋다**. 최소 40비트의 엔트로피를 담는 **것이 좋다**. 서비스는 실패한 시도에 속도 제한을 걸어**야 한다**. 틀렸거나 만료된 코드에는 `401`과 `unauthorized`로 응답한다.
- 토큰은 클라이언트마다 독립적이므로, 사용자는 다른 클라이언트에 영향을 주지 않고 한 클라이언트를 폐기할 수 있다. 서비스는 사용자가 페어링된 클라이언트를 나열하고 폐기할 수 있게 하는 **것이 좋다**.
- 클라이언트는 토큰을 운영체제 키체인이나 자격 증명 관리자에 보관하는 **것이 좋다**. 서비스는 각 토큰의 해시만 저장하는 **것이 좋다**.
- 토큰이 없거나, 올바르지 않거나, 폐기된 경우에는 `401`, `unauthorized`, `WWW-Authenticate: Bearer` 헤더로 응답한다. 토큰은 유효하지만 엔드포인트가 요구하는 스코프가 없으면 `403`과 `forbidden`으로 응답한다.

## 10.3 스코프 {#scopes}

권한은 별개의 스코프로 나뉜다. 모델 다운로드, 모델 삭제, 도구 실행이 inference 스코프에 얹혀 가는 일은 결코 없다.

| 스코프 | 허용하는 것 |
| --- | --- |
| `inference` | 모델 카탈로그 읽기, 응답과 작업 만들기, 클라이언트 자신의 작업 읽기와 취소. |
| `models:manage` | 모델 로드와 언로드. |
| `models:install` | 예약됨. 모델 다운로드와 삭제. |
| `tools:execute` | 예약됨. 서비스 측에서 도구 실행. |

작업과 저장된 응답은 그것을 만든 클라이언트에 속한다. 서비스는 다른 클라이언트의 요청에는 그것들이 없는 것처럼 응답하는 **것이 좋다**(`task_not_found` 또는 `response_not_found`).

## 10.4 브라우저 및 네트워크 보호 {#browser}

- 서비스는 기본적으로 교차 출처 브라우저 요청을 거부하고, 명시적으로 설정된 `Origin` 값만 허용해**야 한다**. 다른 `Origin`을 가진 요청에는 `403`과 `forbidden`으로 응답한다.
- 출처가 허용되면 서비스는 그 CORS 프리플라이트 요청에 응답하고, `Access-Control-Allow-Origin`에 `*`가 아니라 정확히 그 출처를 담아 보낸다.
- 서비스는 DNS 리바인딩을 막기 위해 `Host` 헤더를 검증해**야 한다**. 서비스가 담당하는 호스트 이름, 즉 루프백 이름과 주소, 그리고 LAN 모드를 위해 설정된 이름만 받아들인다. 그 밖의 값에는 `403`과 `forbidden`으로 응답한다.

## 10.5 LAN 모드 {#lan}

LAN 모드는 루프백 주소 밖에서도 수신 대기하는 것을 뜻한다.

- 서비스는 사용자가 명시적으로 켜지 않는 한 LAN 모드를 활성화해서는 **안 된다**.
- LAN 모드에서 서비스는 인증을 요구해**야 하며** TLS도 활성화하는 **것이 좋다**. 클라이언트는 사용자가 명시적으로 허용하지 않는 한 루프백이 아닌 주소로 일반 HTTP를 통해 토큰을 보내지 **않는 것이 좋다**.
- mDNS 광고는 LAN 모드이면서 사용자가 LAN 검색도 켠 경우에만 허용된다([3.2절](https://madeforagent.com/ko/lmsp/1.0/discovery.md#mdns)).

## 10.6 로깅과 개인정보 {#logging}

- 모델 경로, 로그, 프롬프트, 생성된 콘텐츠는 mDNS 광고에 포함되어서는 **안 된다**.
- 기본적으로 서비스는 메타데이터(시각, 엔드포인트, 상태 코드, id, 토큰 수, 소요 시간)만 기록하는 **것이 좋다**. 전체 프롬프트나 생성된 콘텐츠는 기록하지 **않는 것이 좋다**.
- 상태 점검 응답과 오류 상세 정보에는 모델 경로, 프롬프트, 액세스 토큰, 그 밖의 민감한 정보가 포함되어서는 **안 된다**.
