JadeCode

[리뷰] 인증,보안 본문

개발/웹

[리뷰] 인증,보안

z-zero 2022. 7. 6. 13:00

cookie

쿠키는 서버에서 클라이언트에 영속성있는 데이터를 저장하는 방법이다. 서버는 클라이언트의 쿠키를 이용하여 데이터를 가져올 수 있다. 그러므로 쿠리를 이용하는 것은 단순히 서버에서 클라이언트에 쿠키를 전송하는 것만 의미하지 않고 클라이언트에서 서버로 쿠키를 다시 전송하는 것도 포함된다.

 

쿠키옵션

'Set-Cookie':[
            'cookie=yummy', 
            'Secure=Secure; Secure',
            'HttpOnly=HttpOnly; HttpOnly',
            'Path=Path; Path=/cookie',
            'Doamin=Domain; Domain=tistory.com'
        ]

1. Domain

도메인이라는 것은 서버에 접속할 수 있는 이름이다. (www.google.com). 쿠키 옵션에서 도메인은 포트(https) 및 서브 도메인(www) 정보, 세부 경로를 포함하지 않는다. 따라서 요청해야 할 URL이 https://www.localhost.com:3000/user/login 이라면 여기에서 도메인은 localhost.com이다.  만약 쿠키 옵션에서 도메인 정보가 존재한다면 클라이언트에서는 쿠크의 도메인 옵션과 서버의 도메인이 일치해야만 쿠키를 전송할 수 있다. 이를 통해 naver.com에서 받은 쿠키를 google.com에 전송하는 일을 막을 수 있다.

 

2.Path

Path는 세부 경로로써 서버가 라우팅할 때 사용하는 경로를 의미한다. https://www.localhost.com:3000/user/login 라면 path는 /user/login이 된다. 이를 명시하지 않으면 기본적으로 /으로 설정되어 있다.

path옵션의 특징은 설정된 경로를 포함하는 하위 경로로 요청을 하더라도 쿠키를 서버에 전송할 수 있따. path가 /user로 설정되어 있고, 요청하는 세부 경로가 /user/login인 경우라면 쿠키 전송이 가능하다. 하지만 반대의 경우는 불가능하다.

 

3. MaxAge or Expires 

쿠키가 유요한 기간을 정하는 옵션이다. 만약 쿠키가 영원히 남아있다면 그만큼 탈취되기도 쉽기 때문에 유효기한을 설정하는 것이 보안에 중요하다.

MaxAge는 쿠키가 유효한 시간을 초 단위로 설정하는 옵션이다.

Expires는 날짜를 지정하는 것이다. 옵션의 값은 클라이언트의 시간을 기준으로 한다. 

지정된 시간, 날짜를 초과하게 되면 쿠키는 자동으로 파괴된다.

 

쿠키는 위 옵션에 따라 세션쿠키(Session Cookie)와 영속성 쿠키(Persistent Cookie)로 나누어진다.

세션 쿠키: MaxAge 또는 Expires 옵션이 없는 쿠키로, 브라우저가 실행 중일 때 사용할 수 있는 임시 쿠키다. 브라우저를 종료하면 해당 쿠키는 삭제된다.

영속성 쿠키: 브라우저의 종료 여부와 상관없이 MaxAge 또는 Expires에 지정된 유효시간만큼 사용가능한 쿠키다.

 

4. Secure

Secure옵션이 true로 설정된 경우 HTTPS를 이용하는 경우에만 쿠키를 전송할 수 있다. 단, 도메인이 localhost인 경우에는 HTTPS가 아니어도 쿠키 전송이 가능하다. 

 

5. HttpOnly

자바스크립트로 브라우저의 쿠키에 접근 가능 여부를 결정한다. true인 경우 자바스크립트로 쿠키에 접근이 불가능한다. false인 경우 document.cookie를 이용해 자바스크립트로 쿠키에 접근할 수 있으므로 쿠키가 탈취될 위험이 있다.

 

6.SameSite

Cross-Origin요청을 받은 경우, 요청에서 사용한 메서드와 해당 옵션의 조합을 기준으로 서버의 쿠키전송 여부를 결정하게 된다.

- Lax: Cross-Origin 요청이라면 GET 메소드에 대해서만 쿠키를 전송할 수 있다.

- Strict: 단어 그대로 가장 엄격한 옵션으로, Cross-Origin이 아닌 same-site 인 경우에만 쿠키를 전송 할 수 있다.

- None: Cross-Origin에 대해 가장 관대한 옵션으로 항상 쿠키를 보내줄 수 있다. 다만 쿠키 옵션 중 Secure 옵션이 필요하다.

이때 same-site는 요청을 보낸 Origin과 서버의 도메인, 프로토콜, 포트가 같은 경우를 말한다. 이 중 하나라도 다르다면 Cross-Origin으로 구분된다.

 

