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

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

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

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

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

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

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

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

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

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



답변

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

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

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

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


답변

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

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

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

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

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


답변

나는 접근 방식을 믿는다 :

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

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

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

도움이 되었기를 바랍니다


답변

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

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

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

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

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


답변

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

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

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

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

https://jwt.io/introduction/


답변

서버에서 세션을 생성 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. 응답 또는 오류 메시지를 다시 보냅니다.