본문 바로가기

블록체인 기반 핀테크 및 응용 SW개발자 양성과정 일기

[52일차]20210527 JWT token 토큰 만들어 브라우저 cookie에 저장하기

반응형

server1이 꽉차면 server2로 가게됨 (여기서 client는 재로그인을 해야함 )

문제 해결 위해 : 브라우저가 내용을 가지고 있게됨 => 보안취약

-> data 암호화해서 token 보내줌 

 

위의 흐름 중 5번 중요 ! 

6. server는 middleware를 통해 token 쳌 

 

* 토큰의 생성 

 

google jwt (json web token) -> application, webside 등등 모두 사용

https://jwt.io/

 

JWT.IO

JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.

jwt.io

token = 문자로 표현되어 있음 (SJDnshdLS..) 

 토큰을 만들 때 이미 암호화를 거침. ( 규격이 있슴) 

우리가 받아서 복구화 , 복구화의 결과 = json 

 

오늘 수업 : 토큰 생성 ( 암호화와 함께 ) 

알록달록

암호화된token = header, payload, verify signature 세개로 구성되어 있음

Encoded token 을 브라우저가 들고 댕기다가 server한테 줄 때마다  server가 복구화, 일치확인, 응답. 

 

사용 이유 : server가 다수가 되었을 때 회원이 로그인 할 때마다 정보 공유가 어려움. 차라리 고객이 들고 다니게 만들었고 보안의 이유상 암호화를 시킨 것  => 메모리적으로 server에게 좋음. 

 

 

 


 

 

Header : 토큰의 정보 , 타입,

alg = 알고리즘? 

 

바이너리 데이터(Binary data) 

우리가 쓰는 모든 text 파일  

 

 

 

 

 

 

 

 

 

-> 글자를 16진수로 바꿈 

 

 

 

image도 text로 이루어져있는데 -> 요 text도 binary data이다. 

 

 

 

 

 

15 -> 16진법으로 F 

15 -> 이진법으로 1111 (4비트, 4자리수)

15를 2로 나눠 신기하군

 

 

 

2진수 (0,1) - 컴퓨터 최애 -> 0,1만 표현하면 데이터 넘 많아지니깐 요걸 해결하기위해 16진수 사용 

8진수 (0~7)

10진수 (0~9) 

16진수 (0~9 + A~F) 

 

컴퓨터가 16진수 -> 2진수 바꾸기 쉽다. 

2진수는 16진수를 좋아함 

16진수는 64진수를 좋아함

 

.toSTring('base64') => 글자가 더 줄여짐 

 

let header 를 암호화하기

객체라서 - JSON.stringify() 를 통해 

Buffer.from () - 안에 String 값이 들어감 -> header는 객체 -> Object를 String으로 바꿔주기 (by JSON.stringify())  = 저렇게 객체처럼 생긴 글자를 만든다는 것 (객체처럼 생김 근데 string) 

 

 

let txt = "마포대교는 무너졌냐ㅑ";
let header = {
    "alg":"HS256",
    "typ":"JWT"
}


console.log(typeof header);
console.log(typeof JSON.stringify(header));
console.log(header);
console.log(JSON.stringify(header));
console.log(header.alg);  //Object  - 된다. 
console.log(JSON.stringify(header).alg);  // Stirng - 안된다. 

let txt2 = Buffer.from(JSON.stringify(header)).toString('base64').replace('=','');

console.log(txt2);

컴퓨터가 읽기 쉬운 바이너리 파일로 만들고 -> 64진수로 만든 것 : header만들기 끗 

-> 아직 암호화는 아님

 

 

 

 

Payload 도 똑같이 

let payload = {
    "sub":"123456678",
    "name":"John Doe",
    "iat":123325,
}

let encodepayload = Buffer.from(JSON.stringify(payload)).toString('base64').replace('=','');
console.log(encodepayload);

 

 

Buffer.from

The Buffer.from() method creates a new buffer filled with the specified string, array, or buffer.

let payload = {
    "sub":"123456678",
    "name":"John Doe",
    "iat":123325,
}

console.log(Buffer.from(JSON.stringify(payload)));
console.log(Buffer.from(JSON.stringify(payload)).toString('base64'));

let encodepayload = Buffer.from(JSON.stringify(payload)).toString('base64').replace('=','');
console.log(encodepayload);


let a = Buffer.from('a');
let b = Buffer.from([1,2,3])
console.log(a)
console.log(b)

 

 

