RESTful 웹 서비스-다른 서비스의 요청을 인증하는 방법은 무엇입니까?


117

사용자뿐만 아니라 다른 웹 서비스 및 응용 프로그램도 액세스해야하는 RESTful 웹 서비스를 설계하고 있습니다. 들어오는 모든 요청을 인증해야합니다. 모든 통신은 HTTPS를 통해 이루어집니다. 사용자 인증은 서비스에서 제공 하는 / session 리소스에 사용자 이름과 암호 (SSL 연결을 통해)를 게시하여 획득 한 인증 토큰을 기반으로 작동 합니다.

웹 서비스 클라이언트의 경우 클라이언트 서비스 뒤에 최종 사용자없습니다 . 요청은 예약 된 작업, 이벤트 또는 기타 컴퓨터 작업에 의해 시작됩니다. 연결 서비스 목록은 미리 알려져 있습니다 (분명히 생각합니다). 다른 (웹) 서비스에서 오는 이러한 요청을 어떻게 인증해야합니까? 인증 프로세스가 이러한 서비스에 대해 구현하기 쉬운 것이지만 보안 비용이 들지 않기를 바랍니다. 이와 같은 시나리오의 표준 및 모범 사례는 무엇입니까?

내가 생각할 수있는 (또는 나에게 제안 된) 옵션 :

  1. 클라이언트 서비스가 "가짜"사용자 이름과 암호를 사용하도록하고 사용자와 동일한 방식으로 인증합니다. 이 옵션이 마음에 들지 않습니다.

  2. 클라이언트 서비스에 대한 영구 응용 프로그램 ID를 할당합니다. 응용 프로그램 키도 가능합니다. 내가 이해하는 한 이것은 사용자 이름 + 비밀번호를 갖는 것과 동일합니다. 이 ID와 키를 사용하여 각 요청을 인증하거나 인증 토큰을 만들어 추가 요청을 인증 할 수 있습니다. 어느 쪽이든 애플리케이션 ID와 키를 얻을 수있는 사람은 누구나 클라이언트를 가장 할 수 있기 때문에이 옵션을 좋아하지 않습니다.

  3. 이전 옵션에 IP 주소 확인을 추가 할 수 있습니다. 이것은 가짜 요청을 수행하는 것을 더 어렵게 만듭니다.

  4. 클라이언트 인증서. 내 인증 기관을 설정하고 루트 인증서를 만들고 클라이언트 서비스에 대한 클라이언트 인증서를 만듭니다. 그러나 몇 가지 문제가 떠 오릅니다. a) 사용자가 인증서없이 인증을 계속하도록 허용하는 방법 및 b) 클라이언트 서비스 관점에서이 시나리오를 구현하는 것이 얼마나 복잡합니까?

  5. 다른 것-거기에 다른 해결책이 있어야합니까?

내 서비스는 Java에서 실행되지만 기본 원칙에 더 관심이 있고 구현 세부 사항에 그다지 관심이 없기 때문에 어떤 특정 프레임 워크를 기반으로 할 것인지에 대한 정보를 의도적으로 생략했습니다. 기본 프레임 워크에 관계없이 구현이 가능합니다. 그러나 나는이 주제에 대해 약간의 경험이 없기 때문에 실제 구현에 대한 구체적인 팁과 예제 (예 : 유용한 타사 라이브러리, 기사 등)도 많은 도움이 될 것입니다.


내가 제안 할 수 있다면, 빅 박스 웹 사이트 서비스에 익숙해지고 원하는 것을 골라 선택하십시오. 또한 사용자는 다른 RESTful 서비스의 모범 사례와 유사점을 찾을 수 있습니다.
Yzmir Ramirez

비슷한 주제를 다루는 또 다른 질문 (거의 2 년 전)을 찾았습니다. stackoverflow.com/questions/1138831/…
Tommi

서비스 (웹 및 기타 서비스)가 호스팅되는 OS는 무엇입니까? 동일한 인프라의 일부인 서버에서 실행되고 있습니까?
Anders Abel

OS는 다를 수 있습니다 : Win, * nix 등. 그리고 클라이언트 서비스는 내 서비스와 동일한 인프라 내에있을 수도 있고 아닐 수도 있습니다.
Tommi 2011-06-02

답변:


34

