session & 암호화

이지우·2024년 6월 25일
0

멋사

목록 보기
12/16

session

세션 할당 원리

어플리케이션

  • 서버 서블릿이 가동

일반 메모리 영역

  • 서블릿 객체가 일반 메모리 영역에 하나 생성됨
    상속되는 모든 데이터도 함께 생성

application scope

  • 서버가 가동될 때 객체가 하나 생성됨(하나만)
  • 그 객체는 정보를 갖게 됨
    : param 테이블
    : attribute 테이블
    : 테이블이라서 key-value 형태로 저장 가능

은수, 길동, 톰 모두 웹 서버로 /index.html을 가져감
화면에 id, pw 입력 후 request 날림
서블릿에 req 도착

최초로 넘어가는 경우엔 쿠키가 없음
-> id, pw는 보통 post방식으로 넘김
-> url의 body에 데이터 채워짐

요청이 넘어가면 request queue에 쌓임
꺼내지면서 request 객체가 생성(쓰레드 객체)
이 객체들의 우선순위는 모두 동일하게 0
어떤게 먼저 작업할 지 모름

작업이 시작되면 메모리의 스택 영역의 맨 밑에 있는 메인 스택에 런 메소드 스펙 생성됨
여기에 request 객체와 response 객체의 주소를 가리킴

  • 쓰레드는 스택 영역 내에서 작업을 수행하며, 다른 쓰레드가 CPU 사용 권한을 소모하면 대기 상태로 넘어감
  • cpu 사용 권한의 시간은 아주 짧음
  • 이 과정이 반복되며, 쓰레드마다 작업 순서가 정해지지 않고 일정 순서대로 변경될 수 있음
  • 여러 쓰레드들이 조금씩 왔다갔다 하면서 작업 수행됨

request 정보들은 db에 가서 확인하는 작업이 일어남
확인이 완료되면 user객체가 생성되고 이 안에는 그 회원의 정보가 들어감
이 객체를 어딘가에 저장해두기 위해 세션 사용함

req.session: 세션 할당
세션에는 테이블 형태의 값이 저장됨
ex) user @100 / user라는 이름으로 100번지
-> 100번지를 가리키게 됨

쿠키(JSID)가 생성되고 response 헤더에 들어감
서블릿 객체로 인해 무언가가 일어나고 response가 web server를 거쳐서 응답되어짐 -> 커넥션 종료 -> 스택영역 삭제 -> 쿠키 삭제
하지만 user 정보는 남아있음 (30분)
이때 유지시간은 설정할 수 있지만 길게 설정하면 용량 문제가 생김

세션이 할당된 상태에서 웹 브라우저가 종료되어도 서버에서는 종료되었는지 모름 -> 30분간 유지 (비효율)
-> 모든 페이지에서 로그아웃 버튼이 보이게해서 로그아웃 하도록 함

saveUninitialized : true로 설정하면 어떤 사용자가 로그인하지 않아도 세션을 할당해줌
로그인하고 정보가 확인되어야 그 정보를 가리키는 세션이 생기도록 하기 위해 false로 하는 것이 좋다

로그인 버튼 클릭 시 url의 마지막에 서블릿에 도착하기 위한 서블릿 이름이 와야 함
url 뒤에 확장명이 정확하게 없거나 .do로 되어있는 경우면 서블릿일 수 있음
-> ❗ 서블릿 이름은 자신의 기술과 구조를 노출시키면 안돼서 별명 사용
-> 스프링 프레임워크에서 대표 서블릿을 .do라고 하는 예제를 많은 사람이 따라해서 .do를 보면 java로 만든것을 알게되어버림
-> .do가 아닌 다른 별명 사용하기


개발자모드에서 세션 id 지우면 같은 세션으로는 접속 못함
지우고 새로고침해도 세션을 생성할 생각이 없는데 세션이 생성됨
새로고침 할때마다 새로운 세션 생성
세션 계속 추가되면 DOS 공격이 될 수 있음

로그인 될 때만 세션 부여하기 위해
saveUninitialized: false로 지정

app.use(session({
  secret : 'adsfasdaf',
  resave : false,
  saveUninitialized : false 
}));

app.post('/login', (req, res) =>{
  console.log(req.body);
  mydb.collection('account')
    .findOne({userid:req.body.userid})
    .then(result => {
      //console.log(result);
      if(result != null && result.userpw == req.body.userpw){
        req.session.userid = req.body.userid;
        console.log(req.session);
        res.send('login ok');
      }else{
        res.send('login fail');
      }
    })
    .catch(err=>{
      console.log(err);
      res.status(500).send();
    });
});

로그인 성공 시 세션이 생성됨
세션에 userid가 아니라 req.body로 객체를 넣어줄 수도 있음

app.post('/login', (req, res) =>{
  console.log(req.body);
  mydb.collection('account')
    .findOne({userid:req.body.userid})
    .then(result => {
      //console.log(result);
      if(result != null && result.userpw == req.body.userpw){
        //req.session.userid = req.body.userid;
        req.session.user = req.body;
        console.log(req.session);
        res.send('login ok');
      }else{
        res.send('login fail');
      }
    })
    .catch(err=>{
      console.log(err);
      res.status(500).send();
    });
});

res.send(`${req.session.user.userid}님 환영합니다.`);

app.get('/bank', (req, res)=>{
  // 로그인되면 /bank 접속 가능
  if(req.session.user.userid){  // 세션에 userid가 있으면 로그인된 상태
    res.send(`${req.session.user.userid}님 자산 현황`);
  }else{
    res.send('로그인부터 해주세요');
  }
});

