OAuth 2.0 액세스 토큰 NGINX 및 NGINX Plus로 검증하기
이 포스트에서는 NGINX 및 NGINX Plus가 OAuth 2.0 신뢰 당사자 역할을 수행하여 유효성 검사를 위해 IdP에 액세스 토큰을 보내고 유효성 검사 프로세스를 통과하는 요청만 Proxy 하는 방법을 설명합니다.
이 작업에 NGINX 및 NGINX Plus를 사용할 때의 다양한 이점과 짧은 시간 동안 유효성 검사 응답을 캐싱하여 사용자 경험을 개선할 수 있는 방법에 대해 논의합니다. NGINX Plus의 경우 NGINX Plus R18에서 도입된 것처럼 JavaScript 모듈로 Key-Value Store를 업데이트하여 NGINX Plus 인스턴스의 클러스터 전체에 캐시를 배포하는 방법도 보여줍니다.
X.509 클라이언트 인증서에서 HTTP 기본 인증에 이르기까지 API 호출 인증을 위한 다양한 옵션이 있습니다. 그러나 최근 몇 년 동안 OAuth 2.0 액세스 토큰의 형태가 사실상 표준이 되었습니다. 이는 클라이언트에서 API 서버로 전달되는 인증 자격 증명이며, 일반적으로 HTTP 헤더로 전달됩니다.
그러나 OAuth 2.0은 상호 연결 표준의 미로입니다. OAuth 2.0 인증 흐름을 발급, 제시 및 검증하는 프로세스는 종종 몇 가지 관련 표준에 의존합니다. 작성 시점에는 8개의 OAuth 2.0 표준이 있으며 OAuth 2.0 핵심 사양(RFC 6749)이 액세스 토큰의 형식을 지정하지 않기 때문에 액세스 토큰이 적절한 예입니다. 실제로는 일반적으로 사용되는 두 가지 형식이 있습니다.
- RFC 7519에 정의된 JSON Web Token(JWT)
- 인증된 클라이언트의 고유 식별자에 불과한 불투명한 토큰
인증 후 클라이언트는 보호된 리소스에 대한 액세스 권한을 얻기 위해 각 HTTP 요청과 함께 액세스 토큰을 제공합니다. 신뢰할 수 있는 ID 공급자(IdP)가 실제로 발급했고 만료되지 않았는지 확인하려면 액세스 토큰의 유효성 검사가 필요합니다. IdP는 자신이 발행하는 JWT에 암호로 서명하기 때문에 IdP에 대한 런타임 종속성 없이 JWT를 “오프라인”으로 검증할 수 있습니다. 일반적으로 JWT에는 확인할 수 있는 만료 날짜도 포함되어 있습니다. NGINX Plus auth_jwt 모듈은 오프라인 JWT 유효성 검사를 수행합니다.
반면에 불투명한 토큰은 토큰을 발행한 IdP로 다시 전송하여 유효성을 검사해야 합니다. 그러나 이것은 이전에 로그인한 세션을 여전히 활성 상태로 두지 않고 예를 들어 글로벌 로그아웃 작업의 일부로 IdP에서 이러한 토큰을 취소할 수 있다는 이점이 있습니다. 전역 로그아웃으로 인해 IdP로 JWT를 검증해야 할 수도 있습니다.
특별한 언급이 없는 한, 이 포스트의 정보는 NGINX Open Source와 NGINX Plus 모두에 적용됩니다. NGINX Plus에 대한 언급은 해당 제품에만 적용됩니다.
목차
1. 토큰 검사
2. NGINX auth_request 모듈을 사용하여 OAuth 2.0 토큰 유효성 검사
3. NGINX JavaScript Module을 사용한 auth_request 확장
3-1. 최적화 1: NGINX에 의한 캐싱
3-2. 최적화 2: NGINX Plus를 사용한 분산 캐싱
3-3. 최적화 3: 검사 응답에서 속성 추출
4. OAuth 2. 0 토큰 검사를 위한 Production 구성
5. OAuth 2.0 액세스 토큰 검증 요약
1. 토큰 검사
IdP로 액세스 토큰의 유효성을 검사하는 표준 방법을 토큰 검사라고 합니다. RFC 7662, OAuth 2.0 Token Introspection은 이제 신뢰 당사자가 IdP에 토큰을 제공하는 데 사용하는 JSON/REST 인터페이스를 설명하고 응답 구조를 설명하는 널리 지원되는 표준입니다. 다수의 선도적인 IdP 공급업체 및 클라우드 제공 업체에서 지원합니다.
사용되는 토큰 형식에 관계없이 각 Backend 서비스 또는 애플리케이션에서 액세스 토큰의 유효하지 않거나 예상치 못한 문자 유효성 검사를 수행하면 많은 중복 코드와 불필요한 처리가 발생합니다. 다양한 오류 조건과 Edge 사례를 고려해야 하며, 각 Backend 서비스에서 이를 수행하는 것은 구현의 불일치와 결과적으로 예측할 수 없는 사용자 경험을 위한 방법입니다. 각 Backend 서비스가 다음 오류 조건을 처리하는 방법을 고려하십시오.
- 액세스 토큰 누락
- 대용량 액세스 토큰
- 액세스 토큰의 유효하지 않거나 예상치 못한 문자
- 여러 액세스 토큰이 표시됨
- Backend 서비스 전반의 클럭 오차

