REST API 토큰 기반 인증


122

인증이 필요한 REST API를 개발 중입니다. 인증 자체가 HTTP를 통한 외부 웹 서비스를 통해 발생하기 때문에 인증 서비스를 반복적으로 호출하지 않도록 토큰을 분배 할 것이라고 생각했습니다. 첫 번째 질문에 깔끔하게 연결됩니다.

클라이언트가 각 요청에서 HTTP 기본 인증을 사용하고 인증 서비스 서버 측에 대한 호출을 캐싱하도록 요구하는 것보다 더 좋은가요?

기본 인증 솔루션은 콘텐츠 요청이 시작되기 전에 서버에 대한 전체 왕복이 필요하지 않다는 장점이 있습니다. 토큰은 잠재적으로 범위가 더 유연 할 수 있지만 (즉, 특정 리소스 또는 작업에 대한 권한 만 부여), 내 간단한 사용 사례보다 OAuth 컨텍스트에 더 적합 해 보입니다.

현재 토큰은 다음과 같이 획득됩니다.

curl -X POST localhost/token --data "api_key=81169d80...
                                     &verifier=2f5ae51a...
                                     &timestamp=1234567
                                     &user=foo
                                     &pass=bar"

api_key, timestampverifier모든 요청에 의해 요구된다. "검증 자"는 다음에 의해 반환됩니다.

sha1(timestamp + api_key + shared_secret)

내 의도는 알려진 당사자의 통화 만 허용하고 통화가 그대로 재사용되는 것을 방지하는 것입니다.

이것으로 충분합니까? 언더 킬? 지나침?

토큰을 가지고 클라이언트는 리소스를 얻을 수 있습니다.

curl localhost/posts?api_key=81169d80...
                    &verifier=81169d80...
                    &token=9fUyas64...
                    &timestamp=1234567

가능한 가장 간단한 호출의 경우 이것은 끔찍하게 장황하게 보입니다. shared_secret유언장이 (최소한) iOS 응용 프로그램에 포함되어 있다는 점을 고려할 때이 응용 프로그램에서 추출 할 수 있다고 가정 할 때 잘못된 보안 감각 이상의 것을 제공합니까?


2
대신 SHA1 (타임 스탬프 + API_KEY + shard_secret) 더 나은 보안 해싱을위한 HMAC (shared_secret, timpestamp + API_KEY)를 사용한다 사용 en.wikipedia.org/wiki/Hash-based_message_authentication_code
미구엘 A. 카라 스코

@ MiguelA.Carrasco 그리고 2017 년에 bCrypt가 새로운 해싱 도구라는 합의가있는 것 같습니다.
Shawn

답변:


94

모든 것을 분리하고 각 문제를 분리하여 해결하겠습니다.

입증

인증의 경우 baseauth는 프로토콜 수준에서 성숙한 솔루션이라는 장점이 있습니다. 이것은 많은 "나중에 발생할 수있는 " 문제가 이미 해결 되었음을 의미 합니다. 예를 들어 BaseAuth를 사용하면 사용자 에이전트는 암호가 암호라는 것을 알고 있으므로 캐시하지 않습니다.

인증 서버로드

서버에서 인증을 캐싱하는 대신 사용자에게 토큰을 분배하는 경우에도 동일한 작업을 수행합니다. 인증 정보 캐싱. 유일한 차이점은 캐싱에 대한 책임을 사용자에게 돌리는 것입니다. 이것은 이득이없는 사용자에게는 불필요한 노동처럼 보이므로 제안한대로 서버에서 투명하게 처리하는 것이 좋습니다.

전송 보안

SSL 연결을 사용할 수 있다면 그게 전부입니다. 연결은 안전합니다 *. 실수로 여러 번 실행되는 것을 방지하려면 여러 URL을 필터링하거나 사용자에게 URL에 임의의 구성 요소 ( "nonce")를 포함하도록 요청할 수 있습니다.

url = username:key@myhost.com/api/call/nonce