로그인 안된 상태일 때 user 세션을 찾을 수 없어서 에러 발생
❗ 어제 실습때 발생했던 에러

app.get('/bank', (req, res)=>{
  // 로그인되면 /bank 접속 가능
  if(typeof req.session.user != 'undefined'){  // 세션에 userid가 있으면 로그인된 상태
    res.send(`${req.session.user.userid}님 자산 현황`);
  }else{
    res.send('로그인부터 해주세요');
  }
});

undefined 상태일 경우 조건으로 수정하여 해결!


세션이 있으면 로그인 상태 유지

app.get('/login', (req, res) =>{
  if(req.session.user){
    res.send('이미 로그인 되어있습니다.');
  }else{
    res.render('login');
  }
});

로그아웃

if(user){
  반갑습니다. ..님 로그아웃
}else{
  로그인 해주세요. 로그인
}

<% if(user){ %>
  <h3>반갑습니다. <%= user.userid %>님</h3>
  <a href="/logout">로그아웃</a> 
<% }else{ %>
  <h3>로그인 해주세요.</h3>
  <p><p>
  <button class="w-100 btn btn-warning login"><b>로그인</b></button>
<% } %>

res.render index 페이지로 넘어가면 else로 들어갈 수 있지만
다이렉트로 접속하면 user가 undefined되었다는 오류 발생
-> if에 조건 추가

<% if(typeof user !=='undefined' && user){ %>
      <h3>반갑습니다. <%= user.userid %>님</h3>
      <a href="/logout">로그아웃</a> 
    <% }else{ %>
      <h3>로그인 해주세요.</h3>
      <p><p>
      <a href="/login" class="w-100 btn btn-warning login"><b>로그인</b></a>
    <% } %>

로그인 후 세션이 있는 상태
여기에서 index페이지를 직접 요청하면 foward가 아니라서 user가 없음 -> 로그인해주세요 (else문) 실행됨

app.get("/", function (req, res) {
  if(req.session.user){
    //res.send('이미 로그인 되어있습니다.');
    res.render('index.ejs', {user:req.session.user});
  }else{
    res.render('index.ejs', {user:null});
  }
});

app.get("/", function (req, res) {
  if(typeof req.session.user !== 'undefined' && req.session.user){
    //res.send('이미 로그인 되어있습니다.');
    res.render('index.ejs', {user:req.session.user});
  }else{
    res.render('index.ejs', {user:null});
  }
});

이렇게 수정해도 안됨
❗❗ session 설정한 내용 위에 작성했어서 난 오류였다
session 설정 아래로 내려주니 잘 작동 함

여기에서는 typeof req.session.user !== 'undefined' && 추가 안해줘도 됨!


보안 상 모든 페이지에서 로그인 여부가 보여야 함
-> 모든 페이지에 있는 nav 영역에서 로그인 여부를 인식이 가능하도록 코딩해야 함

성능을 고려하면 위에 했던 작업은 좋지 않음
nav 페이지를 갈때마다 user 데이터를 들고 가야함
html로 만들었었는데 동적 처리를 위해 menu.ejs로 바꾸고 데이터를 들고 가게 해야하는데 이는 좋지 않음
이유: ssr이어서 client에서 요청할 때마다 동적처리해서 nav를 완성한 상태를 넘겨야 함 -> 모든 요청을 ssr해야하여 서버 부하

세션 id는 클라이언트의 cookie 형태로 있으니 세션이 존재하면 js로 html에 포함하여 로그인 상태로 보여주고 그렇지 않으면 로그인 내용을 안보여주게 처리 (서버 부하 없앨 수 있음)
문제는 세션 id는 js로 핸들링될 수 없는 보안쿠키임

  • HttpOnly는 js로 사용 불가능한 보안 쿠키
  • node.js가 아닌 html 안에서 사용하는 바닐라 js를 말함

회원가입

signup.ejs

<div class = "container mt-4">
  <form action = "/signup" method="post">
    <div class = "form-group">
      <label>아이디</label>
      <input type="text" name = "userid" class = "form-control">
    </div><p></p>
    <div class="form-group">
      <label>비밀번호</label>
      <input type="text" name = "userpw" class = "form-control">
    </div><p></p>   
    <div class="form-group">
      <label>소속</label>
      <input type="text" name = "usergroup" class = "form-control">
    </div><p></p>   
    <div class="form-group">
      <label>이메일</label>
      <input type="text" name = "useremail" class = "form-control">
    </div><p></p>             
    <button type = "submit" class="btn btn-primary" style="float:right">가입</button>
  </form>
</div>

app.get("/signup", (req, res)=>{
  res.render('signup');
});

app.post("/signup", (req, res)=>{
  console.log(req.body);
});

app.post("/signup", (req, res)=>{
  console.log(req.body);
  mydb.collection('account')
    .insertOne(req.body)
    .then(result => {
      console.log('회원가입 성공');
    })
    .catch(err=>{
      console.log(err);
    });
  res.redirect('/');
});

암호화

비밀번호 암호화

input type='password'

암호화를 위해 비밀번호 타입으로 변경

사용자는 입력을 평문으로 하고 저장되어 있는 것은 해쉬로 암호화됨

똑같은 해쉬 알고리즘으로 암호화하여 암호화되어 있던 값과 비교


profile
노력형 인간

0개의 댓글