토큰 유효성 검사를 수행하는 Backend 애플리케이션
2. NGINX auth_request 모듈을 사용하여 OAuth 2.0 토큰 유효성 검사
코드 중복과 그로 인한 문제를 방지하기 위해 NGINX를 사용하여 Backend 서비스를 대신하여 액세스 토큰의 유효성을 검사할 수 있습니다. 여기에는 여러 가지 이점이 있습니다.
- 클라이언트가 유효한 토큰을 제시한 경우에만 요청이 Backend 서비스에 도달합니다.
- 코드 변경 없이 액세스 토큰으로 기존 Backend 서비스를 보호할 수 있습니다.
- 모든 애플리케이션이 아닌 NGINX 인스턴스만 IdP에 등록해야 합니다.
- 누락되거나 잘못된 토큰을 포함하여 모든 오류 조건에 대해 동작이 일관됩니다.

Reverse Proxy로 토큰 유효성 검사를 수행하는 NGINX
NGINX가 하나 이상의 애플리케이션에 대한 Reverse Proxy 역할을 하므로 요청을 Backend에 Proxy 하기 전에 auth_request 모듈을 사용하여 IdP에 대한 API 호출을 트리거 할 수 있습니다. 잠시 후에 살펴보겠지만 다음 솔루션에는 근본적인 결함이 있지만 이후 섹션에서 확장할 auth_request 모듈의 기본 작업을 소개합니다.
server {
listen 80;
location / {
auth_request /_oauth2_token_introspection;
proxy_pass http://my_backend;
}
location = /_oauth2_token_introspection {
internal;
proxy_method POST;
proxy_set_header Authorization "bearer SecretForOAuthServer";
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_body "token=$http_apikey&token_hint=access_token";
proxy_pass https://idp.example.com/oauth/token;
}
}
auth_request 지시문(5 행)은 API 호출을 처리할 위치를 지정합니다. Backend로의 Proxy(6 행)는 auth_request 응답이 성공한 경우에만 발생합니다. auth_request 위치는 9 행에 정의되어 있습니다. 외부 클라이언트가 직접 액세스하지 못하도록 내부로 표시됩니다.
11~14 행은 토큰 검사 요청 형식을 준수하도록 요청의 다양한 속성을 정의합니다. 검사 요청에서 전송된 액세스 토큰은 14 행에 정의된 본문의 구성 요소입니다. 여기에서 token=$http_apikey는 클라이언트가 apikey 요청 헤더에 액세스 토큰을 제공해야 함을 나타냅니다. 물론 액세스 토큰은 요청의 모든 속성에 제공될 수 있으며, 이 경우 다른 NGINX 변수를 사용합니다.
3. NGINX JavaScript Module을 사용한 auth_request 확장
앞서 언급한 바와 같이, 이러한 방식으로 auth_request 모듈을 사용하는 것은 완전한 솔루션이 아닙니다. auth_request 모듈은 HTTP 상태 코드를 사용하여 성공 여부를 결정합니다(2xx = 좋음, 4xx = 나쁨). 그러나 OAuth 2.0 토큰 검사 응답은 JSON 개체에서 성공 또는 실패를 인코딩하고 두 경우 모두 HTTP 상태 코드 200(OK)을 반환합니다.

