IT's 우

[Node, 3주차 -3] 암호화, 파일 시스템 본문

카카오 클라우드 스쿨 2기/node

[Node, 3주차 -3] 암호화, 파일 시스템

디우 2022. 11. 16. 19:58
728x90

5. 암호화

  • crypto 모듈을 암호화에 이용

1) 암호화 방식

- 단방향 암호화

암호화는 가능하지만 암호화된 문장을 이용해서 복호화하는 것은 불가능
원본 데이터와의 비교는 가능(동일한 문장을 암호화하면 동일한 결과가 만들어지기 때문)
해시 기법(문자열을 고정된 길이의 다른 문자열로 만드는 방식)을 주로 이용 알고리즘으로는 md4, sha1, sha256, sha512 등이 사용되는 md5와 sha1은 취약점이 발견돼서 거의 사용하지 않는데 안드로이드에서 가끔 sha1 알고리즘을 사용합니다.
블록체인에서는 sha256을 사용하다가 sha512로 변환 중입니다.
비밀번호 저장이나 블록체인에서는 단방향 암호화를 주로 이용

createHash(알고리즘): 사용할 알고리즘 설정
update(문자열): 변화할 문자열을 설정
digest(인코딩 방식): 인코딩할 알고리즘을 설정하는데 주로 base64를 많이 사용

 

// 암호화 모듈 가져오기
const crypto = require("crypto");
let password = "1234";
// 단방향 암호화 수행
let p1 = crypto.createHash("sha256").update(password).digest('base64');
console.log(p1);

//길이가 달라져도 고정된 길이의 문자열 출력
password = "12345678910";

p1 = crypto.createHash("sha256").update(password).digest('base64');
console.log(p1);

// 동일한 문자열 암호화하면 동일한 결과 만들어진다.
let str="12345678910";
let p2 = crypto.createHash("sha256").update(str).digest('base64');
console.log(p1==p2);

- 양방향 암호화
암호화할 때 키를 사용해서 암호화하는 방식으로 복호화가 가능
암호화 할 때 사용한 키와 복호화할 때 사용한 키가 같아야만 복호화가 가능
동일한 데이터를 암호화했을 때 암호화된 결과가 다를 수도 있습니다.
이 데이터는 비교 연산을 잘하지 않고 복원해서 사용하는 경우가 대부분입니다.
일반 데이터 암호화에 이용

createCipheriv(알고리즘, 키, 초기화 벡터): 양방향 암호화 객체 생성
암호화 객체.update(암호화할 문자열, 문자열 인코딩 방식- utf8, 출력 인코딩 방식- base64): 문자열이 리턴됨
암호화 객체.final(출력 인코딩 방식): 암호화 완료

createDeccipheriv(알고리즘, 키, 초기화 벡터): 양방향 복호화 객체 생성 - 암호화할 때 사용한 것을 그대로 대입
암호화 객체.update(복호화할 문자열, 출력 인코딩 방식- base64, 문자열 인코딩 방식- utf8): 문자열이 리턴됨
암호화 객체.final(문자열 인코딩 방식- utf8): 복호화 완료

 

// 암호화 모듈 가져오기
const crypto=require("crypto");

const algorithm= "aes-256-cbc"; // 알고리즘은 정해진 알고리즘 이용
// Node의 crypto 모듈에서는 key는 32자리 iv는 16자리
const key="12345678901234567890123456789012";
const iv="1234567890123456";

// 암호화 객체 생성

const cipher=crypto.createCipheriv(algorithm,key,iv);
let result=cipher.update('01037901997','utf8','base64');
result += cipher.final('base64');
console.log(result);

// 복호화
const decipher=crypto.createDecipheriv(algorithm,key,iv);
let result2=decipher.update(result,'base64','utf8');
result2 += decipher.final('utf8');
console.log(result2);

6. 파일 시스템

  • 파일 읽고 쓰기
  • 파일을 읽고 쓰기 위한 모듈은 fs

1) 파일 읽기

fs.readFile('파일경로', [options], 콜백 함수): 비동기 방식으로 읽음
콜백 함수는 매개변수가 두 개인데 첫 번째는 매개변수는 에러가 발생했을 때 에러 내용을 가지고 있고 두 번째 매개변수가 읽기에 성공했을 때 읽어낸 데이터

fs.readFileSync('파일 경로', [options]): 동기식을 읽어내고 읽어낸 데이터를 리턴

2) Buffer

  • buffer: 데이터를 저장하기 위한 메모리
  • buffering: 데이터를 한꺼번에 처리하기 위해서 데이터를 모으는 작업
  • readFile이라는 함수는 읽어내고 난 후 Buffer 객체를 리턴
    Buffer 객체에는 크기를 알려주는 length 속성 그리고 문자열을 Buffer로 변경하는 from 함수나 Buffer의 내용을 문자열로 변환하는 toString 함수 등이 포함되어 있습니다.