*buffer, 버퍼란?

 

하나의 장치에서 다른 장치로 데이터를 전송할 경우에 양자간의 데이터의 전송속도나 처리속도의 차를 보상하여 양호하게 결합할 목적으로 사용하는 기억영역을 버퍼 또는 버퍼 에어리어라고 한다. 보통 중앙처리장치와 단말이나 다른 입출력장치사이의 데이터 송수신에는 입출력 영역으로서 버퍼를 필요로 한다. 또, 중앙처리장치와 주기억장치의 사이에 고속으로 동작하는 소용량의 버퍼 메모리(로컬 메모리라고도 한다)를 설치하여 처리의 고속화를 꾀하는 방식도 있다.

[네이버 지식백과] 버퍼 [Buffer] (정보통신용어사전, 2008. 1. 15., 윤승은)

 

 

 

 

Verify Signature 

위의 두가지 정보(Header, Payload) 를 받아서 암호화를 한 내용을 담는 공간 = 비밀 키 

 

암호화 하는 package 다운 받기 

$npm install crypto

const crypto = require('crypto')

//첫번째 인자값 : 어떤 암호화 할건지 (sha256)
//두번째 인자값 : 암호화 규칙 : string = 우리가 임의대로 만들어 놓은 key값 = 16진수로 만들어 놓기  
// 두번째값 - 요 값을 가지고 sha256 암호 형태로 결과값을 주겠다.
let signature = crypto.createHmac('sha256',Buffer.from('anything'))
console.log(signature)


-

const crypto = require('crypto')

let txt = "마포대교는 무너졌냐ㅑ";
let header = {
    "alg":"HS256",
    "typ":"JWT"
}

let encodeheader = Buffer.from(JSON.stringify(header)).toString('base64').replace('=','');

let payload = {
    "sub":"123456678",
    "name":"John Doe",
    "iat":123325,
}

let encodepayload = Buffer.from(JSON.stringify(payload)).toString('base64').replace('=','');

//첫번째 인자값 : 어떤 암호화 할건지 (sha256)
//두번째 인자값 : 암호화 규칙 : string = 우리가 임의대로 만들어 놓은 key값 = 16진수로 만들어 놓기  
// 두번째값 - 요 값을 가지고 sha256 암호 형태로 결과값을 주겠다.
let signature = crypto.createHmac('sha256',Buffer.from('anything'))
                .update(`${encodeheader}.${encodepayload}`)//header.payload의 값을 string을 . 으로 연결해서 표현 
                .digest('base64').replace('=','') // string 값을 64비트 형태로 바꾸기 
                
console.log(signature)

console.log(`${encodeheader}.${encodepayload}.${signature}`);

console.log에 찍힌 token 

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY2NzgiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjEyMzMyNX0.NSNmmXiinXHWDz4U8sxvLsayCwMaV1IgRG7Zi3xllRY

 

* token 이 잘 만들어졌는지 확인하기 

아까 JWT 사이트에서 확인

Signature Verified 

바이너리로 했다고 오른쪽아래 파란색 checkbox 체크 해보기 

 

 

 

 

 

 

만든 token을 client에게 보내고 client가 받는거 해보기 

function 에 담고 return 으로 키 반환, module.exports = createtoken; 으로 exports 하기 

const crypto = require('crypto')

function createtoken() {

    let header = {
        "alg": "HS256",
        "typ": "JWT"
    }

    let encodeheader = Buffer.from(JSON.stringify(header)).toString('base64').replace('=', '');

    let payload = {
        "sub": "1234567890",
        "name": "John Doe",
        "user": "ddd",
        "iat": 123325,
    }

    let encodepayload = Buffer.from(JSON.stringify(payload)).toString('base64').replace('=', '');

    let signature = crypto.createHmac('sha256', Buffer.from('anything'))
        .update(`${encodeheader}.${encodepayload}`)
        .digest('base64').replace('=', '')

    return `${encodeheader}.${encodepayload}.${signature}`

}
let token = createtoken();
console.log(token);
module.exports = createtoken; 

 

 

 


 

 

 

쿠키 사용해보면서 내용 어떻게 전달되는지 보기 

$npm i express

server.js 기본 코드 작성

const express=require('express');
const app=express();

app.get('/', (req,res)=>{
    res.send('hello world')
})

app.listen(3000,()=>{
    console.log('server start port: 3000');
})

 

 

 

아직 key가없음

 

 