이 문제에 대한 모든 해결책은 공유 비밀로 귀결됩니다. 또한 하드 코딩 된 사용자 이름 및 암호 옵션이 마음에 들지 않지만 매우 간단하다는 이점이 있습니다. 클라이언트 인증서도 좋지만 정말 많이 다른가요? 인증서는 서버에 있고 하나는 클라이언트에 있습니다. 가장 큰 장점은 무차별 대입이 더 어렵다는 것입니다. 하지만 그로부터 보호 할 수있는 다른 보호 수단이 있기를 바랍니다.

클라이언트 인증서 솔루션에 대한 귀하의 포인트 A는 해결하기 어렵다고 생각합니다. 분기를 사용합니다. if (client side certificat) { check it } else { http basic auth }나는 자바 전문가가 아니며 클라이언트 측 인증서를 위해 일한 적이 없습니다. 그러나 빠른 Google은 골목을 바로 찾는 이 자습서로 안내 합니다.

이 모든 "최고의"논의에도 불구하고 "코드가 적고 영리함이 적을수록 좋다"는 또 다른 철학이 있음을 지적하겠습니다. (저는 개인적으로이 철학을 가지고 있습니다). 클라이언트 인증서 솔루션은 많은 코드처럼 들립니다.

OAuth에 대한 질문을 표명 한 것을 알고 있지만 OAuth2 제안에는 SSL과 함께 사용해야하는 " 베어러 토큰 " 이라는 문제에 대한 솔루션이 포함되어 있습니다 . 단순성을 위해 하드 코딩 된 사용자 / 패스 (앱당 하나씩, 개별적으로 취소 할 수 있도록) 또는 매우 유사한 전달자 토큰을 선택합니다.


27
클라이언트 인증서는 공유 비밀이 아닙니다. 그것이 그들이 존재하는 이유입니다. 클라이언트에는 개인 키가 있고 서버에는 공개 키가 있습니다. 클라이언트는 비밀을 공유하지 않으며 공개 키는 비밀이 아닙니다.
Tim

5
튜토리얼 링크는 ... 튜토리얼 문서를하지만 오라클 사이트에서 일부 자바 인덱스 페이지로 연결되지 않습니다
마르 얀 Venema의

2
@MarjanVenema 음, newz2000이 응답 한 지 2 년 후 링크를 ​​시도하고 있기 때문입니다.하지만 WayBack Machine을 항상 사용해 볼 수 있습니다. web.archive.org/web/20110826004236/http://java.sun.com/…
Fábio 듀크 실바

1
@MarjanVenema : 미안하지만 newz2000이 여기로 와서 링크가 죽은 후에 업데이트 할 것으로 예상하고 있습니까? 당신이 말했듯이, 그것은 링크 부패이므로 조만간 발생합니다. 그 당시 저자가보고 있던 내용을보기 위해 아카이브에 액세스하거나 새 링크를 찾아 긍정적 인 기여를하세요. 귀하의 의견이 다른 사람에게 어떻게 도움이되었는지 모르겠습니다. 그러나 여기에서 다음 링크를 따르십시오 : oracle.com/technetwork/articles/javase/… (결국 역시 썩을 것이라는 점에 유의하십시오)
Fábio Duque Silva

2
@ FábioSilva : 아니요. 나는 그가 그렇게 할 것이라고 기대 하지 않습니다 . 아카이브를 읽었지만 새 링크를 찾을 시간이 없었기 때문에 차선책을했습니다. 커뮤니티의 다른 사람이 새 위치를 찾고 게시하다. 분명히 새 링크를 찾을 시간이 있었기 때문에 나를 괴롭히는 댓글에 넣는 대신 게시물의 링크를 업데이트하지 않은 이유는 무엇입니까?
Marjan Venema 2014 년

36

귀하의 질문을 읽은 후 필요한 요청을 수행하기 위해 특별한 토큰을 생성하십시오. 이 토큰은 특정 시간에 유지됩니다 (하루에 말).

다음은 인증 토큰을 생성하는 예입니다.

(day * 10) + (month * 100) + (year (last 2 digits) * 1000)

예 : 2011 년 6 월 3 일

(3 * 10) + (6 * 100) + (11 * 1000) = 
30 + 600 + 11000 = 11630

그런 다음 사용자 암호 (예 : "my4wesomeP4ssword!")와 연결합니다.

11630my4wesomeP4ssword!

그런 다음 해당 문자열의 MD5를 수행합니다.