이것이 불가능하고 전송 된 정보가 비밀이 아니라면 토큰 접근 방식에서 제안한대로 해시로 요청을 보호하는 것이 좋습니다. 해시가 보안을 제공하므로 사용자에게 해시를 baseauth 비밀번호로 제공하도록 지시 할 수 있습니다. 견고성을 높이기 위해 재생 공격을 방지하기 위해 타임 스탬프 대신 임의의 문자열을 "nonce"로 사용하는 것이 좋습니다 (동일한 시간에 두 개의 합법적 인 요청이 이루어질 수 있음). 별도의 "공유 비밀"및 "api 키"필드를 제공하는 대신 api 키를 공유 비밀로 사용한 다음 레인보우 테이블 공격을 방지하기 위해 변경되지 않는 솔트를 사용할 수 있습니다. 사용자 이름 필드는 인증의 일부이기 때문에 임시 값을 입력하기에 좋은 장소처럼 보입니다. 이제 다음과 같은 깨끗한 호출이 있습니다.

nonce = generate_secure_password(length: 16);
one_time_key = nonce + '-' + sha1(nonce+salt+shared_key);
url = username:one_time_key@myhost.com/api/call

이것이 약간 힘들다는 것은 사실입니다. 이는 SSL과 같은 프로토콜 수준 솔루션을 사용하지 않기 때문입니다. 따라서 사용자에게 일종의 SDK를 제공하는 것이 좋을 수 있습니다. 그래야 최소한 사용자가 직접 검토 할 필요가 없습니다. 이런 식으로해야하는 경우 보안 수준이 적절하다고 생각합니다.

안전한 비밀 저장소

그것은 당신이 저지하려는 사람에 달려 있습니다. 사용자의 전화에 액세스 할 수있는 사람들이 사용자의 이름으로 REST 서비스를 사용하지 못하도록 차단하는 경우 대상 OS에서 일종의 키링 API를 찾고 SDK (또는 구현 자)가이를 저장하도록하는 것이 좋습니다. 거기에 열쇠. 그것이 가능하지 않다면, 적어도 그것을 암호화하고 암호화 된 데이터와 암호화 키를 별도의 장소에 저장함으로써 비밀을 얻는 것을 조금 더 어렵게 만들 수 있습니다.

다른 소프트웨어 공급 업체가 대체 클라이언트의 개발을 방지하기 위해 API 키를 얻지 못하도록하려는 경우 암호화 및 저장 분리 방식 만 거의 작동합니다. 이것은 화이트 박스 암호화이며 현재까지 아무도이 클래스의 문제에 대해 진정으로 안전한 해결책을 제시하지 못했습니다. 당신이 할 수있는 최소한은 여전히 ​​각 사용자에 대해 단일 키를 발행하여 남용 된 키를 금지 할 수 있도록하는 것입니다.

(*) 편집 : SSL 연결 을 확인 하기 위한 추가 단계를 거치지 않고 는 더 이상 안전한 것으로 간주되지 않아야 합니다.


cmc, 모든 좋은 점과 훌륭한 음식에 감사드립니다. 결국 S3 REST API 인증 메커니즘 처럼 위에서 설명한 것과 유사한 토큰 / HMAC 접근 방식을 취했습니다 .
cantlin

서버에 토큰을 캐시하면 기본적으로 좋은 이전 세션 ID와 동일하지 않습니까? 세션 ID는 수명이 짧으며 모든 요청에서 DB에 도달하지 않도록 빠른 캐시 저장소 (구현하는 경우)에도 연결됩니다. 진정한 RESTful 및 상태 비 저장 디자인에는 세션이 없어야하지만 토큰을 ID로 사용하고 DB에 계속 연결하는 경우 대신 세션 ID를 사용하는 것이 더 낫지 않을까요? 또는 진정한 상태 비 저장 설계를 위해 전체 세션 데이터에 대해 암호화되거나 서명 된 정보가 포함 된 JSON 웹 토큰을 사용할 수 있습니다.
JustAMartin 2017 년

16

