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(도메인, 레코드)
로 조회한다.
암호화 모듈로, 보안에 활용할 수 있다.
단방향 암호화란 복호화할 수 없는 암호화이다. 즉, 한 번 암호화하면 원래 무슨 문자였는지 되돌릴 수 없다. 해시 함수라고도 부르며, 보통 고객의 비밀번호에 활용한다.
고객의 비밀번호를 암호화해 저장한 후, 로그인 시 입력 받은 비밀번호를 같은 암호화 알고리즘(주로 해시 기법
)으로 암호화해 비교한다. 해시 함수의 사용은 다음과 같다.
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
등이 있지만, md5
와 sha1
은 이미 취약점이 발견되었다고 한다. 아직까지는 sha512
로 충분하지만, 추후에는 더 강력한 알고리즘으로 교체해야 할 수도 있다.
update
는 변환할 문자열을 받는다. digest
는 인코딩할 알고리즘을 넣는다. base64
, hex
, latin1
이 주로 사용되며, base64
의 출력물이 가장 짧아서 애용된다.
주로 pbkdf2
나 bcrypt
, 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만 번 반복한다. randomBytes
와 pbkdf2
는 내부적으로 멀티 스레딩으로 동작해 블로킹되지 않는다.
또한, randomBytes
의 결과값은 매번 달라지므로 salt
를 잘 보관해야 암호를 찾을 수 있다. pbkdf2
는 간단하지만 더 나은 보안이 필요하다면 bcrypt
나 scrypt
를 사용한다.
복호화할 수 있는 암호화 방식으로, 복호화 시 암호화할 때와 같은 키
를 사용해야 한다. 예시의 코드를 완벽히 이해하려면 암호학을 별도로 공부해야 한다고 한다.
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=
복호화 : 암호화할 문장
*/
createCipheriv
과 createDecipheriv
는 알고리즘, 키, iv
를 인자로 받는다. iv
는 암호화 시 사용하는 초기화 벡터이다. 사용 가능한 알고리즘 목록은 getCiphers
메서드로 볼 수 있다.
update
는 문자열, 인코딩, 출력 인코딩
을 받는다. 암호화에는 인코딩 utf-8
을, 암호화 base64
를 많이 사용한다. 복호화에는 반대로 적용한다.
final
은 출력 인코딩
을 넣는다.
각종 편의 기능을 모아둔 모듈이다. 자주 사용하는 메서드로 두 가지가 있다.
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
도 있지만 잘 사용하지 않는다고 한다.
worker_thread
: 멀티 스레드 방식으로 작업할 때 사용한다.child_process
: 다른 프로그램을 실행하고 싶거나 명령어를 수행하고 싶을 때 사용한다.async_hooks
: 비동기 코드의 흐름을 추적할 수 있는 실험적인 모듈이다.dgram
: UDP
관련 작업할 때 사용한다.net
: TCP
나 IPC
통신할 때 사용한다.querystring
: URLSearchParams
이전에 사용했던 모듈이다.string_decoder
: 버퍼 데이터를 문자열로 바꾸는 데 사용한다.tls
: TLS
와 SSL
관련 작업에 사용한다.tty
: 터미널 관련 작업에 사용한다.v8
: V8 엔진에 접근할 때 사용한다.vm
: 가상머신에 접근할 때 사용한다.wasi
: 웹어셈블리를 실행할 때 사용하는 실험적인 모듈이다.