[ node.js + redis ] 암호화

fasongsong·2024년 6월 27일

실습

목록 보기
4/4

📌 개요


  • Node.Js와 NoSQL중 Redis를 사용하여 간단한 형태의 Data 암호화를 Server-Side에서 실습


📌 과제 목표


1) Node.JS를 이해하고 Local환경에 설치한다.
2) Node Library 세팅하여 web service 구현한다.
3) Redis DB를 Local환경에 설치한다.
4) View 화면 및 Server+DB 암호화 연동 부분을 실습한다.



📌 공식 문서


📌 구현


1. 환경 구축 (nodejs 설치, npm 설치)

2. Index.js 생성 및 node init 진행

  • 진행할 폴더 내에 Index.js를 만든 후 cmd창 켜서 node init 명령어 실행
  • 진행하면 해당 폴더에 package.json이 생성

3. Redis 및 암호화 library 구현 및 web service 활성화

  • command창에서 npm i express body-parser crypto redis 실행
  • index.js 수정
const redis = require('redis');
const crypto = require('crypto');
const express = require('express');
const bodyParser = require('body-parser');

//32바이트 길이의 secret 키
const key = crypto.randomBytes(32); 
//초기화 벡터 생성 (16 바이트)
const iv = crypto.randomBytes(16); 
const app = express();
const client = redis.createClient;


//JSON 파싱을 위한 미들웨어 설정
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));

//데이터를 암호화하는 함수
function encrypt(text){
    const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
    let encrypted = cipher.update(text, 'utf8', 'hex');
    encrypted += cipher.final('hex');
    return {iv: iv.toString('hex'), encryptedData: encrypted};
}

//데이터를 복호화하는 함수
function decrypt(text){
    const decipher = crypto.createDecipheriv('aes-256-cbc',key,iv);
    let decrypted = decipher.update(text, 'hex', 'utf8');
    decrypted += decipher.final('utf8');
    return decrypted;
}

app.get('/', function(req, res){
    res.send("Hello world!");
})

//서버 시작
const PORT = 3333;
app.listen(PORT, ()=>{
    console.log(`서버 실행 포트: ${PORT}`);
});
  • web service 활성화
  • command창에서 node index.js 실행 후 browser에서 localhost:3333 접근하여 “Hello world!” 문구 출력 및 server 실행 확인.

4. Redis DB 설치 및 서버 실행

  • https://github.com/microsoftarchive/redis/releases 에서 윈도우용 무설치 레디스 파일 다운로드
    사이트 접속후 3.0.504 (Latest) 부분에서 Redis0x6403.0.504.zip 다운로드
  • 이후 다운로드 받은 파일을 압축을 풀어두고 cmd창 해당경로로 이동하여 .\redis-server 명령어로 redis server start
    redis는 기본적으로 windows를 지원하지 않기 떄문에 WSL 설치후 진행하여야 하나 가장 간단한 무설치 형태를 선택

5. 암호와 Data DB Insert 및 View 구현

  • index.js 파일에 client 부분 수정.
//로컬 Redis 서버에 연결
const client = redis.createClient(6379, 'localhost');
client.connect();
  • redis 관련 function 구현부분 추가 작성.
// 비동기로 Redis에 데이터 저장
async function saveToRedis(key, data){
    try{
        await client.set(key, JSON.stringify(data));
        return true;
    } catch(err){
        console.error('Redis 저장 중 에러 발생: ', err);
        return false;
    }
}

//암호화된 데이터를 Redis에 저장하는 API 엔드포인트
app.post('/insert', async (req, res)=>{
    const {data} = req.body;
    const encryptedData = encrypt(data);

    //암호화된 데이터를 Redis에 저장
    const result = await saveToRedis('data', encryptedData);
    if(result){
        res.status(200).send(" data : "+JSON.stringify(encryptedData)+" <br/> 저장 완료 !! ");
    }else{
        res.status(500).send('Insert error!');
    }
});
  • 종료 초기화부분 추가 작성.
//node 종료시 호출
process.on('SIGINT', ()=>{
    client.quit();
    console.log('서버 종료 및 Redis 클라이언트 종료');
    process.exit();
})
  • View 화면 구현.
    Index.html 파일을 생성하여 아래의 view 구현부분을 작성.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>NoSQL 데이터 암호화</title>
</head>
<body>
    <h1>데이터 암호화 TEST</h1>
    <form id="dataForm">
        <input type="text" id="dataInput" placeholder="데이터 입력">
        <button type="submit">저장</button>
    </form>
    <div id="result"></div>

    <script>
        const form = document.getElementById('dataForm')
        const input = document.getElementById('dataInput');
        const resultDiv = document.getElementById('result');

        form.addEventListener('submit', async(event)=>{
            event.preventDefault();
            const data = input.value;

            //데이터를 서버에 전송
            const response = await fetch('/insert', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({data})
            });

            if(response.ok){
                const result = await response.text();
                resultDiv.textContent = result;
            }else{
                resultDiv.textContent = 'error!!';
            }
        });

    </script>
</body>
</html>

welcome화면으로 index.html을 지정하기 위해 아래 구문 추가.

// index.html을 제공하기 위한 미들웨어 설정
app.use(express.static(__dirname)); //현재 디렉토리 지정