순수한 RESTful API는 기본 프로토콜 표준 기능을 사용해야합니다.

  1. HTTP의 경우 RESTful API는 기존 HTTP 표준 헤더를 준수해야합니다. 새 HTTP 헤더를 추가하면 REST 원칙을 위반합니다. 휠을 재발 명하지 말고 상태 응답 코드, 헤더 등을 포함하여 HTTP / 1.1 표준의 모든 표준 기능을 사용하십시오. RESTFul 웹 서비스는 HTTP 표준을 활용하고 의존해야합니다.

  2. RESTful 서비스는 STATELESS 여야합니다. 서버에서 이전 REST 요청의 상태를 기억하려는 토큰 기반 인증과 같은 모든 트릭은 REST 원칙을 위반합니다. 다시 말하지만 이것은 필수입니다. 즉, 웹 서버가 서버에 모든 종류의 세션을 설정하기 위해 서버에 요청 / 응답 컨텍스트 관련 정보를 저장하는 경우 웹 서비스는 Stateless가 아닙니다. 상태 비 저장이 아니면 RESTFul이 아닙니다.

결론 : 인증 / 승인 목적으로 HTTP 표준 권한 헤더를 사용해야합니다. 즉, 인증해야하는 각 후속 요청에 HTTP 권한 / 인증 헤더를 추가해야합니다. REST API는 HTTP 인증 체계 표준을 따라야합니다.이 헤더의 형식 지정 방법에 대한 세부 사항은 RFC 2616 HTTP 1.1 표준 – 섹션 14.8 RFC 2616 승인 및 RFC 2617 HTTP 인증 : 기본 및 다이제스트 액세스 인증에 정의되어 있습니다. .

Cisco Prime Performance Manager 애플리케이션을위한 RESTful 서비스를 개발했습니다. 여기에서 RESTFul API 준수에 대한 자세한 내용을 보려면 해당 애플리케이션 용으로 작성한 REST API 문서를 Google에서 검색 하십시오 . 이 구현에서는 HTTP "Basic"인증 체계를 사용하기로 선택했습니다. -해당 REST API 문서의 버전 1.5 이상을 확인하고 문서에서 인증을 검색합니다.


8
"새 HTTP 헤더를 추가하는 것은 REST 원칙에 위배됩니다." 어떻게 그렇게합니까? 그리고 당신이 그것에 있다면 당신은 특정 기간 후에 만료되는 암호와 특정 기간 후에 만료되는 토큰의 차이점 (원칙과 관련하여)이 정확히 무엇인지 설명해 주실 수 있습니다.
더 나은 올리버

6
사용자 이름 + 암호는 모든 요청에 ​​대해 클라이언트와 서버간에 교환되는 토큰 (!)입니다. 이 토큰은 서버에서 유지되며 수명이 있습니다. 암호가 만료되면 새 암호를 얻어야합니다. "토큰"을 "서버 세션"과 연관시키는 것 같지만 잘못된 결론입니다. 구현 세부 사항이기 때문에 관련이 없습니다. 사용자 이름 / 암호 이외의 토큰을 상태 저장으로 분류하는 것은 순전히 인공적인 것입니다.
더 나은 올리버

1
원래 질문의 일부인 기본 인증을 통해 RESTful을 구현하는 이유를 동기 부여해야한다고 생각합니다. 코드가 포함 된 좋은 예제를 링크 할 수도 있습니다. 이 주제의 초보자로서 이론은 많은 좋은 자원으로 충분히 명확 해 보이지만 구현 방법은 그렇지 않으며 예제는 복잡합니다. 수천 번 수행 된 것을 적시에 구현하기 위해 사용자 지정 코딩이 필요한 것처럼 보이는 것이 실망 스럽습니다.
JPK

13
-1 "서버에서 이전 REST 요청의 상태를 기억하려는 토큰 기반 인증과 같은 모든 트릭은 REST 원칙을 위반합니다." 토큰 기반 인증은 이전 REST 요청의 상태와 관련이 없으며 REST의 상태 비 저장을 위반하지 않습니다 .
Kerem Baydoğan 2016 년