05a9d022d621b64096160683f3afe804

언제 요청을하나요? 항상이 토큰을 사용하세요.

https://mywebservice.com/?token=05a9d022d621b64096160683f3afe804&op=getdata

이 토큰은 항상 매일 고유하므로 이러한 종류의 보호는 항상 귀하의 서비스를 보호하기에 충분하다고 생각합니다.

희망이 도움이됩니다

:)


1
모든 요청에 ​​보안 토큰을 추가하는 방식이 정말 마음에 듭니다.하지만 프로그래머가 이미 100 개의 jsp 페이지를 생성하고 그 후에 t0이 이전에 생성 된 100 페이지와 생성 될 페이지에서 보안을 구현했을 때이 문제가 발생합니다. 이 경우 올바른 선택이 아닌 각 요청에 토큰을 추가하십시오. :)
Ankur Verma

4
시계가 동기화되지 않으면 어떻게됩니까? 이 경우 클라이언트가 잘못된 토큰을 생성하지 않습니까? 둘 다 UTC로 datetime을 생성하더라도 시계가 여전히 다를 수 있으므로 토큰이 작동하지 않는 매일 시간이 발생할 수 있습니까?
NickG 2013 년

@NickG, 전에이 문제가 있었는데 서버 시간을 요청하여 이것을 보호하는 유일한 방법이었습니다. 이것은 99 % UTC의 문제를 죽일 것입니다. 물론 단점은 서버에 대한 추가 호출입니다.
kororo

그러나 나는 여전히 하루 동안이 토큰을 사용하여 웹 서비스를 사용할 수 있습니까? 이것이 어떻게 도움이 될지
Mina Gabriel

@MinaGabriel 토큰 생성에 더 많은 시간 프레임을 추가 할 수 있습니다. (분 * 10) + (시 * 100) + (일 * 1000) + (월 * 10000) + (연도 (마지막 2 자리) * 100000)
kororo

11

취할 수있는 접근 방식에는 여러 가지가 있습니다.

  1. RESTful 순수 주의자는 BASIC 인증을 사용하고 모든 요청에 ​​대해 자격 증명을 보내기를 원할 것입니다. 그들의 근거는 아무도 어떤 상태도 저장하지 않는다는 것입니다.

  2. 클라이언트 서비스는 세션 ID를 유지하는 쿠키를 저장할 수 있습니다. 나는 개인적으로 이것이 내가 듣는 일부 순수 주의자들만큼 불쾌하다고 생각하지 않습니다. 반복해서 인증하는 것은 비용이 많이들 수 있습니다. 하지만이 아이디어가별로 마음에 들지 않는 것 같습니다.

  3. 귀하의 설명에 따르면 OAuth2에 관심이있는 것 같습니다. 지금까지 제가 본 경험에 비추어 볼 때 다소 혼란스럽고 일종의 블리딩 에지입니다. 거기에 구현이 있지만 그 사이에 거의 없습니다. Java에서는 Spring3의 보안 모듈에 통합되었음을 이해 합니다. (그들의 튜토리얼 은 멋지게 작성되었습니다.) Restlet에 확장이 있을지 기다리고 있었지만 지금까지 제안되었고 인큐베이터에 있을지 모르지만 아직 완전히 통합되지 않았습니다.


나는 옵션 2에 대해 아무것도 가지고 있지 않습니다. RESTful 앱에서 좋은 솔루션이라고 생각합니다.하지만 클라이언트 서비스는 처음에 토큰을 어디서 얻습니까? 처음에는 어떻게 인증합니까? 아마도 이것이 잘못되었다고 생각하지만 클라이언트 서비스가이를 위해 자체 사용자 이름과 암호를 가져야한다는 것이 이상하게 보입니다.
Tommi

최종 사용자가 귀하의 사용자 인 경우 중개 서비스는 첫 번째 요청에서 자격 증명을 귀하에게 전달할 수 있으며 귀하는 쿠키 또는 기타 토큰을 반환 할 수 있습니다.
jwismar

마찬가지로 OAuth 시나리오에서 최종 사용자는 웹 서비스에 대한 액세스 권한을 중개 서비스에 위임합니다.
jwismar

오해가있는 것 같습니다 . 클라이언트 서비스 뒤에는 최종 사용자전혀 없습니다 . 상황을 더 잘 설명하기 위해 질문을 업데이트했습니다.
Tommi