유효한 토큰에 대한 토큰 검사 응답의 JSON 형식
필요한 것은 auth_request 모듈이 해당 응답을 올바르게 해석할 수 있도록 IdP의 내부 검사 응답을 적절한 HTTP 상태 코드로 변환하는 JSON Parser입니다.
고맙게도 JSON 구문 분석은 NGINX JavaScript 모듈(njs)의 사소한 작업입니다. 따라서 토큰 검사 요청을 수행하기 위해 location 블록을 정의하는 대신 auth_request 모듈에 JavaScript 함수를 호출하도록 지시합니다.
Note: 이 솔루션을 사용하려면 nginx.conf의 load_module 지시문을 사용하여 JavaScript 모듈을 동적 모듈로 로드해야 합니다.
js_import oauth2.js; # Location of JavaScript code
server {
listen 80;
location / {
auth_request /_oauth2_token_introspection;
proxy_pass http://my_backend;
}
location = /_oauth2_token_introspection {
internal;
js_content oauth2.introspectAccessToken;
}
13행의 js_content 지시문은 JavaScript 함수 introspectAccessToken을 auth_request 핸들러로 지정합니다. 핸들러 함수는 oauth2.js에 정의되어 있습니다.
function introspectAccessToken(r) {
r.subrequest("/_oauth2_send_request",
function(reply) {
if (reply.status == 200) {
var response = JSON.parse(reply.responseBody);
if (response.active == true) {
r.return(204); // Token is valid, return success code
} else {
r.return(403); // Token is invalid, return forbidden code
}
} else {
r.return(401); // Unexpected response, return 'auth required'
}
}
);
}
export default { introspectAccessToken }
introspectAccessToken 함수는 아래 구성 Snippet에 정의된 다른 위치(/oauth2_send_request)에 대한 HTTP 하위 요청(2 행)을 만듭니다. 그런 다음 JavaScript 코드는 응답(5 행)을 구문 분석하고 활성 필드의 값을 기반으로 적절한 상태 코드를 auth_request 모듈로 다시 보냅니다. 유효한(활성) 토큰은 HTTP 204(콘텐츠 없음)를 반환하고 잘못된 토큰은 HTTP 403(금지됨)을 반환합니다. 오류 조건은 오류를 유효하지 않은 토큰과 구별할 수 있도록 HTTP 401(권한 없음)을 반환합니다.
Note: 이 코드는 개념 증명용으로만 제공되며 생산 품질이 아닙니다. 포괄적인 오류 처리 및 로깅이 포함된 완벽한 솔루션은 아래에 제공됩니다.
2 행에 정의된 하위 요청 대상 위치는 원래 auth_request 구성과 매우 유사합니다.
location /_oauth2_send_request {
internal;
proxy_method POST;
proxy_set_header Authorization "Bearer SecretForOAuthServer";
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_body "token=$http_apikey&token_hint=access_token";
proxy_pass https://idp.example.com/oauth/token/introspect;
}
토큰 검사 요청을 구성하기 위한 모든 구성은 /_oauth2_send_request 위치에 포함되어 있습니다. 인증(19 행), 액세스 토큰 자체(21 행) 및 토큰 검사 Endpoint의 URL(22 행)은 일반적으로 유일하게 필요한 구성 항목입니다. IdP가 이 NGINX 인스턴스의 토큰 검사 요청을 수락하려면 인증이 필요합니다. OAuth 2.0 Token Introspection 사양은 인증을 요구하지만 방법을 지정하지는 않습니다. 이 예에서는 Authorization 헤더에 Bearer 토큰을 사용합니다.
이 구성을 사용하면 NGINX가 요청을 수신하면 이를 JavaScript 모듈로 전달하여 IdP에 대한 토큰 검사 요청을 수행합니다. IdP의 응답을 검사하고 활성 필드가 true이면 인증이 성공한 것으로 간주됩니다. 이 솔루션은 NGINX로 OAuth 2.0 토큰 검사를 수행하는 작고 효율적인 방법이며 다른 인증 API에 쉽게 적용할 수 있습니다.
또한 일반적으로 토큰 검사의 가장 큰 문제는 모든 HTTP 요청에 지연 시간을 추가한다는 것입니다. 이는 IdP가 호스팅 된 솔루션 또는 클라우드 공급자인 경우 중요한 문제가 될 수 있습니다. NGINX 및 NGINX Plus는 검사 응답을 캐싱하여 이러한 단점을 개선할 수 있습니다.
3-1. 최적화 1: NGINX에 의한 캐싱
OAuth 2.0 토큰 검사는 JSON/REST Endpoint에서 IdP에 의해 제공되므로 표준 응답은 HTTP 상태 200의 JSON 본문입니다. 이 응답이 액세스 토큰에 대해 Key가 지정되면 캐시 가능성이 높아집니다.

유효한 토큰에 대한 완전한 토큰 검사 응답
다음에 동일한 액세스 토큰이 표시될 때 NGINX가 IdP에 대한 API 호출을 수행하는 대신 캐시된 자체 검사 응답을 제공하도록 각 액세스 토큰에 대한 검사 응답의 복사본을 캐시하도록 NGINX를 구성할 수 있습니다. 이렇게 하면 후속 요청에 대한 전체 지연 시간이 크게 향상됩니다. 캐시 된 응답이 사용되는 시간을 제어하여 만료되었거나 최근에 해지된 액세스 토큰을 수락할 위험을 완화할 수 있습니다. 예를 들어, API 클라이언트가 일반적으로 짧은 시간 동안 여러 API 호출을 버스트 하는 경우 캐시 유효성이 10초면 사용자 경험에서 측정 가능한 개선을 제공하기에 충분할 수 있습니다.
캐싱은 캐시에 대한 디스크의 디렉토리(내부 검사 응답)와 키에 대한 공유 메모리 영역(액세스 토큰)을 지정하여 활성화합니다.
proxy_cache_path /var/cache/nginx/oauth keys_zone=token_responses:1m max_size=2m;
proxy_cache_path 지시문은 필요한 저장소를 할당합니다. 검사 응답을 위한 /var/cache/nginx/oauth와 키를 위한 token_responses라는 메모리 영역입니다. http 컨텍스트에서 구성되므로 server 및 location 블록 외부에 나타납니다. 그러면 토큰 검사 응답이 처리되는 location 블록 내에서 캐싱 자체가 활성화됩니다.
location /_oauth2_send_request {
internal;
proxy_method POST;
proxy_set_header Authorization "Bearer SecretForOAuthServer";
proxy_set_header Content-Type "application/x-www-form-urlencoded";
proxy_set_body "token=$http_apikey&token_hint=access_token";
proxy_pass https://idp.example.com/oauth/token/introspect;
proxy_cache token_responses; # Enable caching
proxy_cache_key $http_apikey; # Cache for each access token
proxy_cache_lock on; # Duplicate tokens must wait
proxy_cache_valid 200 10s; # How long to use each response
proxy_ignore_headers Cache-Control Expires Set-Cookie;
}
proxy_cache 지시문(26 행)을 사용하여 이 위치에 대해 캐싱을 활성화합니다. 기본적으로 NGINX는 URI를 기반으로 캐시 하지만 우리의 경우에는 apikey 요청 헤더(27 행)에 표시된 액세스 토큰을 기반으로 응답을 캐시 하려고 합니다.
28 행에서 proxy_cache_lock 지시문을 사용하여 동시 요청이 동일한 캐시 키로 도착하면 다른 요청에 응답하기 전에 첫 번째 요청이 캐시를 채울 때까지 기다려야 한다고 NGINX에 알립니다. proxy_cache_valid 지시문(29 행)은 NGINX에 검사 응답을 캐시 하는 기간을 알려줍니다. 이 지시문이 없으면 NGINX는 IdP가 보낸 캐시 제어 헤더에서 캐싱 시간을 결정합니다. 그러나 이것이 항상 신뢰할 수 있는 것은 아니므로 응답을 캐시 하는 방법에 영향을 미칠 수 있는 헤더를 무시하도록 NGINX에 지시하기도 합니다(30 행).
이제 캐싱이 활성화되면 액세스 토큰을 제공하는 클라이언트는 10초마다 한 번씩 토큰 검사 요청을 만드는 지연 시간 비용만 겪게 됩니다.
3-2. 최적화 2: NGINX Plus를 사용한 분산 캐싱
콘텐츠 캐싱과 토큰 검사를 결합하는 것은 보안에 미치는 영향은 미미하지만 전체 애플리케이션 성능을 향상시키는 매우 효과적인 방법입니다. 그러나 NGINX가 분산 방식(예: 여러 데이터 센터, 클라우드 플랫폼 또는 Active-Active 클러스터)으로 배포되는 경우 캐시 된 토큰 검사 응답은 검사 요청을 수행한 NGINX 인스턴스에서만 사용할 수 있습니다.
NGINX Plus를 사용하면 메모리 내 Key‑Value Store인 keyval 모듈을 사용하여 토큰 검사 응답을 캐시 할 수 있습니다. 또한 zone_sync 모듈을 사용하여 NGINX Plus 인스턴스 클러스터 전체에서 이러한 응답을 동기화할 수도 있습니다. 즉, 어떤 NGINX Plus 인스턴스가 토큰 검사 요청을 수행했는지에 관계없이 클러스터의 모든 NGINX Plus 인스턴스에서 응답을 사용할 수 있습니다.
Note: 런타임 상태 공유를 위한 zone_sync 모듈의 구성은 이 포스트의 범위를 벗어납니다.
NGINX Plus R18 이상에서는 keyval 지시문에 선언된 변수를 수정하여 Key‑Value Store를 업데이트할 수 있습니다. JavaScript 모듈은 모든 NGINX 변수에 액세스할 수 있으므로 응답을 처리하는 동안 검사 응답을 Key‑Value Store에 채울 수 있습니다.
NGINX 파일 시스템 캐시와 마찬가지로 Key‑Value Store는 저장소를 지정하여 활성화됩니다. 이 경우에는 키(액세스 토큰)와 값(검사 응답)을 저장하는 메모리 영역입니다.
keyval_zone zone=access_tokens:4m timeout=10s sync;
keyval $http_apikey $token_data zone=access_tokens;
keyval_zone 지시문에 대한 timeout 매개변수를 사용하여 auth_request_cache.conf의 29 행에서와 같이 캐시 된 응답에 대해 동일한 10초 유효 기간을 지정하여 NGINX Plus 클러스터의 각 구성원이 만료 시 응답을 독립적으로 제거합니다. 2 행은 각 항목에 대한 Key-Value 쌍을 지정합니다. 키는 apikey 요청 헤더에 제공된 액세스 토큰이고 값은 $token_data 변수에 의해 평가되는 자체 검사 응답입니다.
이제 apikey 요청 헤더를 포함하는 각 요청에 대해 $token_data 변수는 이전 토큰 검사 응답(있는 경우)으로 채워집니다. 따라서 이미 토큰 검사 응답이 있는지 확인하기 위해 JavaScript 코드를 업데이트합니다.
function introspectAccessToken(r) {
if (r.variables.token_data) {
tokenResult(r); // Existing response in key-value store so do validation
} else {
r.subrequest("/_oauth2_send_request",
function(reply) {
if (reply.status == 200) {
r.variables.token_data = reply.responseBody; // Create entry
tokenResult(r); // Do validation of response
} else {
r.return(401); // Unexpected response, return auth-required
}
}
);
}
}
2 행은 이 액세스 토큰에 대한 Key‑Value Store 항목이 이미 있는지를 테스트합니다. 자체 검사 응답을 얻을 수 있는 두 가지 경로(Key‑Value Store 또는 자체 검사 응답에서)가 있으므로 유효성 검사 논리를 다음과 같은 별도의 함수인 tokenResult로 이동합니다.
function tokenResult(r) {
var response = JSON.parse(r.variables.token_data);
if (response.active) {
r.return(204);
} else {
r.return(401);
}
}
이제 각 토큰 검사 응답이 Key‑Value Store에 저장되고 NGINX Plus 클러스터의 다른 모든 구성원 간에 동기화됩니다. 다음 예제에서는 유효한 액세스 토큰이 포함된 간단한 HTTP 요청과 Key‑Value Store의 콘텐츠를 표시하기 위해 NGINX Plus API에 대한 쿼리를 보여줍니다.
$ curl -IH "apikey: tQ7AfuEFvI1yI-XNPNhjT38vg_reGkpDFA" http://localhost/
HTTP/1.1 200 OK
Date: Wed, 24 Apr 2019 17:41:34 GMT
Content-Type: application/json
Content-Length: 612
$ curl http://localhost/api/4/http/keyvals/access_tokens
{"tQ7AfuEFvI1yI-XNPNhjT38vg_reGkpDFA":"{\"active\":true}"}
Key‑Value Store는 JSON 형식 자체를 사용하므로 토큰 검사 응답에는 따옴표에 이스케이프가 자동으로 적용됩니다.
3-3. 최적화 3: 검사 응답에서 속성 추출
OAuth 2.0 토큰 검사의 유용한 기능은 응답에 활성 상태 외에 토큰에 대한 정보가 포함될 수 있다는 것입니다. 이러한 정보에는 토큰 만료 날짜 및 연결된 사용자의 속성(사용자 이름, 이메일 주소 등)이 포함됩니다.

토큰 속성을 사용한 토큰 검사 응답
이 추가 정보는 매우 유용할 수 있습니다. 로그에 기록하거나 세분화된 액세스 제어 정책을 구현하는 데 사용하거나 Backend 애플리케이션에 제공할 수 있습니다. 이러한 각 속성을 성공적인(HTTP 204) 응답과 함께 추가 응답 헤더로 전송하여 auth_request 모듈로 내보낼 수 있습니다.
function tokenResult(r) {
var response = JSON.parse(r.variables.token_data);
if (response.active) {
// Convert all members of the response into response headers
for (var p in response) {
if (!response.hasOwnProperty(p)) continue;
r.log("OAuth2 Token-" + p + ": " + response[p]);
r.headersOut['Token-' + p] = response[p];
}
r.status = 204;
r.sendHeader();
r.finish();
} else {
r.return(401);
}
}
자체 검사 응답(23 행)의 각 속성을 반복하고 이를 응답 헤더로 auth_request 모듈에 다시 보냅니다. 표준 응답 헤더(26 행)와의 충돌을 피하기 위해 각 헤더 이름에는 Token- 접두사가 붙습니다. 이제 이러한 응답 헤더를 NGINX 변수로 변환하여 일반 구성의 일부로 사용할 수 있습니다.
location / {
auth_request /_oauth2_token_introspection;
auth_request_set $username $sent_http_token_username;
proxy_set_header X-Username $username;
proxy_pass http://my_backend;
}
이 예에서는 사용자 이름 속성을 새 변수인 $username으로 변환합니다(11 행). auth_request_set 지시문을 사용하면 토큰 검사 응답의 컨텍스트를 현재 요청의 컨텍스트로 내보낼 수 있습니다. 각 속성에 대한 응답 헤더(JavaScript 코드에 의해 추가됨)는 $sent_http_token_attribute로 제공됩니다. 그런 다음 12 행에는 $username에 대한 값이 Backend로 Proxy 되는 요청 헤더로 포함됩니다. 토큰 검사 응답에서 반환된 속성에 대해 이 구성을 반복할 수 있습니다.

토큰 검사 응답에서 Proxy된 요청으로 특성 내보내기
4. OAuth 2.0 토큰 검사를 위한 Production 구성
위의 코드 및 구성 예제는 기능적이며 개념 증명 테스트 또는 특정 사용 사례에 대한 사용자 정의에 적합합니다. Production 사용을 위해 추가 오류 처리, 로깅 및 유연한 구성을 강력히 권장합니다. GitHub Repo에서 NGINX 및 NGINX Plus에 대한 보다 강력하고 자세한 구현을 찾을 수 있습니다.
5. OAuth 2.0 액세스 토큰 검증 요약
이 포스트에서는 JavaScript 모듈과 함께 NGINX auth_request 모듈을 사용하여 클라이언트 요청에 대해 OAuth 2.0 토큰 검사를 수행하는 방법을 보여주었습니다. 또한 캐싱으로 해당 솔루션을 확장하고 NGINX 구성에서 사용하기 위해 검사 응답에서 속성을 추출했습니다.
또한 NGINX Plus Key-Value Store를 검사 응답을 위한 분산 캐시로 사용하여 NGINX Plus 인스턴스 클러스터 전체에 Production 배포에 적합한 방법도 설명했습니다.
NGINX Plus로 OAuth 2.0 토큰 검사를 직접 사용해 보거나 테스트해 보려면 지금 30일 무료 평가판을 신청하거나 사용 사례에 대해 최신 소식을 빠르게 전달받고 싶으시면 아래 뉴스레터를 구독하세요.
댓글을 달려면 로그인해야 합니다.