IT박스

REST 인증 및 API 키 노출

itboxs 2020. 9. 4. 07:05
반응형

REST 인증 및 API 키 노출


나는 REST에 대해 읽고 있었고 그것에 대한 많은 질문과 다른 많은 사이트와 블로그에 대한 질문이 있습니다. 이 특정 질문을 본 적이 없지만 ... 어떤 이유로이 개념에 대해 마음을 감쌀 수는 없습니다 ...

RESTful API를 구축하고 있고 보안을 유지하고 싶다면 내가 본 방법 중 하나는 보안 토큰을 사용하는 것입니다. 다른 API를 사용했을 때 토큰과 공유 비밀이있었습니다. 내가 이해하지 못하는 것은 나머지 서비스 작업에 대한 요청이 자바 스크립트 (XHR / Ajax)를 통해 이루어지고 있다는 것입니다. 누군가가 FireBug (또는 브라우저에서 "소스보기")와 같은 간단한 것으로이를 스니핑하는 것을 방지하는 것입니다. API 키를 복사 한 다음 키와 시크릿을 사용하여 그 사람을 가장하는 것입니까?


api 비밀은 명시 적으로 전달되지 않고, 비밀은 현재 요청 부호 를 생성하는 데 사용됩니다 . 서버 측에서 서버는 동일한 프로세스에 따라 서명을 생성합니다. 두 서명이 일치하면 요청이 성공적으로 인증됩니다. 서명 은 비밀이 아닌 요청을 통해 전달됩니다.


파트너가 등록한 도메인에서만 사용할 수있는 API를 공개하고 있습니다. 콘텐츠는 부분적으로 공개되지만 (하지만 우리가 알고있는 도메인에만 표시되는 것이 바람직 함) 대부분 사용자에게 비공개입니다. 그래서:

  • 확인하려면 어떤 표시됩니다, 우리의 사용자는 우리와 함께 로그인해야하지만,이 별도로 처리됩니다.

  • 데이터가 표시 되는 위치 를 결정하기 위해 공개 API 키를 사용하여 우리가 알고있는 도메인에 대한 액세스를 제한하고 무엇보다도 개인 사용자 데이터가 CSRF에 취약하지 않도록합니다 .

이 API 키는 실제로 누구에게나 볼 수 있으며 다른 방법으로 파트너를 인증 하지 않으며 REFERER가 필요하지 않습니다 . 그래도 안전합니다.

  1. 때 우리의 get-csrf-token.js?apiKey=abc123IS 요청 :

    1. abc123데이터베이스 에서 키 를 찾고 해당 키에 대한 유효한 도메인 목록을 가져옵니다.

    2. CSRF 유효성 검사 쿠키를 찾습니다. 존재하지 않는 경우 보안 임의 값을 생성 하고 HTTP 전용 세션 쿠키 에 넣습니다 . 쿠키가 존재하는 경우 기존 임의 값을 가져옵니다.

    3. API 키에서 CSRF 토큰을 만들고 쿠키에서 임의의 값을 생성하고 서명합니다 . (서버에 토큰 목록을 유지하는 대신 값에 서명합니다. 서명 된 토큰에서 두 값을 모두 읽을 수 있습니다. 괜찮습니다.)

    4. 응답이 캐시되지 않도록 설정하고 쿠키를 추가하고 다음과 같은 스크립트를 반환합니다.

      var apiConfig = apiConfig || {};
      if(document.domain === 'expected-domain.com' 
            || document.domain === 'www.expected-domain.com') {
      
          apiConfig.csrfToken = 'API key, random value, signature';
      
          // Invoke a callback if the partner wants us to
          if(typeof apiConfig.fnInit !== 'undefined') {
              apiConfig.fnInit();
          }
      } else {
          alert('This site is not authorised for this API key.');
      }
      

    노트:

    • 위의 내용은 서버 측 스크립트가 요청을 위조하는 것을 방지하지 않지만 브라우저에서 요청한 경우 에만 도메인이 일치 하는지 확인 합니다.

    • 자바 스크립트에 대한 동일 출처 정책은 브라우저가로드 한 후 자바 스크립트 소스를 검사 XHR (아약스)를 사용할 수 없도록합니다. 대신 일반 브라우저는 <script src="https://our-api.com/get-csrf-token.js?apiKey=abc123">(또는 동적 인 동급)을 사용해서 만로드 할 수 있으며 그런 다음 코드를 실행합니다. 물론 서버는 생성 된 JavaScript에 대해 Cross-Origin 리소스 공유 또는 JSONP를 지원 해서는 안됩니다 .

    • 브라우저 스크립트는 document.domain위 스크립트를로드하기 전에 의 값을 변경할 수 있습니다 . 그러나 동일한 원본 정책은 just , to 또는 일부 브라우저에서 .s 다시 쓰기와 같은 접두사 제거 하여 도메인을 단축하는 것만 허용 합니다 .subdomain.example.comexample.commyblog.wordpress.comwordpress.combbc.co.ukco.uk

    • 서버 측 스크립트를 사용하여 JavaScript 파일을 가져 오면 서버도 쿠키를 가져옵니다. 그러나 제 3 자 서버는 사용자의 브라우저가 해당 쿠키를 당사 도메인에 연결하도록 할 수 없습니다. 따라서 서버 측 스크립트를 사용하여 가져온 CSRF 토큰 및 유효성 검사 쿠키는 브라우저가 아닌 후속 서버 측 호출에서만 사용할 수 있습니다. 그러나 이러한 서버 측 호출에는 사용자 쿠키가 포함되지 않으므로 공개 데이터 만 가져올 수 있습니다. 이것은 서버 측 스크립트가 파트너의 웹 사이트에서 직접 스크랩 할 수있는 것과 동일한 데이터입니다.

  2. 사용자가 로그인 할 때 원하는 방식으로 사용자 쿠키를 설정하십시오. (사용자는 JavaScript를 요청하기 전에 이미 로그인했을 수 있습니다.)

  3. All subsequent API requests to the server (including GET and JSONP requests) must include the CSRF token, the CSRF validation cookie, and (if logged on) the user cookie. The server can now determine if the request is to be trusted:

    1. The presence of a valid CSRF token ensures the JavaScript was loaded from the expected domain, if loaded by a browser.

    2. The presence of the CSRF token without the validation cookie indicates forgery.

    3. The presence of both the CSRF token and the CSRF validation cookie does not ensure anything: this could either be a forged server side request, or a valid request from a browser. (It could not be a request from a browser made from an unsupported domain.)

    4. The presence of the user cookie ensures the user is logged on, but does not ensure the user is a member of the given partner, nor that the user is viewing the correct website.

    5. The presence of the user cookie without the CSRF validation cookie indicates forgery.

    6. The presence of the user cookie ensures the current request is made through a browser. (Assuming a user would not enter their credentials on an unknown website, and assuming we don’t care about users using their own credentials to make some server side request.) If we also have the CSRF validation cookie, then that CSRF validation cookie was also received using a browser. Next, if we also have a CSRF token with a valid signature, and the random number in the CSRF validation cookie matches the one in that CSRF token, then the JavaScript for that token was also received during that very same earlier request during which the CSRF cookie was set, hence also using a browser. This then also implies the above JavaScript code was executed before the token was set, and that at that time the domain was valid for the given API key.

      So: the server can now safely use the API key from the signed token.

    7. If at any point the server does not trust the request, then a 403 Forbidden is returned. The widget can respond to that by showing a warning to the user.

