JWT
💡OAuth란? (Open Authorization)
- 사용자의 리소스에 대한 접근 권한을 안전하게 위임하기 위한 개방형 표준 프로토콜!
- 사용자가 비밀번호를 제공하지 않고도 제3자 어플리케이션에 권한을 부여할 수 있다.
- 주로 소셜 미디어 로그인이나 외부 서비스 연동에 사용된다.
💡 JWT (Json Web Token)
- 사용자 인증에 주로 사용되는 토큰 기반 인증 방식!
- JSON 형식의 정보를 안전하게 전송하기 위한 표준 규격
- Header, Payload, Signature 세 부분으로 구성된다.
- 토큰 자체에 사용자 정보를 포함하고 있어 서버에서 별도의 세션 저장소가 필요 없다.
- 주로 웹 어플리케이션에서 사용자 인증을 위해 사용.
더보기
// app.js
// POST /login
app.post("/login", (req, res) => {
try {
const { id, pw } = req.body;
const { id: realId, pw: realPw } = userInfo; // DB에 저장되어있는 데이터
// DB 데이터와 비교
if (id === realId && pw === realPw) {
// 로그인 성공
// jwt 발급
const token = jwt.sign({ id: id }, SECRET); // sign:(payload, signature)
console.log("토큰>>>", token);
res.send({ result: true, token }); // {result: true, token: 'eyJhbGciOi(중략)'}
// jwt token은 클라이언트에서 관리하기 때문에 클라이언트에게 토큰을 보내주어야 함
} else {
// 로그인 실패
res.send({ message: "로그인 정보가 올바르지 않습니다.", result: false });
// {message: '로그인 정보가 올바르지 않습니다.', result: false}
}
} catch (err) {
console.log("post /login err", err);
res.status(500).send({ message: "서버에러" });
}
});
💻 JWT와 OAuth의 차이점
- 목적: JWT는 주로 인증(authentication)에, OAuth는 권한 부여(authorization)에 사용
- 복잡성: JWT는 비교적 단순한 구조를 가지고 있지만, OAuth는 여러 단계와 참여자가 있는 복잡한 프로토콜
- 사용 사례: JWT는 단일 어플리케이션 내에서의 인증에 적합하고, OAuth는 여러 서비스 간의 권한 위임에 적합
- 토큰 내용: JWT는 사용자 정보를 직접 포함하지만, OAuth의 액세스 토큰은 일반적으로 랜덤한 문자열
비밀번호 암호화
💻 암호화 종류
💡 단방향 암호화
- 암호화된 데이터를 원래의 형태로 복호화 할 수 없다.
- 동일한 입력값에 대해 항상 같은 해시값을 생성!
- 주로 해시 함수를 사용하여 구현
- 대표적인 알고리즘: SHA-256, SHA-512
👍🏻 장점
- 복호화가 불가능하므로 보안성이 높다.
- 데이터베이스가 해킹되어도 원본 비밀번호를 알아내기 어렵다.
더보기
const crypto = require("crypto");
/*
1. crypto를 통해 단방향 암호화 구현 -> 복호화 불가능
- createHash(알고리즘)
- pdkdf2Sync(비밀번호, sort, 해시 반복횟수, 키의 길이, 알고리즘)
*/
// 1-1) createHash(알고리즘).update(평문).digest(인코딩방식)
// 인코딩 방식: base64, hex, ascii, binary
// digest: 암호화 된 문장을 우리가 읽을 수 있는 문자열로 인코딩하는 것
const createHashPW = (pw) => {
return crypto.createHash("sha512").update(pw).digest("base64");
};
console.log(createHashPW("1234"));
console.log(createHashPW("1234"));
console.log(createHashPW("1234")); // 전부 똑같은 값
console.log(createHashPW("1234.")); // 조금만 변해도 전혀 다른 해시값이 나옴
// 1-2) pdkdf2Sync(비밀번호, sort, 해시 반복횟수, 키의 길이, 알고리즘).toString(인코딩방식)
function saltAndHashPW(pw) {
const salt = crypto.randomBytes(16).toString("base64");
const iterations = 100;
const keylen = 64;
const algorithm = "sha512";
const hash = crypto
.pbkdf2Sync(pw, salt, iterations, keylen, algorithm) // buffer 객체를 리턴하는 중
.toString("base64");
return { salt, hash };
} // DB에 salt와 hash 모두 저장해야 함
console.log("pbkdf2Sync >> ", saltAndHashPW("1234"));
console.log("pbkdf2Sync >> ", saltAndHashPW("1234"));
console.log("pbkdf2Sync >> ", saltAndHashPW("1234"));
// 암호 비교 함수
function checkPw(inputPW, savedSalt, savedHash) {
const iterations = 100;
const keylen = 64;
const algorithm = "sha512";
// 반복횟수, 길이, 알고리즘 모두 saltAndHashPW와 같아야 함 (비교를 위해)
// pbkdf2Sync의 모든 인자가 똑같다면 해시값도 똑같다.
const hash = crypto
.pbkdf2Sync(inputPW, savedSalt, iterations, keylen, algorithm)
.toString("base64");
return hash === savedHash;
}
const realPW = "qwer1234";
console.log("====================");
const data = saltAndHashPW(realPW);
console.log("data >> ", data);
const { salt: DBsalt, hash: DBhash } = data;
console.log("=========비밀번호 일치 여부 확인==========");
const isMatch = checkPw("qwqw", DBsalt, DBhash);
const isMatch2 = checkPw("qwer1234", DBsalt, DBhash);
console.log(isMatch); // false, 비밀번호 불일치
console.log(isMatch2); // true, 비밀번호 일치
#️⃣해시(Hash)#️⃣
- 임의의 길이를 가진 데이터를 고정된 길이의 값으로 변환하는 과정 또는 그 결과를 말한다. 이 과정에서 사용되는 함수를 해시 함수라고 한다!
#️⃣ 해시의 주요 특징
- 고정 길이 출력: 입력 데이터의 크기와 상관없이 항상 동일한 길이의 해시값을 생성
- 일방향성: 해시값으로부터 원본 데이터를 복원하는 것은 계산적으로 불가능
- 결정론적: 동일한 입력에 대해 항상 같은 해시값을 생성
- 충돌 저항성: 서로 다른 입력에 대해 동일한 해시값이 나오는 확률이 매우 낮음
💡 양방향 암호화
- 암호화와 복호화가 모두 가능
- 대칭키와 비대칭키(공개키) 방식으로 나뉨
1️⃣ 대칭키
- 암호화와 복호화에 동일한 키를 사용
- 속도가 빠르지만 키 관리가 어렵다.
- 대표적인 알고리즘: AES, DES
2️⃣ 비대칭키(공개키)
- 암호화와 복호화에 서로 다른 키를 사용
- 키 관리가 용이하지만 속도가 느리다.
- 대표적인 알고리즘: RSA
더보기
/*
2. 양방향 알고리즘
- createCipheriv: 암호화
- createDecipheriv: 복호화
*/
const key = crypto.randomBytes(32);
const iv = crypto.randomBytes(16); // 비밀 수
const algorithm = "aes-256-cbc";
const originalMessage = "hello, world!"; // 원본 메세지, 평문
// 암호화
function encrypt(text) {
// 1. 암호화 객체 생성
// const cipher = crypto.createCipheriv(algorithm, key, iv);
const cipher = crypto.createCipheriv(algorithm, key, iv);
// 2. 실제 데이터 암호화
// let encrypted = cipher.update(평문, 입력 인코딩, 출력 인코딩);
let encrypted = cipher.update(text, "utf8", "base64");
// 3. 최종 결과 생성
encrypted += cipher.final("base64");
return encrypted; // 암호화된 데이터
}
console.log(encrypt(originalMessage));
console.log(encrypt(originalMessage));
// 복호화
function decrypt(encryptedText) {
// 1. 복호화 객체 생성
const decipher = crypto.createDecipheriv(algorithm, key, iv);
// 2. 실제 데이터 복호화
// base64 방식으로 인코딩된 문자열이 utf8로 복호화됨
let decrypted = decipher.update(encryptedText, "base64", "utf8");
// 3. 최종 결과 생성
decrypted += decipher.final("utf8");
return decrypted;
}
const encryptedMessage = encrypt(originalMessage);
console.log("암호화 된 문장: ", encryptedMessage);
const decryptedMessage = decrypt(encryptedMessage);
console.log("복호화 된 문장: ", decryptedMessage);
'🌱SeSAC x CodingOn 웹 취업 부트캠프' 카테고리의 다른 글
[새싹/코딩온] 풀스택 웹 개발자 취업 부트캠프 9주차: 프로젝트 회고 (2) (0) | 2025.01.07 |
---|---|
[새싹/코딩온] 풀스택 웹 개발자 취업 부트캠프 8주차: 프로젝트 회고 (1) (0) | 2025.01.06 |
[새싹/코딩온] 풀스택 웹 개발자 취업 부트캠프 7주차 (1): Cookie & Session (0) | 2025.01.04 |
[새싹/코딩온] 풀스택 웹 개발자 취업 부트캠프 6주차 (2): 환경변수, Sequelize, Database 응용 (0) | 2025.01.04 |
[새싹/코딩온] 풀스택 웹 개발자 취업 부트캠프 6주차 (1): MVC 패턴, MySQL 연결 (0) | 2025.01.04 |