[GO] Session 생성

타키탸키·2022년 11월 16일
0

GO-WEB

목록 보기
7/11
post-custom-banner

Session

  • 세션(session)
    • 웹 사이트의 여러 페이지에 걸쳐 사용되는 사용자 정보를 저장하는 방법
    • 사용자가 브라우저를 닫아 서버와의 연결을 끝내는 시점까지를 의미
  • 쿠키와의 차이점
    • 쿠키는 클라이언트 측의 컴퓨터에 모든 데이터 저장
    • 세션은 서비스가 돌아가는 서버 측에 데이터 저장
      • 세션의 키 값만을 클라이언트 측에 저장
      • 브라우저는 필요할 때마다 이 키 값을 이용하여 서버에 저장된 데이터 사용
    • 보안에 취약한 쿠키를 보완하는 역할
  • 상태 생성
    • 고유 식별자를 쿠키에 저장하거나 URL에 심는 것
    • 이때, 서버는 각 사용자를 고유 식별자와 연관시킨다
      • 웹 사이트를 방문하는 모든 사용자 식별 가능
    • ID의 고유성과 HTTP 전송의 암호화
      • 쿠키와 고유 식별자를 통해 생성된 세션의 보안에 기여하는 두 가지 요인
    • 서버와 클라이언트 사이의 연결은 일회성이기 때문에 연속성을 위한 상태 생성이 중요하다
  • 고유 식별자
    • 사용자가 서버에 요청을 보내면 고유 식별자를 전송해준다
    • 이를 통해 서버와 통신하는 대상에 대한 정보를 알 수 있다
    • 특정 개인에 대한 정보를 서버에 유지할 수 있게 한다
    • 서버에 접근하는 대상을 구분하여 그 대상에 따라 정보 접근 권한이 달라진다
    • 정보를 열기 위한 열쇠
  • 고유 식별자 저장 방법
    • 쿠키
      • 지정 도메인에 따라 다름
      • 클라이언트의 컴퓨터에 도메인으로부터의 쿠키가 있다면 클라이언트가 도메인으로 보내는 모든 요청의 쿠키가 서버에 간다
      • 이를 통해 사용자 식별이 가능해진다
    • URL
      • 다른 페이지로 가기 위해 링크를 누를 때마다 URL의 매개 변수 혹은 고유 식별자를 갖춘 URL의 변수 등이 식별자로 사용된다
      • 쿠키가 없더라도 고유 식별자를 URL에 동적으로 연결하여 요청을 보낼 때마다 확인 가능
      • HTTPS를 사용하면 TLS와 보안 연결에 의해 안전하게 보호된다
      • 데이터가 필드로 전송되는 동안 전부 암호화되기 때문
  • UUID
    • 범용 고유 식별자
    • 수가 매우 많아 앞으로 백 년 동안은 거뜬히 만들어낼 수 있다
    • HTTPS를 사용하는 전송을 중단할 수 없다
  • 데이터베이스 키
    • 고유 식별자로 사용 가능
    • 사용자 키가 아니라 사용자를 더 안전하게 만들어주는 세션용 테이블 키
  • 세션 원리
    • 클라이언트가 서버로 고유 식별자(세션 ID, SID) 전송
    • 세션 DB
      • 특정 사용자 ID와 연관된 저장 공간
    • 고유 식별자가 있는 사용자 ID를 알면, 사용자에 관한 정보를 모두 확인 가능
      • 사용자 ID를 통해 사용자 정보에 접근 가능
      • 게시물, 신용카드, 로그인 이메일, 비밀번호, ...
    • 세션 ID는 사용자 ID와 연결됨
    • 세션 DB와 사용자 DB는 분리된 공간
      • 세션은 일시적이지만 사용자 정보는 영구적
    • 사용자가 새 세션을 만들고 새로운 세션 ID를 만들면 그 세션 ID를 사용자 ID와 연결한다
    • 쿠키와 세션 ID를 사용해 세션 생성의 바탕이 되는 사용자 ID를 가져오는 것

UUID

  • UUID
    • 범용 고유 식별자
    • 네트워크 상에서 고유성이 보장되는 ID를 만들기 위한 표준 규약
    • 128비트의 숫자이며, 32자리의 16진수로 표현된다
    • 8자리-4자리-4자리-4자리-12자리 패턴
      • 하이픈을 집어 넣어 5개의 그룹으로 구분
  • UUID 생성하기
    • Cookie를 요청했을 때 Cookie가 없으면 새로운 UUID 생성
      • goolge package의 uuid 모듈로 대체(satori 지원 안 함)
      • import error 발생 -> build는 됨
      • sumdb 파일 삭제 후, src에 모듈 설치
      • uuid.New()
    • 생성된 UUID는 쿠키의 Value 필드에 넣어 전송한다
    • Cookie 옵션 - HttpOnly
      • 브라우저가 서버에 http request를 요청할 때만 쿠키 전송 허용
    • Cookie 옵션 - Secure
      • 브라우저와 서버가 HTTPS로 통신할 때만 쿠키 전송 허용