node서버 재시작 후 localhost:3333 재접속시 view화면 정상접속 확인.
임의의 데이터 입력후 저장, reponse data 확인.

  • Redis DB에서 Data 확인
    cmd창에서 redis 폴더 이동후 redis-cli.exe –h localhost –p 6379 입력하여 redis client 진입.
    - 간단한 text 모델을 사용. (예시 “text-davinci-003”) 필요시 다양한 모델 리스트를 확인하여 적용할 수 있음.
    prompt를 바꿔서 질문을 수정 할 수 있음.
    마지막의 여러 답변 중 첫번째 답변만 보이도록 지정한 부분도 응용할 수 있음.
    redis에서 결과값 확인.


📌 전체코드


[index.js]

const redis = require('redis');
const crypto = require('crypto');
const express = require('express');
const bodyParser = require('body-parser');

const key = crypto.randomBytes(32); //32바이트 길이의 secret 키
const iv = crypto.randomBytes(16); //초기화 벡터 생성 (16 바이트)
const app = express();

//로컬 Redis 서버에 연결
const client = redis.createClient(6379, 'localhost');
client.connect();

//JSON 파싱을 위한 미들웨어 설정
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
// index.html을 제공하기 위한 미들웨어 설정
app.use(express.static(__dirname)); //현재 디렉토리 지정

//데이터를 암호화하는 함수
function encrypt(text){
    const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
    let encrypted = cipher.update(text, 'utf8', 'hex');
    encrypted += cipher.final('hex');
    return {iv: iv.toString('hex'), encryptedData: encrypted};
}

//데이터를 복호화하는 함수
function decrypt(text){
    const decipher = crypto.createDecipheriv('aes-256-cbc',key,iv);
    let decrypted = decipher.update(text, 'hex', 'utf8');
    decrypted += decipher.final('utf8');
    return decrypted;
}

// app.get('/', function(req, res){
//     res.send("Hello world!");
// })

//서버 시작
const PORT = 3333;
app.listen(PORT, ()=>{
    console.log(`서버가 포트 ${PORT}에서 실행중입니다.`);
});

// 비동기로 Redis에 데이터 저장
async function saveToRedis(key, data){
    try{
        await client.set(key, JSON.stringify(data));
        return true;
    } catch(err){
        console.error('Redis 저장 중 에러 발생: ', err);
        return false;
    }
}

//암호화된 데이터를 Redis에 저장하는 API 엔드포인트
app.post('/insert', async (req, res)=>{
    const {data} = req.body;
    const encryptedData = encrypt(data);

    //암호화된 데이터를 Redis에 저장
    const result = await saveToRedis('Data', encryptedData);
    if(result){
        res.status(200).send(" data : "+JSON.stringify(encryptedData)+" <br/> 저장 완료 !! ");
    }else{
        res.status(500).send('Insert error!');
    }
});

//node 종료시 호출
process.on('SIGINT', ()=>{
    client.quit();
    console.log('서버 종료 및 Redis 클라이언트 종료');
    process.exit();
})

[index.html]

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>NoSQL 데이터 암호화</title>
</head>
<body>
    <h1>데이터 암호화 TEST</h1>
    <form id="dataForm">
        <input type="text" id="dataInput" placeholder="데이터 입력">
        <button type="submit">저장</button>
    </form>
    <div id="result"></div>

    <script>
        const form = document.getElementById('dataForm')
        const input = document.getElementById('dataInput');
        const resultDiv = document.getElementById('result');

        form.addEventListener('submit', async(event)=>{
            event.preventDefault();
            const data = input.value;

            //데이터를 서버에 전송
            const response = await fetch('/insert', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({data})
            });

            if(response.ok){
                const result = await response.text();
                resultDiv.textContent = result;
            }else{
                resultDiv.textContent = 'error!!';
            }
        });

    </script>
</body>
</html>


📌 시행착오


  • welcome화면으로 index.html을 지정하기 위해 아래 구문 추가하는 부분에서 기존에 적었던
app.get('/', function(req, res){
    res.send("Hello world!");
})

을 주석처리해야함

  • Redis와 node.js 서버 모두 켜놓고 테스트 해야함

  • Redis DB에서 확인하는 테스트에서 redis-cli.exe –h localhost –p 6379 만 입력하면 에러가 나는 경우가 있음
    - 해결법이 여러가지인데 아래의 3번으로 해결!

    1. Redis 설치 확인:
      Redis가 제대로 설치되어 있는지 확인. Redis를 설치하지 않았다면, 공식 웹사이트에서 설치 파일을 다운로드하고 설치.

    2. 환경 변수 설정:
      Redis 설치 경로를 환경 변수에 추가. 예를 들어, redis-cli.exe가 C:\Redis 폴더에 설치되어 있다면, 해당 경로를 시스템 환경 변수 PATH에 추가해야 함.

    3. 경로를 포함하여 명령 실행:
      명령어를 실행할 때 전체 경로를 포함하여 실행.
      예를 들어:

      C:\Redis\redis-cli.exe -h localhost -p 6379
    4. 현재 디렉토리에서 실행:
      명령어를 실행하는 디렉토리가 redis-cli.exe 파일이 있는 디렉토리인지 확인. 그렇지 않다면 해당 디렉토리로 이동한 후 다시 시도.

profile
파송송의 개발 기록

0개의 댓글