[Node] 노드 기능(2)

찐새·2023년 1월 17일
0

Node.js

목록 보기
3/6
post-thumbnail

6. dns

DNS를 다룰 때 사용하는 모듈로, 도메인을 통해 IP 등 DNS 정보를 얻고자 할 때 사용한다.

// dns.mjs
import dns from "dns/promises";

const DOMAIN = "naver.com";

const ip = await dns.lookup(DOMAIN);
console.log("IP : ", ip);

const a = await dns.resolve(DOMAIN, "A");
console.log("A : ", a);

const mx = await dns.resolve(DOMAIN, "MX");
console.log("MX : ", mx);

const cname = await dns.resolve(`www.${DOMAIN}`, "CNAME");
console.log("CNAME : ", cname);

const any = await dns.resolve(DOMAIN, "ANY");
console.log("ANY : ", any);

/* 결과
IP :  { address: '223.130.195.200', family: 4 }
A :  [
  '223.130.200.104',
  '223.130.195.200',
  '223.130.200.107',
  '223.130.195.95'
]
MX :  [
  { exchange: 'mx2.naver.com', priority: 10 },
  { exchange: 'mx1.naver.com', priority: 10 },
  { exchange: 'mx3.naver.com', priority: 10 }
]
CNAME :  [ 'www.naver.com.nheos.com' ]
ANY :  [
  { exchange: 'mx3.naver.com', priority: 10, type: 'MX' },
  { exchange: 'mx1.naver.com', priority: 10, type: 'MX' },
  { exchange: 'mx2.naver.com', priority: 10, type: 'MX' },
  { value: 'ns1.naver.com', type: 'NS' },
  { value: 'ns2.naver.com', type: 'NS' }
]
*/

A(ipv4 주소), AAAA(ipv6 주소), NS(네임서버), SOA(도메인 정보), CNAME(별칭, www가 붙으면 별칭인 경우가 많음), MX(메일 서버) 등은 레코드라고 부른다. 레코드의 정보는 dns.resolve(도메인, 레코드)로 조회한다.

7. crypto

암호화 모듈로, 보안에 활용할 수 있다.

7-1. 단방향 암호화

단방향 암호화란 복호화할 수 없는 암호화이다. 즉, 한 번 암호화하면 원래 무슨 문자였는지 되돌릴 수 없다. 해시 함수라고도 부르며, 보통 고객의 비밀번호에 활용한다.

고객의 비밀번호를 암호화해 저장한 후, 로그인 시 입력 받은 비밀번호를 같은 암호화 알고리즘(주로 해시 기법)으로 암호화해 비교한다. 해시 함수의 사용은 다음과 같다.

import crypto from "crypto";

console.log(
  "base64:",
  crypto.createHash("sha512").update("비밀번호").digest("base64")
);
console.log(
  "hex:",
  crypto.createHash("sha512").update("비밀번호").digest("hex")
);
console.log(
  "base64:",
  crypto.createHash("sha512").update("다른 비밀번호").digest("base64")
);

/* 결과
base64: dvfV6nyLRRt3NxKSlTHOkkEGgqW2HRtfu19Ou/psUXvwlebbXCboxIPmDYOFRIpqav2eUTBFuHaZri5x+usy1g==
hex: 76f7d5ea7c8b451b773712929531ce92410682a5b61d1b5fbb5f4ebbfa6c517bf095e6db5c26e8c483e60d8385448a6a6afd9e513045b87699ae2e71faeb32d6
base64: cx49cjC8ctKtMzwJGBY853itZeb6qxzXGvuUJkbWTGn5VXAFbAwXGEOxU2Qksoj+aM2GWPhc1O7mmkyohXMsQw==
*/

createHash는 사용할 해시 알고리즘을 넣는다. 종류로는 md5, sha1, sha256, sha512 등이 있지만, md5sha1은 이미 취약점이 발견되었다고 한다. 아직까지는 sha512로 충분하지만, 추후에는 더 강력한 알고리즘으로 교체해야 할 수도 있다.

update는 변환할 문자열을 받는다. digest는 인코딩할 알고리즘을 넣는다. base64, hex, latin1이 주로 사용되며, base64의 출력물이 가장 짧아서 애용된다.

주로 pbkdf2bcrypt, scrypt 알고리즘으로 암호화를 하는데, 노드는 이중에서 pbkdf2를 지원한다. pbkdf2는 기존 문자열에 salt라고 불리는 문자열을 덧붙여 해시 알고리즘을 반복 적용하는 것이다.

crypto.randomBytes(64, (err, buf) => {
  const salt = buf.toString("base64");
  console.log("salt : ", salt);
  crypto.pbkdf2("비밀번호", salt, 10_000, 64, "sha512", (err, key) => {
    console.log("비밀번호 : ", key.toString("base64"));
  });
});

