인증요청1. 세션(Session)을 사용하려면, 웹보안을 알아야 한다. [TIL / node.js]

알락·2022년 11월 1일
0
post-thumbnail

이제는 새로운 서비스의 개발에서는 거의 쓰지 않을 것 같은 Session이다. 많은 경우 OAuth나 자체적으로 Token을 발행하는 인증 방식을 취하는 것 같다. 하지만 여전히 레거시한 서비스에서는 Session을 사용하는 경우도 있다. 그리고 OAuthToken이 갖는 단점을 오히려 Session이 해결을 해줄 수도 있으니 알고 있으면 취할 수 있는 인증 방식의 선택지가 늘어날 것이라 생각된다.


세션(Session)

HTTP 통신은 Stateless한 특징을 갖고 있다. 즉, 상태가 없어서 요청과 응답의 과정만 존재한다. 하지만 지금의 웹서비스는 ID와 비밀번호로 본인 확인을 요청하고 난 이후, 로그인이 되어있는 '상태'로 해당 웹서비스가 제공하는 다른 페이지를 향유할 수 있다. 이것을 가능하게 하는 방법은 여러가지가 있지만 이번에는 세션(Session, 이하 세션)에 집중해보려고 한다.

⌞ 쿠키의 문제점

세션의 등장에는 쿠키(Cookie, 이하 쿠키)를 빼놓고 얘기할 수 없다. 쿠키는 상태 정보를 클라이언트에서 보관하고 있는 것이다. 문제는 비밀번호와 같이 사용자 본인의 프라이버시 노출될 취약한 정보가 쿠키에 저장되어있으면 다른 사람들도 볼수 있는 소지가 생긴다는 것이다.

JavaScriptdocument.cookie만 입력하여도 손쉽게 cookie에 접근할 수 있었다.

세션은 민간한 정보를 클라이언트가 보관하지 않고, 서버에서 보관한다. 그리고 해싱하여 난해한 문자열로 id를 발급해 클라이언트용으로 세션-쿠키를 발급한다. 그래서 쿠키에 비해 비교적 안전한 인증 확인을 할 수 있다.


⌞ 세션의 문제점 1.

결국 세션도 쿠키와 같이 클라이언트의 상태를 다른 페이지에 걸쳐서 유지시키는 기능을 한다고 할 수 있다. 하지만 여전히 문제점은 남아있다. 결국 다른 이용자가 세션을 탈취하여 서버에 신원확인을 요청하면 유효해서 악용할 여지가 생긴다. 쉽게 말하자면, 다른 이용자가 나로 빙의해서 웹사이트 이용이 가능한 것이다.

⌞ 문제를 해결하려는 노력

결국 세션의 ID가 담기는 쿠키에 대한 제한이 이루어졌다.

⌞ 서버 측 노력

쿠키에 담길 수 있는 정보들을 알아보자.

  • Secure :
    Secure가 지정되어있는 Cookie는 https 프로토콜을 사용하는 암호화 전송에서만 이용이 가능한 쿠키다.
  • HttpOnly :
    Cross-Site Script(CSX) 공격에 대응하기 위하여 Http 통신에서만 사용 가능한 쿠키로 지정하는 옵션이다. 위에서처럼 JavaScript로 쿠키에 접근이 불가능하다. 특히 세션에 대한 정보는 서버에서 관리를 하기 때문에 HttpOnly를 꼭 사용하는 편이다.
  • SameSite :
    Cross-Origin을 허용하지 않고 같은 도메인을 사용하는 서버에만 전달되어진다. 모든 브라우저에서 제공되는 기능은 아니라고 한다.
  • Domain :
    SameSite와 비슷한데, 쿠키를 주고 받을 수 있는 Domain 주소를 지정하는 것이다. 에를 들면 "velog.io"를 지정했다면, 해당 주소를 사용하는 서버하고만 쿠키를 주고 받을 수 있다.
  • Path :
    쿠키가 전송되어 최종적으로 사용되는 경로를 지정할 수 있다. "/user/login" 같은 형식으로 지정하면 된다.

서버 측에서 응답으로 보내는 헤더의 Set-Cookie 예시는 다음과 같을 것이다.

