암호화 방식 중 하나로 다른 암호화 방식들과 달리, 해싱은 암호화만 가능하다.
- 해시 함수를 사용하여 암호화를 진행한다.
해시함수는 특징이있다
- 항상 같은 길이의 문자열을 리턴한다.
- 서로 다른 문자열에 동일한 해시 함수를 사용하면 반드시 다른 결과값이 나온다.
- 동일한 문자열에 동일한 해시 함수를 사용하면 항상 같은 결과값이 나온다.
항상 같은 결과값이 나온다는 특성을 이용해 해시 함수를 거치기 이전의 값을 알아낼 수 있도록 기록해놓은 표인 레인보우 테이블이 존재한다.
해싱 이전 값에 임의의 값을 더해 데이터가 유출 되더라도 해싱 이전의 값을 알아내기 더욱 어렵게 만드는 방법으로 위에서 레인보우 테이블의 보안상 위협을 보완하는 방법이다.
- 솔트를 사용하게 되면 해싱 값이 유출되더라도, 솔트가 함께 유출 된 것이 아니라면 암호화 이전의 값을 알아내는 것은 불가능에 가깝다.
데이터 그 자체를 사용하는 것이 아니라, 동일한 값의 데이터를 사용하고 있는지 여부만 확인하는 것이 목적이다.
예를 들어
사이트 관리자는 사용자의 비밀번호를 알고있을 필요가 없다.
보통 비밀번호를 데이터베이스에 저장할 때, 복호화가 불가능하도록 해싱하여 저장하게 된다.
해싱은 복호화가 불가능하므로 사이트 관리자도 정확한 비밀번호를 알 수 없게 된다.
그래서 사용자가 로그인 요청 시 해싱한 값끼리 비교하여 일치하는지만 확인한다.
해싱은 민감한 데이터를 다루어야 하는 상황에서 데이터 유출의 위험성은 줄이면서 데이터의 유효성을 검증하기 위해서 사용되는 단방향 암호화 방식이다.
토큰 기반 인증은 기존의 세션 기반 인증이 가지고 있던 한계를 극복하고자 고안되었다.
세션 기반 인증은 서버에서 유저의 상태를 관리
서버의 부담을 줄이기 위해 서버가 사용자의 인증 상태를 저장하는 것이 아닌 클라이언트에 이를 저장하는 방법을 고민하게 되었고, 그 결과 토큰 기반 인증 방식이 등장했다.
토큰은 유저의 인증 상태를 클라이언트에 저장할 수 있어서, 세션 인증 방식의 비교해 서버의 부하나 메모리 부족 문제를 줄일 수 있다.
웹 보안에서의 토큰은 인증과 권한 정보를 담고 있는 암호화된 문자열을 말한다.
이를 이용해 특정 애플리케이션에 대한 사용자의 접근 권한을 부여할 수 있다
사용자가 인증 정보를 담아 서버에 로그인 요청을 보낸다.
서버는 데이터베이스에 저장된 사용자의 인증 정보를 확인한다.
인증에 성공했다면 해당 사용자의 인증 및 권한 정보를 서버의 비밀 키와 함께 토큰으로 암호화한다.
생성된 토큰을 클라이언트로 전달한다.
서버는 전달받은 토큰을 서버의 비밀 키를 통해 검증한다.
이를 통해 토큰이 위조되었는지 혹은 토큰의 유효 기간이 지나지 않았는지 등을 확인할 수 있다.
토큰이 유효하다면 클라이언트의 요청에 대한 응답 데이터를 전송한다.
확장성 : 다수의 서버가 공통된 세션 데이터를 가질 필요가 없다는 것도 토큰 기반 인증의 장점이다.
이를 통해 서버를 확장하기 더 용이합니다.
어디서나 토큰 생성 가능 : 토큰의 생성과 검증이 하나의 서버에서 이루어지지 않아도 되기 때문에 토큰 생성만을 담당하는 서버를 구축할 수 있다.
이를 잘 활용하면 여러 서비스 간의 공통된 인증 서버를 구현할 수 있다.
권한 부여에 용이 : 토큰은 인증 상태, 접근 권한 등 다양한 정보를 담을 수 있기 때문에 사용자 권한 부여에 용이하다.
이를 활용해 어드민 권한 부여 및 정보에 접근할 수 있는 범위도 설정할 수 있다.
토큰 기반 인증 구현 시 대표적으로 사용하는 기술이다.
- JWT는 JSON 객체에 정보를 담고 이를 토큰으로 암호화하여 전송할 수 있는 기술이다.
- 클라이언트가 서버에 요청을 보낼 때, 인증정보를 암호화된 JWT 토큰으로 제공하고, 서버는 이 토큰을 검증하여 인증정보를 확인할 수 있다.
{
"alg": "HS256",
"typ": "JWT"
}
2.Payload
Payload는 HTTP의 페이로드와 마찬가지로 전달하려는 내용물을 담고 있는 부분이다.
{
"sub": "someInformation",
"name": "phillip",
"iat": 151623391
}
HMAC SHA256 알고리즘을 사용한다면 Signature는 아래와 같은 방식으로 생성
HMACSHA256(base64UrlEncode(header) + '.' + base64UrlEncode(payload), secret);
jwt.io를 참고하여 한번 알아봐도 좋다
Signature을 사용해서 위조된 토큰을 알아낼 수는 있지만, 토큰 자체가 탈취된다면 토큰 인증 방식의 한계가 있다.
무상태성
인증 상태를 관리하는 주체가 서버가 아니므로, 토큰이 탈취되어도 해당 토큰을 강제로 만료시킬 수 없다.
토큰이 만료될 때까지 사용자로 가장해 계속해서 요청을 보낼 수 있게 된다.
유효 기간
토큰이 탈취되는 상황을 대비해서 유효 기간을 짧게 설정하면, 사용자는 토큰이 만료될 때마다 다시 로그인을 진행해야 하기 때문에 좋지 않은 사용자 경험을 제공한다.
그렇다고 유효 기간을 길게 설정하면 토큰이 탈취될 경우 더 치명적으로 작용할 수 있다.
토큰의 크기
토큰에 여러 정보를 담을 수 있는 만큼, 많은 데이터를 담으면 그만큼 암호화하는 과정도 길어지고 토큰의 크기도 커지기 때문에 네트워크 비용 문제가 생길 수 있다.
토큰 인증의 한계를 극복하기 위한 방법 중 하나
Access Token
액세스 토큰은 말 그대로 서버에 접근하기 위한 토큰으로 앞서 다룬 토큰과 비슷한 역할을 한다.
따라서 보안을 위해 보통 24시간 정도의 짧은 유효기간이 설정되어 있다.
Refresh Token
리프레시 토큰은 서버 접근을 위한 토큰이 아닌 액세스 토큰이 만료되었을 때 새로운 액세스 토큰을 발급받기 위해 사용되는 토큰이다.
따라서 리프레시 토큰은 액세스 토큰보다 긴 유효기간을 설정한다.
두 가지의 각기 다른 토큰을 사용하는 경우, 액세스 토큰이 만료되더라도 리프레시 토큰의 유효기간이 남아있다면 사용자는 다시 로그인을 할 필요 없이 지속해서 인증 상태를 유지할 수 있다.
하지만 리프레시 토큰의 도입도 모든 문제를 해결해주진 않는다.
리프레시 토큰은 긴 유효 기간을 가지고 있어 해당 토큰마저 탈취된다면 토큰의 긴 유효 기간 동안 악의적인 유저가 계속해서 액세스 토큰을 생성하고 사용자의 정보를 해킹할 수도 있기 때문이다.
- 이를 대비하기 위해 리프레시 토큰을 세션처럼 서버에 저장하고 이에 대한 상태를 관리하기도 한다.
세상에 완벽한 보안 방법은 없다.
내가 구현하려는 서비스에 어떤 인증 방식이 가장 적절한지 판단하고 의사결정 할 줄 아는 것이 가장 중요하다.
이때 보안과 사용자 경험 사이의 적절한 균형을 찾아야한다.