It's not required to sign the CSRF validation cookie, as we're comparing it to the signed CSRF token. Not signing the cookie makes each HTTP request shorter, and the server validation a bit faster.

The generated CSRF token is valid indefinitely, but only in combination with the validation cookie, so effectively until the browser is closed.

We could limit the lifetime of the token's signature. We could delete the CSRF validation cookie when the user logs out, to meet the OWASP recommendation. And to not share the per-user random number between multiple partners, one could add the API key to the cookie name. But even then one cannot easily refresh the CSRF validation cookie when a new token is requested, as users might be browsing the same site in multiple windows, sharing a single cookie (which, when refreshing, would be updated in all windows, after which the JavaScript token in the other windows would no longer match that single cookie).

For those who use OAuth, see also OAuth and Client-Side Widgets, from which I got the JavaScript idea. For server side use of the API, in which we cannot rely on the JavaScript code to limit the domain, we're using secret keys instead of the public API keys.


This question has an accepted answer but just to clarify, shared secret authentication works like this:

  1. Client has public key, this can be shared with anyone, doesn't matter, so you can embed it in javascript. This is used to identify the user on the server.
  2. Server has secret key and this secret MUST be protected. Therefore, shared key authentication requires that you can protect your secret key. So a public javascript client that connects directly to another service is not possible because you need a server middleman to protect the secret.
  3. Server signs request using some algorithm that includes the secret key (the secret key is sort of like a salt) and preferably a timestamp then sends the request to the service. The timestamp is to prevent "replay" attacks. A signature of a request is only valid for around n seconds. You can check that on the server by getting the timestamp header that should contain the value of the timestamp that was included in the signature. If that timestamp is expired, the request fails.
  4. The service gets the request which contains not only the signature but also all the fields that were signed in plain text.
  5. The service then signs the request in the same way using the shared secret key and compares the signatures.

I supose you mean session key not API key. That problem is inherited from the http protocol and known as Session hijacking. The normal "workaround" is, as on any web site, to change to https.

To run the REST service secure you must enable https, and probably client authentification. But after all, this is beyond the REST idea. REST never talks about security.


What you want to do on the server side is generate an expiring session id that is sent back to the client on login or signup. The client can then use that session id as a shared secret to sign subsequent requests.

The session id is only passed once and this MUST be over SSL.

See example here

Use a nonce and timestamp when signing the request to prevent session hijacking.


I will try to answer the the question in it's original context. So question is "Is the secret (API) key safe to be placed with in JavaScript.

In my opinion it is very unsafe as it defeats the purpose of authentication between the systems. Since the key will be exposed to the user, user may retrieve information he/she is not authorized to. Because in a typical rest communication authentication is only based on the API Key.

A solution in my opinion is that the JavaScript call essentially pass the request to an internal server component who is responsible from making a rest call. The internal server component let's say a Servlet will read the API key from a secured source such as permission based file system, insert into the HTTP header and make the external rest call.

I hope this helps.

참고URL : https://stackoverflow.com/questions/5472668/rest-authentication-and-exposing-the-api-key

반응형