- Json Web Token
- OAuth(Open Autorization): 서드파티 어플리케이션이 사용자의 계정에 접근한 수 있는 권한을 부여하기 위한 프로토콜
- OAuth2.0: JWT Bearer Token인증방식을 지원, 클라이언트가 발급받은 JWT를 Autorization 헤더에 담아 요청을 보내면, 서버는 해당 JWT의 유효성을 검사하여 권한을 부여한다
- Header, Payload, Signature
- 클라이언트에서 요청하면 서버에서 생성과 검증과정을 가짐
- jwt.sign(payload, secretOrPrivateKey,[option]) 생성
- jwt.verify(token, secretOrPrivateKey,[option]) 유효성검증
- npm install jsonwebtoken 모듈 다운로드
- const jwt = require("jsonwebtoken"); 모듈 require
- 생성코드(sign)
const jwt = require("jsonwebtoken");
const SECRET = "DWB0jOga2jrAozUXUsLCQ1e4EeeQH8"; //랜덤문자열 사용
//req, res함수 안 코드
const token = jwt.sign({ id }, SECRET);
res.send({ result: true, token });
//view의 js에서 send데이터 성공시 localStorage작업 진행
localStorage.setItem("login", token);
- 검증코드(verify)
//view의 js에서 header에 토큰 정보 전송
const token = localStorage.getItem("login");
const response = await axios({
method: "post",
url: "/token",
headers: {
Authorization: `Bearer ${token}`,
},
});
//app.js코드
if (req.headers.authorization) {
//인증정보 들어왔을 때
const token = req.headers.authorization.split(" ")[1];
//Bearer와 뒤의 토큰을 분리(띄어쓰기 기준), [0] = Bearer, [1] = 토큰만 저장
try {
const auth = jwt.verify(token, SECRET);
//auth는 payload와 iat(issued at, 발급시간)정보 가짐(배열)
if (userInfo.id === auth.id) {
//payload값을 비교하여 유효성 검증
res.send({ result: true, name: userInfo.name });
}
} catch(e) {
//오류발생시 코드작성
}
}
- 단방향 암호화: 패스워드 저장 등에 활용, 원본 데이터 복원이 불가능, 주로 해시 함수를 사용하여 구현
- 양방향 암호화: 데이터 기밀성 유지 및 안전한 통신을 위해 사용
1) 대칭키 알고리즘: 암호화,복호화에 동일키 사용
2) 공개키 알고리즘: 공개키, 개인키 쌍을 각각 암호화, 복호화에 사용
- js에서 기본적으로 제공되는 모듈 crypto를 사용한다
- createHash(알고리즘).update(암호화할 값).digest(인코딩방식)으로 암호화
- hash값을 DB에 저장하고, 로그인시 암호화를 진행하여 값을 비교하면 로그인 검사를 할 수 있다
const crypto = require("crypto");
const createHashPw = (pw) => {
return crypto.createHash("sha512").update(pw).digest("base64");
};
console.log("1st hasing", createHashPw("1234"));
console.log("2nd hasing", createHashPw("1234"));
console.log("3rd hasing", createHashPw("1234")); //전부다 똑같은 값 출력
- salt와 hash값을 DB에 저장해두어야한다
- 같은 입력값이라도 salt값에 따라 해시값이 달라진다
- pdkdf2Sync(암호화할값, 솔트, 반복횟수, 키길이, 알고리즘).toString("base64");을 통해 암호화 한다
- toString을 하지 않으면 buffer값을 가지기 때문에 꼭 문자열로 바꾸는 toString을 진행해야한다
- salt값은 randomBytes()를 통해 무작위로 설정한 후 DB에 저장한다
- 암호화 작업 함수 작성 코드
function saltAndHashPw(pw) {
const salt = crypto.randomBytes(16).toString("base64");
const iterations = 100; //반복횟수
const keylen = 64; //생성할 키의 길이
const algorithm = "sha512";
//pdkdf2Sync(암호화할값, 솔트, 반복횟수, 키길이, 알고리즘)
const hash = crypto
.pbkdf2Sync(pw, salt, iterations, keylen, algorithm).toString("base64"); //buffer to String
return { hash, salt }; //{ hash: hash, salt: salt }
}
console.log("1st hashing", saltAndHashPw("1234"));
console.log("2nd hashing", saltAndHashPw("1234"));```
코드를 입력하세요
//랜덤 salt로 인해 다른 값이 나온다
//로그인 작업 시
const hash = crypto
.pbkdf2Sync(inputPw, savedSalt, iterations, keylen, algorithm).toString("base64");
//저장해둔 salt와 동일한 설정으로 해시하여 DB에 저장된 값을 비교한다
### Crypto - 양방향
\- 암호화 객체를 만들고 이를 통해 암호화 한다
\- 암호화객체: crypto.createCipheriv(알고리즘, 키, iv)사용
\- 키와 iv는 buffer데이터로 랜덤값 생성하여 사용
\- 데이터 암호화: 암호화객체.update(암호화할 데이터, 입력인코딩, 출력인코딩);
\- 암호화객체.final(출력인코딩)메소드로 최종결과 생성
\- 암호화 코드
```js
//algorithm, key, iv는 미리 변수로 선언한 상태라고 가정
function encrypt(text) {
const cipher = crypto.createCipheriv(algorithm, key, iv);
let encrypted = cipher.update(text, "utf8", "base64");
encrypted += cipher.final("base64");
return encrypted;
}
- 복호화: createDecipheriv()사용
- 암호화 역으로 진행
- 복호화 코드
function decrypt(encryptedText) {
const decipher = crypto.createDecipheriv(algorithm, key, iv);
let decrypted = decipher.update(encryptedText, "base64", "utf8"); //입력인코딩과 출력인코딩이 반대로 변경된다
decrypted += decipher.final("utf8");
return decrypted;
}
- npm install bcrypt를 통해 모듈 설치가 필요
- require하여 bcrypt선언해준다
- salt의 라운드 수를 설정하고 값을 넣어줘야한다(클수록 안전 but 성능저하)
- 강한 보안이 필요한 경우 주로 사용된다
- 해시값 생성: hashSync(비밀번호, saltRound) -> 암호화된 문자열을 반환 한다
- 해시값 비교: compareSync(원본비밀번호, 해시된 비밀번호) -> true or false값을 반환한다
- 실행코드
const bcrypt = require("bcrypt");
const saltRounds = 10;
function hashPw(pw) {
return bcrypt.hashSync(pw, saltRounds);
}
function comparePw(inputPw, hashedPw) {
return bcrypt.compareSync(inputPw, hashedPw);
}
// 두 함수를 사용하여 비밀번호 값을 비교하는데 사용하면 로그인 작업이 가능하다