서버에서 이러한 옵션들을 지정한 다음 서버에서 클라이언트로 쿠키를 처음 전송하게 된다면 헤더에 Set-Cookie라는 프로퍼티로 쿠키를 담아 전송한다. 이후 클라이언트에서 서버에게 쿠키를 전송해야 한다면 클라이언트는 헤더에 Cookie라는 프로퍼티에 쿠키를 담아 서버에 쿠키를 전송하게 된다. 

 

쿠키의 특성을 이용하여 서버는 클라이언트에 인증정보를 담은 쿠키를 전송하고, 클라이언트는 전달받은 쿠키를 서버에 요청과 함께 전송하여 stateless한 인터넷 연결을 stateful하게 유지할 수 있다. 하지만 기본적으로 쿠키는 오랜 시간 동안 유지될 수 있고, HttpOnly 옵션을 사용하지 않았다면 자바스크립트를 이용해서 쿠키에 접근할 수 있기 때문에 쿠키에 민감한 정보를 담는 것은 위험하다.

 

session

서버가 해당 유저는 인증에 성공했음을 알고 있다면 유저가 매번 로그인할 필요가 없다.

서버는 사용자가 인증에 성공했음을 알고 있어야 한다.

클라이언트는 인증 성공을 증명할 수단을 갖고 있어야 한다.

사용자가 인증에 성공한 상태를 세션이라고 부른다. 웹 사이트에서 로그인을 유지하기 위한 수단으로 쿠키를 사용한다. 쿠키에는 서버에서 발급한 세션 아이디를 저장한다. 쿠키를  통해 유효한 세션 아이디가 서버에 전달되고, 세션 스토어에 해당 세션이 존재한다면 서버는 해당 요청에 접근 가능하다고 판단한다. 하지만 쿠키에 세션 아이디 정보가 없는 경우, 서버는 해당 요청이 인증되지 않았음을 알려준다.

 

로그아웃

세션 아이디가 담긴 쿠키는 클라이언트에 저장되어 있으며, 서버는 세션을 저장하고 있다. 그리고 서버는 그저 세션 아이디로만 인증 여부를 판단한다. 쿠키는 세션 아이디, 즉 인증 성공에 대한 증명을 갖고 있으므로, 탈취될 경우 서버는 해당 요청이 인증된 사용자의 요청이라고 판단하기 때문에 우리가 공공 PC에서 로그아웃해야 하는 이유이다. 로그아웃은 서버에서 세션 정보를 삭제해야 하며, 클라이언트에서 쿠키를 갱신하거나 삭제해야 한다.

 

node.js에는 이런 세션을 대신 관리해주는 express-session이라는 모듈이 존재한다.

 

Hashing

암호화 방식 중 하나인 해싱은 복호화가 가능한 다른 암호화 방식들과 달리, 암호화만 가능하다.

해싱은 해시함수를 사용하여 암호화를 진행하는데, 해시 함수는 다음과 같은 특징을 가진다.

  • 항상 같은 길이의 문자열을 리턴한다.
  • 서로 다른 문자열에 동일한 해시 함수를 사용하면 반드시 다른 결과값이 나온다.
  • 동일한 문자열에 동일한 해시 함수를 사용하면 항상 같은 결과값이 나온다.

아래 표는 대표적인 해시 함수중 하나인 SHA1에 특정 입력 값을 넣었을 때 어떤 결과가 리턴되는지 보여주는 예시이다.

https://www.convertstring.com/ko/Hash/SHA1에서 SHA1 함수를 직접 사용해볼 수도 있다.

비밀번호해시 함수(SHA1) 리턴 값

‘password’ ‘5BAA61E4C9B93F3F0682250B6CF8331B7EE68FD8’
‘Password’ ‘8BE3C943B1609FFFBFC51AAD666D0A04ADF83C9D’
‘jiyeong’ ‘AF356A477E5BAD16BA0DCE55057B52AD23D042D9’

레인보우 테이블과 솔트

이전의 결과값을 미리 기록해놓은 표인 레인보우 테이블이 존재한다. 레인보우 테이블에 기록된 값이 유출되었을 때 해싱을 했더라도 해싱 이전의 값을 알아낼 수 있으므로 보안상 위협이 될 수 있다.

이 때 솔트를 사용한다. 솔트는 소름을 치듯 해싱 이전 값에 임의의 값을 더해 데이터가 유출되더라도 해싱 이전의 값을 알아내기 더욱 어렵게 하는 방법이다.

해싱의 목적

복호화가 불가능한 암호화 방식을 사용하는 이유는, 해싱의 목적이 데이터 그 자체를 사용하는 것이 아니라, 동일한 값의 데이터를 사용하고 있는지 여부만 확인하는 것이 목적이기 때문이다. 서버측에서 비밀번호를 모르는 상태에서 해싱한 값끼리 비교해서 일치하는지 확인하는 것이다. 해싱은 민감한 데이터를 다루어야 하는 상황에서 데이터 유출의 위험성은 줄이면서 데이터의 유효성을 검증하기 위해서 사용되는 단방향 암호화 방식이다.

Token