1
그래서 이것에 따르면 JSON 웹 토큰은 사용자의 상태 (클레임)를 저장할 수 있기 때문에 REST 위반입니까? 어쨌든 저는 REST를 위반하고 좋은 오래된 세션 ID를 "토큰"으로 사용하는 것을 선호하지만 초기 인증은 사용자 이름 + 패스로 수행되고 공유 비밀 및 매우 짧은 타임 스탬프를 사용하여 서명되거나 암호화됩니다 (누구나 재생을 시도하면 실패 함 그). "엔터프라이즈 용"애플리케이션에서는 세션 이점을 버리는 것이 어렵 기 때문에 (거의 모든 요청에 ​​필요한 일부 데이터에 대해 데이터베이스를 사용하지 않음) 때때로 진정한 상태 비 저장을 희생해야합니다.
JustAMartin

2

웹에서 상태 저장 프로토콜은 모든 요청에 ​​대해 브라우저와 서버 (쿠키 헤더 또는 URI 재 작성을 통해)간에 교환되는 임시 토큰을 기반으로합니다. 이 토큰은 일반적으로 서버 측에서 생성되며 특정 수명이있는 불투명 한 데이터 조각이며 특정 웹 사용자 에이전트를 식별하는 유일한 목적이 있습니다. 즉, 토큰은 임시적이며 해당 대화 기간 동안 웹 서버가 클라이언트 사용자 에이전트를 대신하여 유지해야하는 상태가됩니다. 따라서 이러한 방식으로 토큰을 사용하는 통신은 STATEFUL입니다. 그리고 클라이언트와 서버 간의 대화가 STATEFUL이면 RESTful이 아닙니다.

사용자 이름 / 암호 (Authorization 헤더에 전송 됨)는 일반적으로 사용자를 식별 할 목적으로 데이터베이스에 유지됩니다. 때때로 사용자는 다른 응용 프로그램을 의미 할 수 있습니다. 그러나 사용자 이름 / 암호는 특정 웹 클라이언트 사용자 에이전트를 식별하기위한 것이 아닙니다 . 웹 서버 프런트 엔드가 STATE 정보를 생성하거나 유지하지 않기 때문에 Authorization 헤더의 사용자 이름 / 암호를 사용하는 웹 에이전트와 서버 간의 대화 (HTTP Basic Authorization 뒤)는 STATELESS입니다.특정 웹 클라이언트 사용자 에이전트를 대신하여 무엇이든. REST에 대한 나의 이해를 바탕으로 프로토콜은 클라이언트와 서버 간의 대화가 STATELESS 여야한다고 명확하게 명시합니다. 따라서 진정한 RESTful 서비스를 원하면 모든 단일 호출에 대해 Authorization 헤더에 사용자 이름 / 암호 (이전 게시물에서 언급 한 RFC 참조)를 사용해야합니다. 토큰 유형 (예 : 웹 서버에서 생성 된 세션 토큰)이 아닙니다. , 권한 부여 서버에서 생성 된 OAuth 토큰 등).

여러 호출 된 REST 제공 업체가 OAuth1 또는 OAuth2 accept-tokens와 같은 토큰을 사용하여 HTTP 헤더에 "Authorization : Bearer"로 전달됨을 이해합니다. 그러나 RESTful 서비스에 이러한 토큰을 사용하는 것은 REST가 수용하는 진정한 STATELESS를 위반하는 것으로 보입니다. 이러한 토큰은 해당 웹 클라이언트 / 서버 대화의 유효한 기간 동안 특정 웹 클라이언트 사용자 에이전트를 식별하기 위해 서버 측에서 생성 / 유지 되는 임시 데이터 조각 이기 때문 입니다. 따라서 STATELESS 프로토콜의 참 의미를 고수하려면 이러한 OAuth1 / 2 토큰을 사용하는 모든 서비스를 REST라고 부르지 않아야합니다.

루벤스

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.