📎 Coding Everybody


4. REST API

REST API(REpresentational State Transfer)는 웹상에서 사용되는 여러 리소스를 HTTP URI로 표현하고, 해당 리소스에 대한 행위를 HTTP Method로 정의하는 방식
리소스(HTTP URI로 정의됨)를 어떻게 하겠다(HTTP Method + Payload)를 구조적으로 깔끔하게 표현하는 방법

REST API의 설계 가이드

리소스에 대한 행위는 HTTP Method(POST, GET, PUT, DELETE)로 표현해야 합니다.
/(슬래시)는 계층 관계를 나타낼때 사용합니다.
URI 마지막 문자에 /(슬래시)를 사용하지 않습니다.
URI에 _(underscore)는 사용하지 않도록 합니다. 또한 영어 대문자보다는 소문자를 씁니다. 그리고 가독성을 위해서 긴 단어는 잘 사용하지 않습니다.
URI에 동사는 GET, POST와 같은 HTTP Method를 표현하기 때문이다.
동사가 아니라 명사를 사용한다.
URI에 파일의 확장자(예를들어 .json , .JPGE)를 포함 시키지 않습니다.

4.1. REST API 제약사항

Client-Server

사용자들에게 제공하는 interface인 User Interface와 데이터 스토리지, 알고리즘 등 서버 내부의 작업들을 분리함으로 써 User Interface는 여러 플랫폼에서의 이식성을 향상될 수 있으며, 서버는 그 구성요소를 단순화하여 확장성을 단순화할 수 있습니다.
클라이언트와 서버가 서로 의존하지 않고 별도로 진화할 수 있습니다. 클라이언트는 서버의 리소스 URI만 알고 있으면 되기 때문입니다.

Stateless

클라이언트에서 서버로의 각 요청에는 그 요청을 이해하는 데 필요한 모든 정보가 포함되어야 합니다. 서버에 저장된 환경 정보를 이용해서 이득(서버에서의 클라이언트 정보 유지 등)을 취하면 안 됩니다. 따라서 세션의 정보는 전적으로 클라이언트가 가지고 있어야 합니다.
로그인했다는 세션 유지가 필요하다면 그 정보 또한 Client가 해당 정보를 가지고 서버에 전달해야 한다. e.g. JWT 등을 사용

Cacheable

요청에 대한 응답 내의 데이터에 해당 요청은 캐시가 가능한지 불가능 한지 명시해야 합니다. 응답을 캐시 할 수 있다면 클라이언트에서 동일한 요청이 왔을 때 응답 데이터를 재사용할 수 있어야 합니다.
cache-control 헤더를 통하여 캐시 여부 명시

Uniform Interface

전체적인 시스템 아키텍처를 간단하고 잘 파악할 수 있도록 하기 위한 약속된 Interface, 해당 규약을 REST를 사용자들이 지킴으로써 추후에 사용하는 Client를 개발하는 사용자와 Server를 개발하는 사용자 간의 결합도가 낮아질 수 있다(Decoupling). 개발 REST는 규약으로 4가지 를 제시합니다.

identification of resources: Resource가 URI로 식별되면 된다

manipulation of resources through representations: representations 전송을 통해서 resources를 조작해야 한다

Representations: HTTP 메소드의 PUT, GET, DELTE 등을 말한다.

self-descriptive messages: 메시지 만으로 어떤 메시지 인지 알 수 있어야 한다

Client]
GET / HTTP/1.1
Host: www.example.org