1
위에 나열된 # 1 옵션은 HTTPS를 통해서만 수행되어야한다고 추가하겠습니다.
mr-sk 2011 년

3

나는 접근 방식을 믿는다 :

  1. 첫 번째 요청, 클라이언트가 ID / 암호를 보냅니다.
  2. 고유 토큰에 대한 ID / 패스 교환
  3. 만료 될 때까지 각 후속 요청에서 토큰 유효성 검사

구현 방법 및 기타 특정 기술 세부 사항에 관계없이 꽤 표준입니다.

정말로 엔벨로프를 푸시하려는 경우 자격 증명이 검증 될 때까지 클라이언트의 https 키를 일시적으로 잘못된 상태로 간주하고, 그렇지 않은 경우 정보를 제한하고, 만료를 기준으로 다시 검증 될 때 액세스 권한을 부여 할 수 있습니다.

도움이 되었기를 바랍니다


3

클라이언트 인증서 접근 방식에 관한 한, 클라이언트 인증서가없는 사용자를 허용하면서 구현하는 것은 그리 어렵지 않습니다.

실제로 자체 서명 된 인증 기관을 만들고 각 클라이언트 서비스에 클라이언트 인증서를 발급했다면 이러한 서비스를 쉽게 인증 할 수 있습니다.

사용중인 웹 서버에 따라 클라이언트 인증서를 허용하지만 요구하지 않는 클라이언트 인증을 지정하는 방법이 있어야합니다. 예를 들어, Tomcat에서 https 커넥터를 지정할 때 'true'또는 'false'대신 'clientAuth = want'를 설정할 수 있습니다. 그런 다음 자체 서명 된 CA 인증서를 신뢰 저장소에 추가해야합니다 (기본적으로 웹 서버 구성에서 다른 파일을 지정하지 않는 한 사용중인 JRE의 cacerts 파일). 따라서 신뢰할 수있는 유일한 인증서는 자신이 서명 한 CA.

서버 측에서는 요청 (null 아님)에서 클라이언트 인증서를 검색 할 수있는 경우에만 보호하려는 서비스에 대한 액세스를 허용하고 추가 보안을 선호하는 경우 모든 DN 검사를 통과합니다. 클라이언트 인증서가없는 사용자의 경우 여전히 서비스에 액세스 할 수 있지만 요청에 인증서가 없습니다.

제 생각에는 이것이 가장 '안전한'방법이지만 확실히 학습 곡선과 오버 헤드가 있으므로 반드시 귀하의 요구에 가장 적합한 솔루션이 아닐 수도 있습니다.


3

5. 다른 것-거기에 다른 해결책이 있어야합니까?

당신이 맞아요! 그리고 JWT (JSON Web Tokens)라고합니다.

JWT (JSON Web Token)는 당사자간에 정보를 JSON 개체로 안전하게 전송하기위한 컴팩트하고 독립적 인 방식을 정의하는 개방형 표준 (RFC 7519)입니다. 이 정보는 디지털 서명되어 있으므로 확인하고 신뢰할 수 있습니다. JWT는 비밀 (HMAC 알고리즘 사용) 또는 RSA를 사용하는 공개 / 개인 키 쌍을 사용하여 서명 할 수 있습니다.

JWT를 살펴 보는 것이 좋습니다. 대체 솔루션과 비교할 때 문제에 대한 훨씬 더 간단한 솔루션입니다.

https://jwt.io/introduction/


1

서버에서 세션을 생성 sessionId하고 각 REST 호출을 통해 클라이언트와 서버간에 공유 할 수 있습니다 .

  1. 먼저 REST 요청 인증 : /authenticate. 클라이언트 형식에 따라 응답을 반환합니다 sessionId: ABCDXXXXXXXXXXXXXX.

  2. 이 저장 sessionIdMap실제 세션. Map.put(sessionid, session)또는 SessionListener귀하를 위해 키를 생성하고 파괴하는 데 사용 합니다.

    public void sessionCreated(HttpSessionEvent arg0) {
      // add session to a static Map 
    }
    
    public void sessionDestroyed(HttpSessionEvent arg0) {
      // Remove session from static map
    }
    
  3. URL?jsessionid=ABCDXXXXXXXXXXXXXX(또는 다른 방법으로) 모든 REST 호출에서 sessionid를 가져옵니다 .

  4. HttpSession사용하여지도에서 검색 sessionId;
  5. 세션이 활성화 된 경우 해당 세션에 대한 요청을 확인합니다.
  6. 응답 또는 오류 메시지를 다시 보냅니다.