server에서 쿠키 생성 방법

app.get('/', (req,res)=>{
    res.cookie('token','any');    //Key:value  == headers:{set-cookie:'token=ingoo') 
    res.send('hello world')      // == body:{ 내용:hello world}
})

send에는 body 에 담는다 라는 것도 있음 

res.send / res.render = 응답 메세지를 완성시켜서 보내줌 

 

 

 

cookie 는 boy? or header? 

-> network 봐봐 - res headers 에 있음 (브라우저가 이 값을 받아서 저장함) 

console.log창에 document.cookie 하면 브라우저가 지금 받고 저장한 값이 나옴

 

 

 

코드 추가 

const express=require('express');
const app=express();

app.get('/', (req,res)=>{
    res.cookie('token','any');
    res.send('hello world <a href="/menu1"> menu1</a>')
})

app.get('/menu1',(req,res)=>{
    res.send('menu1페이지입니다.');
})

app.listen(3000,()=>{
    console.log('server start port: 3000');
})

text로 보내도 브라우저가 html a tag로 변환해줌 

nunjucks를 사용하지않아도 page 이동이 됨 

a link 누르고 요청 header 보기 

server가 저 쿠키 값을 보고 식별하고 처리가능 

 

 

브라우저 : storage에 있는 것을 headers에 넣고 보냄 : cookie가 유지되는 방법

페이지 바뀔 때마다 계속 쿠키값을 줌 (헤더에 있으니) 

 

cookie-parser 다운

$npm install cookie-parser 

코드 작성

const express=require('express');
const cookieParser=require('cookie-parser');
const app=express();

app.use(cookieParser());
app.get('/', (req,res)=>{
    res.cookie('token','any');
    res.send('hello world <a href="/menu1"> menu1</a>')
})

app.get('/menu1',(req,res)=>{
    console.log(req.cookies);
    res.send('menu1페이지입니다.');
})

app.listen(3000,()=>{
    console.log('server start port: 3000');
})

 

 

브라우저가 토큰가지고 있으면 어떤 서버에 가더라도 토큰이 headers안에 있으니 편함 

 

 

 

실제로 토큰 생성해서 넣기 

아까 만든 KEY  module.exports 한거 가져오기 

const token = require('./key'); 

key = 파일명

 

전체 코드 

const express=require('express');
const cookieParser=require('cookie-parser');
const token = require('./key'); 
const app=express();

app.use(cookieParser());
app.get('/', (req,res)=>{

    let {msg} = req.query;
    res.send(`${msg} hello world <a href="/menu1"> menu1</a><a href="/login?id=root&pw=root">로그인</a>`)
})

app.get('/login',(req,res)=>{
    let {id,pw} = req.query;

    if(id=='root' && pw=='root'){
        //토큰 생성
        let keytoken = token();
        res.cookie('token',keytoken);  //만든 토큰을 쿠키값에 넣어줌 
        res.redirect('/?msg=로그인성공');
    }else{
        //토큰 실패
        res.redirect('/?msg=로그인실패');
    }
})

app.get('/menu1',(req,res)=>{
    console.log(req.cookies);
    res.send('menu1페이지입니다.');
})

app.listen(3000,()=>{
    console.log('server start port: 3000');
})

server on -> check 

 

로그인, 메뉴 왔다갔다 할 때 쿠키값있나 확인 ! -> 모두 있음 

쿠키 : 보안 취약은 ? ? 

이렇게 쿠키값 가로채기 가능 ↓↓

그래서 생긴게 - 특별한 명령어들이 생김 - 쿠키를 세팅할 때 세번째 인자값 - 쿠키 설정 바꾸기 by객체  

 

    if(id=='root' && pw=='root'){
        //토큰 생성
        let ctoken = token();
        res.cookie('token',ctoken, {httpOnly:true,secure:true,});  //만든 토큰을 쿠키값에 넣어줌 
        res.redirect('/?msg=로그인성공');
    }else{
        //토큰 실패
        res.redirect('/?msg=로그인실패');
    }

 

브라우저 저장소에 있지만 값을 가져올 수 없게 만듬 

 

 

 

 

 

 

 

내일 : 비동기로 토큰 로그인 / 복구화 공부 

비동기 하려면 req,res 문서 왔다갔다 하는거 정확하게 공부 

매 실행 요청, 응답 헤더 , 바디 보면서 쿠키 보기 - 쿠키 미리 삭제 ㄱ 

반응형