비밀번호 암호화
비밀번호를 데이터베이스에 바로 저장해놓으면 해킹의 위험이나 데이터베이스를 관리하는 사람이 멋대로 고객 정보를 활용할 수 있다. 그래서 비밀번호를 암호화해서 저장하는 것이 정배다.
단방향 암호화 복호화가 불가능하다. 그래서 비교할 때 암호화된 값을 통해서 비교한다. 서로 다른 데이터에 대해서도 같은 해시 값이 나올 수 있다. (해시 값 충돌) Hash 방식이 있다. Hash: 해시 함수에 의해 얻어지는 값으로 임의의 크기의 데이터를 (레인보우 테이블을 방지하기 위해 salt나 iteration을 활용해도 됨) 고정된 크기의 데이터로 변환한다. |
양방향 암호화 복호화가 가능하다. 대칭키, 공개키 방식이 있다. 데이터의 기밀성을 유지하거나 안전한 통신을 위해 사용한다. 대칭키: 암호화와 복호화에 동일한 키 사용 공개키: 공개키와 개인키라는 두개의 키 쌍 사용 |
Bcrypt
비밀번호를 암호화하는 알고리즘 중 하나로 강력하지만 해싱이 느리고 비용이 많이 든다.
// bcrypt
// : 비밀번호를 암호화 하는 알고리즘 중의 하나
// : 주로 강력한 보안 필요할 때 사용
// : blowfish라는 암호를 기반으로 설계된 단방향 암호화 함수
const bcrypt = require('bcrypt');
const originalPW = '1234'; // 원본 비번
const saltRounds = 10; // 솔트 라운드 수 정의, int로 12까지가 최고..?인가
// 1. 비밀번호 해싱 함수
function hashPW(password) {
return bcrypt.hashSync(password, saltRounds); // salt를 자동으로 생성해줌
}
// 2. 원본 비밀번호와 해시된 비밀번호가 일치하는지 확인
// 같은지, 다른지만 알려줌
function comparePW(password, hashedPW) {
return bcrypt.compareSync(password, hashedPW);
}
// 사용 예제
// 원본 비번을 해싱한 결과
const hashedPW = hashPW(originalPW);
console.log(`Hashed PW: ${hashedPW}`);
const isMatch = comparePW(originalPW, hashedPW); // true
const isMatch2 = comparePW('heelo', hashedPW); // false
console.log('비밀번호는 같은가.', isMatch);
console.log('match2의 비밀번호는 같은가', isMatch2);
소켓(Socket)
서버와 클라이언트를 연결해주는 도구로써 인터페이스 역할을 하는 것으로 프로토콜, Ip주소, 포트넘버로 구성
TCP와 UDP프로토콜을 이용하여 데이터를 전송한다.
HTTP 클라이언트의 요청이 있을때만 서버가 응답하고 곧바로 연결을 종료한다. 실시간 연결이 아니다. |
WebSocket 서버와 클라이언트가 특정 PORT를 통해 실시간으로 양방향 통신을 하는 방식 실시간 연결이다. |
프로토콜이란?
컴퓨터 또는 전자기기 간의 원활한 통신을 위해 지키기로 약속한 규약. 프로토콜에는 신호 처리법, 오류처리, 암호, 인증, 주소 등을 포함한다. (이런 식으로 통신하겠다. 란 뜻)
TCP/IP는 컴퓨터 네트워크에서 데이터 통신을 위한 프로토콜 스택으로, 네트워크 간의 데이터 교환을 가능하게 하는 중요한 기술
소켓 프로그래밍
- 클라이언트 소켓: 서버에 연결을 요청하고 서버에서 연결이 수락되면 서버와 데이터를 주고받을 수 있는 소켓
- 서버 소켓: 클라이언트의 요청을 받아들여 실제 통신을 위한 소켓을 생성한다.
다만 socket.id는 유저가 접속할 때마다 난수로 초기화된다. (서버가 끊겼다가 다시 연결되도 마찬가지다.) 이 점에 주의해야 할 것 같다.
exercise.ejs 파일 (Js도 한꺼번에 있다.)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="style.css" />
<script src="/socket.io/socket.io.js"></script>
<title>socket.io 실습</title>
</head>
<body>
<header>
<input type="text" id="username" placeholder="이름">
<button id="enter" type="button">입장</button>
</header>
<main class="dnone">
<div class="notice"></div>
<ul class="container"></ul>
<div class="submit">
<select name="users" id="users">
</select>
<input type="text" id="text" onkeydown="if(window.event.keyCode == 13) {submitText()}" />
<button onclick="submitText()" type="button">전송</button>
</div>
</main>
<!-- 실습1 각 버튼 누를 때마다 서버로 메세지 보내기-->
<!-- <button onclick="sayHello()">HELLO</button>
<button onclick="sayStudy()">STUDY</button>
<button onclick="sayBye()">BYE</button> -->
<script>
const socket = io.connect();
let clients = {};
socket.on("connect", function () {
console.log("클라이언트 연결 완료fmwlvmwlvkmlw >", socket.id);
});
// enter 버튼을 누르면 유저 닉네임과 socket.id라는 value값을 name, socketId라는 key 값으로
// 서버소켓에 보냄
function enter(event) {
event.target.disabled =true;
const nameElement = document.querySelector('#username');
const name = nameElement.value;
if (nameElement.value.trim().length > 0) {
document.querySelector('main').classList.remove('dnone');
socket.emit('userEnter', { name : name, socketId: socket.id })
}
}
document.querySelector('#enter').addEventListener('click', enter);
// hello emit
function submitText() {
const pElement = document.createElement('p');
pElement.classList.add('right');
const gotMsg = document.createElement('span');
// 채팅이 전체일 경우 (select값의 value가 전체일 때)
if (document.querySelector('select').value === '전체') {
gotMsg.textContent = `나: ${document.querySelector('#text').value}`;
gotMsg.classList.add('mymsg');
pElement.appendChild(gotMsg);
document.querySelector('.container').appendChild(pElement);
console.log(socket.id);
socket.emit("text", { who: socket.id, msg: `${document.querySelector('#text').value}`});
document.querySelector('#text').value = '';
} else {
// 채팅을 개인에게 보내는 경우 (select 값의 value가 전체가 아닐 때)
console.log(clients);
gotMsg.textContent = `(${clients[document.querySelector('#users').value]}님에게) 나: ${document.querySelector('#text').value}`;
pElement.appendChild(gotMsg);
document.querySelector('.container').appendChild(pElement);
gotMsg.classList.add('secret-msg');
socket.emit("toText", { who: socket.id, msg: `${document.querySelector('#text').value}`, to: `${document.querySelector('#users').value}`});
document.querySelector('#text').value = '';
}
document.querySelector('.container').scrollTop = document.querySelector('.container').scrollHeight;
}
// 새로운 클라이언트가 들어올 때
socket.on('notice', function(data) {
// clients.push(socket.id);
const divElement = document.createElement('div');
divElement.classList.add('introduce');
divElement.textContent = data.msg;
document.querySelector('.notice').appendChild(divElement);
document.querySelector('#users').innerHTML = '';
const optionEle = document.createElement('option');
optionEle.value = '전체';
optionEle.textContent = '전체';
document.querySelector('#users').appendChild(optionEle);
clients = data.sockets
for (const key in data.sockets) {
// 소켓아이디(해당 클라이언트의)와 data.sockets의 key값 (socket.id들의 집합의 iteration)이 동일할 때
if (socket.id === key) {
continue;
}
const optionElement = document.createElement('option');
optionElement.value = key;
optionElement.textContent = data.sockets[key];
document.querySelector('#users').appendChild(optionElement);
}
})
// 전체 채팅
socket.on('brod', function(data) {
const pElement = document.createElement('p');
pElement.classList.add('left');
const gotMsg = document.createElement('span');
gotMsg.textContent = `${clients[data.who]} : ${data.msg}`;
gotMsg.classList.add('someones-msg')
pElement.appendChild(gotMsg);
document.querySelector('.container').appendChild(pElement);
document.querySelector('.container').scrollTop = document.querySelector('.container').scrollHeight;
})
// 개인 채팅
socket.on('toClient', function(data) {
const pElement = document.createElement('p');
pElement.classList.add('left');
const gotMsg = document.createElement('span');
gotMsg.textContent = `${data.who} : ${data.msg}`;
gotMsg.classList.add('secret-msg');
pElement.appendChild(gotMsg);
document.querySelector('.container').appendChild(pElement);
document.querySelector('.container').scrollTop = document.querySelector('.container').scrollHeight;
});
</script>
</body>
</html>
server.js 파일
const express = require('express');
const http = require('http');
const socketIO = require('socket.io');
const PORT = 8000;
const app = express();
app.set('view engine', 'ejs');
// express 앱으로 http 서버 생성
const server = http.createServer(app);
// socket.id를 http 서버에 연결
const io = socketIO(server);
// app.get('/', function(req, res) {
// res.render('chat');
// });
app.get('/exercise', function(req, res) {
res.render('exercise');
});
app.use(express.static('public'));
const sockets = {};
// io.on(): socket 관련한 통신 작업을 처리
io.on('connection', function(socket) {
// connection 이벤트는 클라이언트가 접속했을 때 발생
// 콜백함수의 인자로 소켓 객체를 제공
// socket.id : 소켓의 고유 id (브라우저 탭 단위)
console.log('서버 연결 완료 >', socket.id);
// socket.emit(event_name, data) : 해당 클라이언트에게만 이벤트, 데이터를 전송
// io.emit(event_name, data): 서버에 접속된 모든 클라이언트에게 전송
// io.to(소켓 아이디).emit(event_name, data) : 소켓 아이디에 해당하는 클라이언트에게만 전송
// 전체 클라이언트에게 입장 안내
socket.on('userEnter', function(data) {
sockets[data.socketId] = data.name;
io.emit('notice', {msg: `${data.name}님이 입장하셨습니다.`, sockets: sockets});
})
// 전체 메세지 받았을 때
socket.on('text', function(data) {
console.log(`${data.who}: ${data.msg}`);
socket.broadcast.emit('brod', {who: data.who, msg: data.
msg});
})
// 개인 메세지 받았을 때
socket.on('toText', function(data) {
io.to(data.to).emit('toClient', {who: sockets[data.who], msg:data.msg});
});
// 클라이언트가 접속을 끊었을 때
socket.on('disconnect', function() {
const removedId = sockets[socket.id];
delete sockets[socket.id];
io.emit('notice', {msg: `${removedId}님이 퇴장하셨습니다.`, sockets: sockets});
console.log('유저 서버 연결 종료 >', socket.id);
})
})
server.listen(PORT, function() {
console.log(`http://localhost:${PORT}`);
})
'포스코x코딩온' 카테고리의 다른 글
[포스코x코딩온] 풀스택 부트캠프 9주차 정리 -1 (2차 프로젝트 회고) (1) | 2023.12.21 |
---|---|
[포스코x코딩온] 풀스택 부트캠프 8주차 정리 -2 (2차 프로젝트 회고) (1) | 2023.12.18 |
[포스코x코딩온] 풀스택 부트캠프 7주차 정리 2 - Cookie, Session, dotenv, aws, 서버구축, jwt (1) | 2023.12.09 |
[포스코x코딩온] 풀스택 부트캠프 7주차 정리 1 - Mysql연동, sequelize (0) | 2023.12.05 |
[포스코x코딩온] 풀스택 부트캠프 6주차 정리 2 - 파일업로드, MVC (0) | 2023.11.30 |