0

사용자가 요청을 승인하면 인증을 위해 다른 앱에서 사용하는 고유 토큰을 생성하는 애플리케이션 ID 매개 변수를 사용하여 사용자를 사이트로 리디렉션하는 애플리케이션을 사용합니다. 이렇게하면 다른 응용 프로그램이 사용자 자격 증명을 처리하지 않으며 사용자가 다른 응용 프로그램을 추가, 제거 및 관리 할 수 ​​있습니다. Foursquare와 몇몇 다른 사이트는 이러한 방식으로 인증되며 다른 애플리케이션으로 구현하기가 매우 쉽습니다.


흠, 설명을 따를 수 있는지 잘 모르겠습니다. 어떤 사용자에 대해 이야기하고 있습니까? 다른 응용 프로그램과 통신하는 응용 프로그램에 대해 이야기하고 있습니다. 이해하신 것 같지만 여전히 이해가 안됩니다. 예를 들어이 "토큰"이 만료되면 어떻게됩니까?
Tommi

생성하여 다른 응용 프로그램으로 다시 보내는 토큰은 영구 토큰이며 사용자 및 응용 프로그램에 연결되어 있습니다. 다음은 foursquares 문서 developer.foursquare.com/docs/oauth.html에 대한 링크 이며 기본적으로 oauth2이므로 좋은 인증 솔루션을 찾아보십시오.
Devin M

오해가있는 것 같습니다 . 클라이언트 서비스 뒤에는 최종 사용자전혀 없습니다 . 링크 한 Foursquare 문서에는 사용자가없는 액세스가 간략하게 언급되어 있으므로 적어도 어느 정도 도움이되었습니다. 감사합니다! 그러나 나는 그것이 실제로 어떻게 작동 할 것인지에 대한 완전한 그림을 형성 할 수 없다.
Tommi

애플리케이션에 대한 키를 생성하기 만하면됩니다. 애플리케이션에 대한 액세스를 허용하는 것뿐이라면 간단한 application_id와 application_key가 인증을 위해 작동해야합니다. 토큰을 사용하여 인증하도록하려면 devise의 토큰 인증 옵션을 사용하십시오. URL 요청과 함께 애플리케이션에 전달되는 매개 변수 일뿐입니다.
Devin M

그러나 이것은 사용자 이름 + 암호 = 세션 인증 토큰 시나리오와 정확히 동일하지 않습니까? application_id와 application_key는 사용자 이름과 암호의 동의어가 아닙니까? :) 이것이 정말로 이와 같은 상황에 대한 표준 관행이라면 완벽하게 괜찮습니다-제가 말했듯이, 저는 이것에 대해 경험이 없습니다-하지만 다른 옵션이있을 것이라고 생각했습니다 ...
Tommi

-3

인증 외에도 큰 그림에 대해 생각하는 것이 좋습니다. 인증없이 백엔드 RESTful 서비스를 만드는 것을 고려하십시오. 그런 다음 최종 사용자와 백엔드 서비스 사이에 매우 간단한 인증이 필요한 중간 계층 서비스를 배치합니다.


최종 사용자와 백엔드 서비스 사이? 클라이언트 서비스가 완전히 인증되지 않은 상태로 남겨지지 않습니까? 내가 원하는 것이 아닙니다. 물론 내 웹 서비스와 클라이언트 서비스 사이에 중간 계층을 배치 할 수는 있지만 여전히 질문이 남아 있습니다. 실제 인증 모델은 무엇일까요?
Tommi

중간 레이어는 Nginx와 같은 웹 서버가 될 수 있으며 거기에서 인증을 할 수 있습니다. 인증 모델은 세션 기반 일 수 있습니다.
Dagang

내 질문에서 설명하려고 했으므로 이러한 클라이언트 서비스에 대한 세션 기반 인증 체계를 원하지 않습니다. (질문에 대한 내 업데이트를 참조하십시오.)
Tommi

이름 및 암호 대신 화이트 IP 목록 또는 IP 범위를 사용하는 것이 좋습니다. 일반적으로 클라이언트 서비스 IP는 안정적입니다.
Dagang
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.