/* 결과
salt :  WMoCs5ejHbCquryWLdTZjA3EfDXDCJxJg/ogyGw0QzOJM7Yixrc9C4WNUpB8e2MlUqnenBKeXo00Fd0kyb+AgA==
비밀번호 :  ai2balE3cAStcRjTZkbxY9FH9TynSxF8yjIZ+Ph1LNRuqaKeDjsRx2H2ZCsMQF3qASDrWm8rpgks7stLH2abcA==
*/

randomBytes의 첫 번째 인자만큼의 바이트 문자열을 만든다. 이것이 salt가 된다. pbkdf2의 인자는 순서대로 (암호, salt, 반복 횟수, 출력 바이트, 해시 알고리즘)이다. 위 코드는 sha512로 변환된 값을 다시 sha512로 변환하는 과정을 1만 번 반복한다. randomBytespbkdf2는 내부적으로 멀티 스레딩으로 동작해 블로킹되지 않는다.

또한, randomBytes의 결과값은 매번 달라지므로 salt를 잘 보관해야 암호를 찾을 수 있다. pbkdf2는 간단하지만 더 나은 보안이 필요하다면 bcryptscrypt를 사용한다.

7-2. 양방향 암호화

복호화할 수 있는 암호화 방식으로, 복호화 시 암호화할 때와 같은 를 사용해야 한다. 예시의 코드를 완벽히 이해하려면 암호학을 별도로 공부해야 한다고 한다.

const algorithm = "aes-256-cbc";
const key = "abcdefghijklmnopqrstuvwxyz123456";
const iv = "1234567890123456";

const cipher = crypto.createCipheriv(algorithm, key, iv);
let result = cipher.update("암호화할 문장", "utf-8", "base64");
result += cipher.final("base64");
console.log("암호화 : ", result);

const decipher = crypto.createDecipheriv(algorithm, key, iv);
let result2 = decipher.update(result, "base64", "utf-8");
result2 += decipher.final("utf-8");
console.log("복호화 : ", result2);

/* 결과
암호화 :  iiopeG2GsYlk6ccoBoFvEH2EBDMWv1kK9bNuDjYxiN0=
복호화 :  암호화할 문장
*/

createCipherivcreateDecipheriv알고리즘, 키, iv를 인자로 받는다. iv는 암호화 시 사용하는 초기화 벡터이다. 사용 가능한 알고리즘 목록은 getCiphers 메서드로 볼 수 있다.

update문자열, 인코딩, 출력 인코딩을 받는다. 암호화에는 인코딩 utf-8을, 암호화 base64를 많이 사용한다. 복호화에는 반대로 적용한다.

final출력 인코딩을 넣는다.

8. util

각종 편의 기능을 모아둔 모듈이다. 자주 사용하는 메서드로 두 가지가 있다.

import util from "util";
import crypto from "crypto";

const dontUseMe = util.deprecate((x, y) => {
  console.log(x + y);
}, "dontUseMe 함수는 사용하지 마셈");

dontUseMe(1, 2);

const randomBytesPromise = util.promisify(crypto.randomBytes);
randomBytesPromise(64)
  .then((buf) => console.log(buf.toString("base64")))
  .catch((err) => console.error(err));

/* 결과
3
(node:5796) DeprecationWarning: dontUseMe 함수는 사용하지 마셈
(Use `node --trace-deprecation ...` to show where the warning was created)
gbDAG6xwwb8lDH0rdzVj5Emp4z4479j6+8DagHq4Icq4Ro2O9FnAeDhhyk7MlpwnV14g2CnGvP/6/iZ3TTcz3Q==
*/

deprecate는 함수가 deprecated되었음을 알린다. 첫 번째 인자로 넣은 함수를 사용했을 때, 두 번째 인자로 넣은 경고 문구가 출력된다.

promisify는 콜백 패턴을 프로미스 패턴으로 바꾼다. 반대로 바꾸는 callbackify도 있지만 잘 사용하지 않는다고 한다.

9. 기타 모듈

  • worker_thread : 멀티 스레드 방식으로 작업할 때 사용한다.
  • child_process : 다른 프로그램을 실행하고 싶거나 명령어를 수행하고 싶을 때 사용한다.
  • async_hooks : 비동기 코드의 흐름을 추적할 수 있는 실험적인 모듈이다.
  • dgram : UDP 관련 작업할 때 사용한다.
  • net : TCPIPC 통신할 때 사용한다.
  • querystring : URLSearchParams 이전에 사용했던 모듈이다.
  • string_decoder : 버퍼 데이터를 문자열로 바꾸는 데 사용한다.
  • tls : TLSSSL 관련 작업에 사용한다.
  • tty : 터미널 관련 작업에 사용한다.
  • v8 : V8 엔진에 접근할 때 사용한다.
  • vm : 가상머신에 접근할 때 사용한다.
  • wasi : 웹어셈블리를 실행할 때 사용하는 실험적인 모듈이다.

참고
Node.js 공식 사이트
Node.js 교과서 개정 3판

profile
프론트엔드 개발자가 되고 싶다

0개의 댓글