3) 변경 가능하거나 변하지 않는 중요한 문자열은 파일이나 데이터베이스에 저장하고 읽는 방식을 사용

  • 운영 환경과 개발 환경이 다른 경우 소스 코드를 수정하게 되면 컴파일을 다시 하고 빌드를 다시 해야 합니다.
  • 클라이언트에 배포하는 프로그램을 만든 경우라면 대대분의 언어는 역 어셈블(실행이 되는 코드에서 소스코드를 찾아가는 과정)이 가능

4) 동기식 파일 읽기

  • 보안에 취약합니다.
// 파일을 읽고 쓸 수 있는 모듈 가져오기
const fs= require('fs');

let data = fs.readFileSync("./text.txt");
//console.log(data.toString());

// Enter 단위로 분할해서 읽기
let ar= data.toString().split("\n");
console.log(ar[0]);

 

5) 비동기식 파일 읽기

  • 파일 읽는 도중 다른 작업을 수행할 수 있도록 하는 것
const fs= require('fs');

// 비동기식 파일 읽기 - error는 에러의 내용이고 data가 Buffer

fs.readFile('./text.txt',(error,data)=>{
    if(error){
        // 에러가 발생했을 때
        console.log(error.log);
    }else{
        console.log(data.toString());
    }
});
console.log("파일 읽기 종료");
  • 콜백 대신에 Promise 사용 가능
let fs=require ('fs').promises;
fs.readFile('./text.txt').then((data)=>{
    console.log(data.toString());
}).catch((error)=>{
    console.log();
})

 

6) Stream

  • 데이터의 흐름
  • 데이터를 일정한 크기로 잘라서 여러 번에 나누어서 처리
    용량이 큰 파일을 한 번에 읽어내려고 하면 버퍼의 크기가 너무 커져서 메모리 부담이 생기게 됨
    이렇게 작게 잘라서 처리하는 것을 chunk라고 합니다.
    로그 파일을 읽을 때 이런 방식을 사용합니다.
  • 스트리밍: 일정한 크기의 데이터를 지속적으로 전달하는 작업
  • 작업
    fs 모듈의 createReadStream 메서드나 createWriteStram 메서드를 이용해서 스트림을 생성: 파일 경로와 highWaterMark 옵션을 이용해서 버퍼의 크기를 설정

    읽기 스트림의 경우는 data(하나의 버퍼를 읽었을 때 발생), end(읽기 끝났을 때 발생), error(오류 발생) 이벤트 처리

    쓰기 스트림의 경우는 drain, finish, error 이벤트를 처리

7) 스트림을 사용하는 이유 확인

  • 용량이 큰 파일을 생성
  • 스트림을 사용하지 않고 복사- 기존 메모리 크기에 파일의 크기만큼의 메모리가 추가로 필요, 300MB 이상의 차이
  • 스트림을 사용하고 복사 - 파일의 내용을 잘라서 읽기 때문에 파일의 크기 만큼의 메모리가 추가로 필요하지 않음

8) 기타 함수

  • access(경로, 옵션, 콜백): 디렉터리나 파일에 접근할 수 있는지를 확인- 접근이 안되면 에러가 발생
  • mkdir(경로, 콜백): 경로를 생성
  • open(경로, 옵션, 콜백): 경로의 파일을 열고 아이디를 리턴하는데 파일이 없으면 생성
  • remove(기존 경로, 새 경로, 콜백): 이름 변경
  • unlink(경로, 콜백): 파일 지우기
  • rmdir(경로, 콜백): 디렉터리 지우기

이 함수들의 콜백은 전부다 에러 객체를 넘겨받습니다.
에러 객체가 존재하면 에러가 발생한 것이고 그렇지 않으면 에러가 발생하지 않은 것입니다.

이미지 파일을 업로드하는 애플리케이션을 생성

// 스트림을 이용한 읽기
const fs= require('fs');
//읽기 전용 스트림 생성

const readStream= fs.createReadStream(
    "./text.txt",{highWaterMark:16}
);
// 데이터를 저장하기 위한 객체를 생성
let data2= [];
//읽는 동안 발생하는 이벤트를 처리
readStream.on('data',(chunk)=>{
    // 읽는 동안에는 읽어온 데이터를 추가
    data2.push(chunk);
});

// 읽기가 끝나면 발생하는 이벤트를 처리
readStream.on('end',()=>{
    // 지금까지 읽은 내용을 하나로 만들기
    let result= Buffer.concat(data2);
    console.log(result.toString());
});
728x90
반응형