회원 가입 예제

  • index 페이지
    • 사용자 정보 가져오기
    • 가져온 정보 화면에 띄우기
  • bar 페이지
    • 사용자 정보 가져오기
    • 로그인 여부 확인하기
      • 로그인이 안되어 있으면 index 페이지로 redirect
    • 로그인 후, 접속할 최종 목표 페이지
  • signup 페이지
    • 로그인 여부 확인하기
      • 로그인이 되어 있으면 index로 redirect
      • 로그인이 이미 되어 있으면 가입 할 필요가 없다
    • POST 메서드로 제출된 Form data 가져오기
      • 가져온 데이터는 user 객체에 저장
      • username이 이미 존재하면 에러 띄우기
    • 새로운 세션 생성하기
      • uuid 생성하기
      • cookie 생성하기(uuid, 세션 id)
      • 세션 DB에 사용자 이름으로 접근하여 user 객체 할당하기
      • 등록이 완료되면 index 페이지로 redirect
  • 동일 패키지 내, go 파일이 여러 개일 때
    • go run .으로 실행
    • go run *.go로 실행
    • go build로 실행
      • 실행 가능한 바이너리로 빌드하여 최종 결과물을 작업 폴더에 넣는다

로그인/로그아웃 예제

  • bcrypt로 비밀번호 암호화 하기
    • 블로피시 암호에 기반을 둔 암호화 해시 함수
    • .GenerateFromPassword(비밀번호, 암호화 수준)
      • 사용자로부터 받은 비밀번호를 byte slice 형태로 암호화한다
      • 암호화 수준을 결정할 수 있다
      • 사용자가 설정한 비밀번호는 사용자만 안다
    • ex:) [36 50 97 36 48 52 36 76 53 ** 67 69 50 78 80 52 48 122 101 47 56 114 49 73 83 86 72 80 ** 121 53 66 98 47 121 116 100 76 106 77 56 ** 74 90 113 119 * 97 77 109 86 67 88 115 99 52 72 ** 76 87]
    • .CompareHashAndPassword(db에 저장된 해시, 사용자 비밀번호 해시)
      • 두 해시 값을 비교하여 사용자가 입력한 비밀번호가 db에 저장된 비밀번호화 같은지 확인
      • 엄밀히 따지면 사용자가 입력한 비밀번호가 아닌 해당 비밀번호에 대한 해시 값을 비교하는 것
  • login 페이지
    • 로그인 여부 확인
      • 로그인 되어 있으면, index 페이지로 redirect
    • 사용자가 입력한 이메일과 비밀번호 가져오기
    • DB에 해당 정보가 있는지 확인
      • 없으면 user name이 틀렸다는 문구 출력
    • DB에 저장된 해시와 사용자가 입력한 비밀번호의 해시 비교하기
      • 맞지 않으면 password가 틀렸다는 문구 출력
    • 세션 생성하기
  • logout 페이지
    • 로그인 여부 확인
      • 로그인 되어 있지 않으면, index 페이지로 redirect
    • session에 대한 쿠키 가져오기
    • dbSession에서 session ID 삭제하기
    • 쿠키 삭제하기
      • MaxAge가 음수이면, 쿠키 바로 삭제
    • login 페이지로 redirect
  • 권한 부여하기
    • user struct에 role 추가하기
    • Form으로부터 role 입력 받기
      • admin만 설정 가능
    • 최종 접속 페이지(bar)에서 권한에 따라 접속 허용하기
  • 세션 만료하기
    • 절차
      • 회원 가입하기
      • 30초 전에 bar 페이지를 가면 정상적으로 접속 된다
      • 30초 뒤에 bar 페이지를 가면 안 들어가진다(redirect)
    • DB session에 사용자 이름과 마지막 활동 시간을 포함하는 session struct를 포함한다
      • session ID를 통해 사용자 이름과 마지막 활동 시간에 접근 가능
    • session 길이를 설정한다
      • ex:) const sessionLength int = 30
    • init 함수에서 정리된 db Session 변수에 현재 시간을 넣어준다
      • session이 정리될 때마다 현재 시간으로 초기화 된다
    • session을 정리하는 함수를 정의하고 로그아웃 시에 호출한다
      • 현재 시간에서 앞서 정의한 정리된 dbSession 변수에 담긴 시간을 뺀 수를 확인한다
      • 현재 session을 보여주고 dbSession을 순회하며 session 길이를 초과한 user를 삭제한다
      • 정리된 db session 변수를 현재 시간으로 초기화 한다
      • 정리 후의 session을 보여준다
    • session 만료 후, 동일한 user name으로 접근하면 새로운 session이 부여된다
    • 쿠키를 생성할 때마다 쿠키의 만료 시간을 session 길이로 설정한다
  • Map과 동시성
    • map에 없는 값을 지워도 에러가 나지 않는다
    • map에 없는 값에 접근(read)해도 에러가 나지 않는다
      • 0을 대신 반환해준다
    • 오직 map에 새로운 값을 추가하거나 변경(write)할 때 에러가 난다
      • 동시성 이슈
      • 하나의 goroutine에서 map에 값을 쓸 경우, 다른 goroutine에서는 해당 map에 값을 읽거나 쓸 수 없다
      • 위와 같이 동시성을 잘못 구현할 경우, 런타임이 문제를 인식하고 프로그램을 종료시킨다
package main

import (
	"fmt"
)

func main() {
	m := map[int]int{}
	m[4] = 3
	delete(m, 7)
	fmt.Println(m) // map[4:3]
	fmt.Println(m[5]) // 0
}
  • time.Time은 다수의 goroutine에서 동시에 사용 가능하다
profile
There's Only One Thing To Do: Learn All We Can
post-custom-banner

0개의 댓글