Set-Cookie : id=3jqwm; Secure; HttpOnly; SameSite;

쿠키를 이와 같이 명시하여 발급해주면 쿠키가 악의적으로 탈취되는 것을 조금 예방할 수 있다. 하지만 완전한 해결책은 아니기 때문에 완전히 신뢰하고 쓸 수 있는 방법은 아니다.

⌞ 클라이언트 측 노력


이건 예시를 보고가면 좋을 것 같다. 요청 측 헤더 WithCredentials 관련한 것이다. 클라이언트 측에서 서버에 인증 요청을 할 때 헤더로 Credential 체크 여부를 먼저 확인한다. 서버 측에서는 해당 여부에 대해 Access-Control-Allow-Credentials를 응답 헤더에 true의 값으로 반환을 해줘야 비로소 자격증명에 관련한 작업들을 클라이언트에게 전해줄 수 있다. 이를테면 쿠키 생성이 있다.

Credentials란 쿠키, Authorization(인증헤더), TLS client certificates(증명서)를 말한다.

클라이언트 코드

function clickLoginBtnHandler(){
        axios.post(`https://localhost/login`,
            {userId, userPassword},
            {withCredentials: true}
        )
        .then(res=>{
           	loginSuccess();
        }).catch(err=>{
            loginFalse();
        })
    }

서버 코드(인증 부분)

const signinUser = async (req, res)=>{
		// 요청의 body에서 입력정보 받아오기
  		const userId = req.body.userId;
        const plainPassword = req.body.userPassword;
  
  		// 패스워드 암호화(테스트 목적으로 간단하게만 구현했습니다.)
  		// 원래는 소금도 쳐줘야해요.
        const hashedPassword = await hash.update(plainPassword).copy().digest("hex");
        
  		// 데이터베이스에 입력된 id 관련 데이터 요청
        const userLeastInfo = await Users.findOne({
            attributes : ["userId", "password"],
            where : {
                userId,
            }
        })
        .then(res => res)
        .catch(err => err)
    
        // 반환된 데이터와 입력된 데이터 대조
        if (userLeastInfo && userLeastInfo.get("password") === hashedPassword) {
          	
          	// ***** 세션을 저장하는 과정 *****
            req.session.userId = userLeastInfo.get("userId");
            req.session.save();
            res.status(200).send({msg : "ok"});
        }
        else res.status(401).send({msg : "입력하신 아이디와 비밀번호가 잘못되었습니다."})

서버 코드(CORS 설정 부분)

const corsOption = {
    credentials : true,
    origin : ["https://localhost:XXXX"],
    method : ["GET", "POST", "OPTIONS"],
}

클라이언트에서 서버측에 아이디와 비밀번호를 body로 전송하여 신원확인을 요청하는 코드다. 일전에 CORS를 다룰 때 Preflight Request가 미리 서버에 요청되는 경우가 있다고 다룬 바 있다. 신원 요청에서도 이 Preflight Request가 미리 요청되어진다. 그리고 해당 클라이언트의 요청에서는 Credential 정책 여부를 확인한다. 세션을 클라이언트와 잘 주고받기 위해서는 관련한 값들을 잘 전달해주어야한다.
Express에서는 해당 설정을 CORS 미들웨어로 가능하니까 참고해두면 좋을 것 같다.


⌞ 세션의 문제점 2.

세션의 정보가 서버에 저장된다는 것이다. 몇 십 명 정도의 정보가 저장이 된다면 부화는 크지 않을 것이다. 하지만 'SNS'나 '커머셜' 사이트 같은 경우에는 한 번에 접속하는 인원이 다수다. 이를 모두 서버에서 유지하고 있으려고 하면 자원이 많이 쓰인다.
보통 지정을 안해주면 세션은 서버의 메모리에서 관리하게 된다. 온메모리 데이터를 따로 데이터베이스에 저장하여 관리한다고 해도, 어쨌든 서버의 관리를 요한다.
결국 이 때문에 비교적 덜 민감한 정보들과 함께 인증 요청에 대해서는 Token을 이용하여 클라이언트가 들고 있게 한다.

참고

profile
블록체인 개발 공부 중입니다, 프로그래밍 공부합시다!

0개의 댓글