세션기반 인증과 토큰기반 인증이 있다. 세션 기반 인증은 서버(DB)에 유저 정보를 담는 인증 방식이다. 서버에서는 유저가 민감하거나 제한된 정보를 요청할 때마다 "지금 요청을 보낸 유저에게 우리가 정보를 줘도 괜찮은가?"를 확인하기 위해 클라이언트가 보낸 세션id를, 가지고 있는 세션 객체와 비교한다. 그런데 매 요청마다 데이터베이스를 살펴보는 것이 불편하고 부담을 덜어내고 싶다면 토큰기반 인증 방식을 사용할 수 있다.

 

토큰만 있으면 권한이 있음을 증명할 수 있고, 토큰의 종류에 따라 어느정도 권한을 가지고있는지도 확일할 수 있다. 토큰의 형식에는 여러 종류가 있지만 JWT를 가장 많이 사용한다.

 

aaaaaa.bbbbbb.cccccc

위와 같이 .으로 세 부분으로 나누어져 있으며 a가 header, b가 payload, c가 signature라고 부른다.

1. header

header는 이것이 어떤 종류의 토큰인지(JWT인지), 어떤 알고리즘으로 signature를 암호화할지가 적혀있다. JSON WEB Token 이라는 이름에 걸맞게 JSON형태로 정보가 담겨져있다.

{
    "alg": "HS256",
    "typ": "JWT"
}

이 JSON객체를 base64방식으로 인코딩하면 JWT의 첫 번째 부분인 헤더가 완성된다. base64는 디코딩할 수 있는 인코딩 방식으로 노출되어서는 안되는 민감한 정보를 담지 않도록 해야한다.

2. payload

payload에는 서버에서 활용할 수 있는 유저의 정보가 담겨있다.

여기에는 어떤 정보에 점근이 가능한지에 대한 권한, 유저의 이름과 같은 개인정보 등의 정보를 담을 수 있다.

payload는 signature를 통해 유효성이 검증될 정보이긴 하지만 역시 base64로 인코딩 되어있어 민감한 정보는 담지 않는 것이 좋다.

{	
    "sub":"someInformatino",
    "name":"jiyeong",
    "iat":151623391
}

3. signature

base64로 인코딩 된 Header와 Payload가 완성되었다면, Signature는 이를 서버의 비밀키와 Header에서 지정한 알고리즘을 사용하여 해싱한다.

예를 들어, 만약 HMAC SHA256알고리즘을 사용한다면 Signature는 아래와 같은 방식으로 생성된다.

HMASCHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret);

 

JWT의 종류

1. 엑세스토큰(Access Token)

엑섹스 토큰은 보호된 정보들에 접근할 수 있는 권한 부여에 사용하는 토큰이다.

2. 리프레시토큰(Refresh Token)

리프레시 토큰은 액세스 토큰을 재발급 받을때 사용하는 토큰이다.

 

클라이언트는 localStorage,SessionStorage,Cookie등 다양하 위치에 저장하며 HTTP헤더(Authorization헤더)또는 쿠키에 토큰을 담아 보낸다. 쿠키에는 리프레시 토큰을 헤더, 엑세스토큰은 바디에 담는 등 다양한 방식으로 구현할 수 있다. Authorization헤더를 사용한다면 Bearer Authentication을 이용한다.

서버는 토큰을 검증하여 토큰에 담긴 header와 payload를 서버의 secret으로 암호화한 값이 토큰의 signature와 일치하는지 확인하고 응답을 보내준다.

 

토큰기반 인증의 장점

1. Statelessness & Scalability(무상태성 & 확장성)

2. 안전하다

3. 어디에서나 생성 가능하다.

4. 권한 부여에 용이하다.

 

OAuth

 

  • Resource Owner: 사용자이며 정보 제공자이기도 하기 때문에 Resource Owner라고 한다.
  • Client: Resource Owner를 대신하여 보호된 리소스에 액세스하는 애플리케이션이다.
  • Local Server: Client의 요청을 수락하고 응답할 수 있는 서버다.
  • Resource Server: 사용자의 정보를 저장하고 있는 서버다.
  • Authorization Server: 인증을 담당하고 있는 서버다. Access Token을 발급하는 인증 서버다.
  • Authorization Grant: Client가 Access Token을 얻는 방법을 의미합니다. 다음과 같은 방법들이 주로 사용된다.
    • Authorization Code Grant Type
    • Refresh Token Grant Type
  • Authorization Code: Authorization Grant의 한 타입으로 Access Token을 발급받기 위한 Code를 의미한다.
  • Access Token: 보호된 리소스에 액세스하는 데 사용되는 인증 토큰이다. 이 Access Token으로 이제 Resource Server에 접근할 수 있다.
  • Refresh Token: 발급받은 Access Token이 만료될 시 Refresh Token을 통해 새로운 Access Token을 받급받을 수 있다.

 

'개발 > ' 카테고리의 다른 글

[리뷰] 번들링, Webpack  (0) 2022.08.09
[리뷰] REACT 심화  (0) 2022.07.12
[리뷰] 네트워크 심화  (0) 2022.06.30
[리뷰] 사용자 친화  (0) 2022.06.28
[리뷰] REDUX  (0) 2022.06.27
Comments