Server]
HTTP/1.1 200 OK
Content-Type: application/json-patch+json
\[{ “op” : “remove”, “path” : “a/b/c"}\]

Hypermedia As The Engine Of Application State: 애플리케이션의 상태는 Hyperlink를 이용해 전이되어야한다. (페이지 변경 등)

어디서 어디로 전이가 가능한지 미리 결정되지 않는다. 어떤 상태로 전이가 완료되고 나서야 그 다음 전이 될 수 있는 상태가 결정된다. 링크가 동적으로 변경될 수 있음

HTTP/1.1 200 OK
Content-Type: application/json
Link: </articles/1>; rel=“previous”,
      </articles/3>; rel=“next”;
{
    “Title” : “The second article”,
    “content” : “Hello! Brother"
}

Layered System

계층화된 시스템 아키텍처를 사용하여 각 구성들 간의 계층을 마음대로 상호작용 할 수 없도록 제한 함으로 써 Interface를 일원화할 수 있습니다.

Code on demand (optional)

서버가 네트워크를 통해 클라이언트에 전달한 javascript 등과 같은 프로그램들은 그 자체로 실행이 될 수 있어야 한다. 이것은 사전 구현에 필요한 기능의 수를 줄임으로써 클라이언트를 단순화합니다.
이 말은 우리가 평소에는 정적인 데이터를 xml 또는 json에 담아서 client로 보내고 client가 이것을 가공합니다. 하지만 code on demand라는 것은 client에 보내는 데이터를 바로 실행 가능한 코드를 보내서 이것을 Client에서 실행하는 것을 말합니다.



5. OAuth 2.0

OAuth 2.0은 다양한 플랫폼 환경에서 인증과 권한 부여를 위한 산업 표준 프로토콜

Authentication(AuthN) 인증: Who are you?

시스템 접근을 확인하는 것 (로그인) -> 인증만 하는 것은 openID

Authorization(AuthZ) 권한: What can you do?

행위의 권리를 검증하는 것 (Delegated Authorization) -> OAuth 2.0

5.1. OAuth 2.0 인증

Resource owner: 사용자

Client: Resource Server 에서 제공하는 자원을 사용하는 애플리케이션 (예, 페이스북의 뉴스를 모아서 보여주는 앱)

Resource server(API server): 자원을 호스팅하는 서버, (예, 페이스북 사진 비디오 등)

Authorization Server: 사용자의 동의를 받아서 권한을 부여하는 서버, 일반적으로 Resource Server 와 같은 URL 하위에 있는 경우가 많음

OAuth 인증과정

image 발급받은 Access Token은 서비스에서 자체적으로 저장, 관리

서버 쪽 요청 보내는 쿼리 파라메터

https://accounts.google.com/o/oauth2/v2/auth?
response_type=code&
client_id=your_client_id&
scope=profile%20contacts&
redirect_uri=https%3A//oauth2.example.com/code

5.2. OAuth 2.0의 인증종류

||Confidential Client|Public Client| |:–:|:–:|:–:| |3-legged|Authorization Code|Implicit| |2-legged|Resource Owner Password Credentials|Client Credentials|

Authorization Code Grant

서버사이드 코드로 인증하는 방식
권한서버가 클라이언트와 리소스 서버간의 중재역할
access token을 바로 클라이언트로 전달하지 않아 잠재적 유출을 방지
로그인시에 페이지 URL에 response_type=code 라고 넘긴다

브라우저에서 access token 노출을 방지하기 위해서, 클라이언트의 프론트엔드 채널은 권한 부여 서버로부터 application code를 얻는다. 그리고 application code를 백엔드 채널로 보낸다. application code를 access token으로 바꾸기 위해서, client_secret이 필요하다. client_secret은 클라이언트의 백엔드 채널에 의해서만 알려지게 되며, 프론트엔드 채널은 client_secret에 관여하지 않는다. 백엔드 채널은 POST 요청을 권한부여 서버에 application code와 client_secret을 동봉해서 보낸다. 요청은 다음과 같이 보내진다.

POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded
code=4/W7q7P51a-iMsCeLvIaQc6bYrgtp9&
client_id=your_client_id&
client_secret==your_client_secret_only_known_by_server&
redirect_url=https%3A//oauth2.example.com/code

권한 부여 서버는 client_secret과 application code의 유효성을 검사하고 access token을 보내준다. 백엔드 채널은 access token을 갖고 있고 이 토큰을 리소스 서버에서 정보를 갖고올 때 사용한다. 이러한 방법으로 브라우저는 access token에 접근하지 않는 방식으로 구현할 수 있다.

Implicit Grant

image

token과 scope에 대한 스펙 등은 다르지만 OAuth 1.0a과 가장 비슷한 인증방식
Public Client인 브라우저 기반의 어플리케이션(Javascript application)이나 모바일 어플리케이션에서 이 방식을 사용하면 된다
OAuth 2.0에서 가장 많이 사용되는 방식이다
권한코드 없이 바로 발급되서 보안에 취약
주로 Read only인 서비스에 사용
로그인시에 페이지 URL에 response_type=token 라고 넘긴다
OAuth 2.0 묵시적 권한부여는 백엔드 채널이 존재하지 않으며, 웹사이트가 브라우저만 사용하는 정적인 사이트일 때 사용된다. 이 경우에는, application code를 access token으로 변경할 때, 백엔드 채널에서 일어나는 마지막 단계를 생략한다. 묵시적 권한부여에서는 권한부여 서버가 access token을 바로 준다.

Password Credentials Grant

Client에 아이디/패스워드를 저장해 놓고 아이디/패스워드로 직접 access token을 받아오는 방식이다
Client 를 믿을 수 없을 때에는 사용하기에 위험하기 때문에 API 서비스의 공식 어플리케이션이나 믿을 수 있는 Client에 한해서만 사용하는 것을 추천한다
로그인시에 API에 POST로 grant_type=password 라고 넘긴다

Client Credentials Grant

어플리케이션이 Confidential Client일 때 id와 secret을 가지고 인증하는 방식이다
로그인시에 API에 POST로 grant_type=client_credentials 라고 넘긴다

5.3. Token

Access Token

앞서 말한 4가지 권한 요청 방식 모두, 요청 절차를 정상적으로 마치면 클라이언트에게 Access Token이 발급됩니다. 이 토큰은 보호된 리소스에 접근할 때 권한 확인용으로 사용됩니다. 문자열 형태이며 클라이언트에 발급된 권한을 대변하게 됩니다. 계정 아이디와 비밀번호 등 계정 인증에 필요한 형태들을 이 토큰 하나로 표현함으로써, 리소스 서버는 여러 가지 인증 방식에 각각 대응 하지 않아도 권한을 확인 할 수 있게 됩니다.

Refresh Token

한번 발급받은 Access Token 은 사용할 수 있는 시간이 제한되어 있습니다. 사용하고 있던 Access Token 이 유효기간 종료 등으로 만료되면, 새로운 Access Token을 얻어야 하는데 그때 이 Refresh Token 이 활용됩니다. 권한 서버가 Access Token 을 발급해주는 시점에 Refresh Token 도 함께 발급하여 클라이언트에게 알려주기 때문에, 전용 발급 절차 없이 Refresh Token을 미리 가지고 있을 수 있습니다. 토큰의 형태는 Access Token과 동일하게 문자열 형태입니다. 단 권한 서버에서만 활용되며 리소스 서버에는 전송되지 않습니다.

토큰의 갱신 과정

클라이언트가 권한 증서를 가지고 권한서버에 Access Token 을 요청하면, 권한 서버는 Access Token과 Refresh Token 을 함께 클라이언트에 알려줍니다. 그 후 클라이언트는 Access Token을 사용하여 리소스 서버에 각종 필요한 리소스들을 요청하는 과정을 반복합니다. 그러다가 일정한 시간이 흐른 후 Access Token이 만료되면, 리소스 서버는 이후 요청들에 대해 정상 결과 대신 오류를 응답하게 됩니다. 오류 등으로 Access Token이 만료됨을 알아챈 클라이언트는, 전에 받아 두었던 Refresh Token을 권한 서버에 보내어 새로운 Access Token을 요청합니다. 갱신 요청을 받은 권한 서버는 Refresh Token 의 유효성을 검증한 후, 문제가 없다면 새로운 Access Token을 발급해줍니다. 이 과정에서 옵션에 따라 Refresh Token 도 새롭게 발급 될 수 있습니다.

5.4. OpenID Connect

OAuth는 유저 인증을 곧바로 제공하지 않지만 권한 부여를 위한 Access Token을 제공한다. OpenID Connect는 권한부여 서버에 의해 작동하는 인증 시스템을 기반으로 클라이언트가 사용자를 판단할 수 있게 해준다. 권한부여 서버에 유저 로그인과 동의를 요청할 때, openid라는 스코프를 정의하면 OpenID Connect 사용이 가능하다. openid는 OpenID가 필요되는 권한부여 서버에 필수적인 스코프이다.

OpenID Connect 인증을 위한 URI 요청은 다음과 같이 만들어진다.

https://accounts.google.com/o/oauth2/v2/auth?
response_type=code&
client_id=your_client_id&
scope=openid%20contacts&
redirect_uri=https%3A//oauth2.example.com/code

이 요청의 결과는 Access Token과 ID 토큰으로 바꿀 수 있는 application code이다. OAuth 플로우가 암묵적 플로우면, 서버는 Access Token과 ID 토큰을 바로 줄 것이다.

ID 토큰은 JWT 또는 JSON 웹 토큰이다. JWT는 header, payload, signature 3가지 부분이 담겨있는 인코드된 토큰이다. ID 토큰을 얻은 이후에, 클라이언트는 payload 부분에 인코드된 사용자 정보를 얻을지 결정할 수 있다.

{
  "iss": "https://accounts.google.com",
  "sub": "10965150351106250715113082368",
  "email": "johndoe@example.com",
  "iat": 1516239022,
  "exp": 1516242922
}

token introspection tool: https://jwt.io/
oauth server(API access management): https://developer.okta.com/
command-line JSON processor: https://stedolan.github.io/jq



6. SSL Certification

6.1. 대칭키



6.2. 공개키



6.3. SSL 인증

$ netstat -lntp # listen하고 있는 포트 확인

ssh에 key pair 추가

서버에 있는 .ssh 디렉토리 내 파일(authorized_keys)에 public key 추가 하고
cat authorized_keys

ssh-rsa 어쩌구저쩌구암호화된기존public키 test-EC2-key
ssh-rsa 어쩌구저쩌구암호화된추가된public키 test-EC2-key

클라이언트에서 private key 생성

$ vim second-key.pem
# 추가된public키와pair된어쩌구저쩌구암호화된private키 넣기
$ ssh -i second-key.pem ec2-user@myip -p22 # second key로 접속 확인

ssh-add로 해당 세션에 저장 해보기

ssh-add test-EC2-key.pem
ssh ec2-user@myip -p22 # 파일 명시 안해도 접속 가능



6.4. SSL 통신