보안에는 4단계가 있다(고하더라).
일단 영어가 섞여 있으니 용어가 어질어질하다.
# | 단계 | 보안 방법 |
---|---|---|
1 | 네트워크 수준 보안 | VPN 터널을 사용하여 네트워크 연결 보호 |
2 | 전송 수준 보안 | HTTP와 마찬가지로 TLS/SSL로 전송 계층 보호 |
3 | 애플리케이션 수준 보안 | 고유한 클라이언트 식별자, 또는 이름/비밀번호로 자격 증명 |
4 | 페이로드 암호화 | 애플리케이션 수준에서 페이로드 자체를 암호화 |
그래서 딱 2개, 2번 TLS/SSL 보안과 3번 자격증명 해보자.
나머지는 이 글 범위를 넘어선다(라고 쓰고 줄행랑💨💨💨).
맨 먼저 내가 누군지 확인 안 된 놈은 입구컷이다.
그래야 어장 관리가 되지 안 그러면 broker 거덜난다.
mosquitto는 기본적으로 localhost 로 붙을 땐 자격증명 없어도 붙지만, 외부에서 붙을 땐 자격증명이 필요하다.
localhost고 뭐고 무조건 내가 누군지 까야 붙을 수 있게 하려면 mosquitto.conf 파일에 다음과 같이 하면 된다.
그리고 mosquitto 2.0 이상에서는 localhost가 아닌 다른 곳에서도 붙게 하려면 listener를 정의해야 한다. 보안 때문에 강화된 거란다.
mosquitto.conf
listener 1883
allow_anonymous false
그 다음 입장자 명단을 만들고, 해킹을 대비해 암호화 한다.
password
server:pwd
client:pwd
이 파일은 mosquitto_passwd 프로그램으로 다음의 명령으로 암호화하라.
$> mosquitto_passwd.exe password
그러면 파일이 아래와 같이 변하는 기적을 맛볼 것이다.
password
server:$7$101$p4wSJs3pD1lwGE2X$HeddQkc56jh2ZehHeCe/W+dq3EgynumOmMdYTkw8hdu8rKXbOjWPfYiqmM/wmTh3oIyu6fcVyH4w84E/SRIMjw==
client:$7$101$QZizFrfQBO53ZAcq$J6GR7oh5UqeK3UGOVy7EpG0Sf7TIJObl6pkRTyjA8j4xy3jdbS0kJEjOSt7IQ6K5tsqpgwHkmubbxKf0gg97/w==
password 파일을 만들었으면 준비는 다 된거다.
이 파일을 mosquitto.conf 파일에 추가하고 함 껏다 켜준다.
mosquitto.conf
listener 1883
allow_anonymous false
password_file C:\Program Files\mosquitto\conf.d\password
이제 우리는 정문에 기도를 세워 둔거다.
기본 어장 관리는 된다고 보면 된다.
client 입장에서는, 이제 물관리하는 이 아저씨를 통과해야 한다.
당연히 민증 까야지.
server.js
const options = {
host: 'stark',
port: 1883,
username: 'server',
password: 'pwd'
}
const client = mqtt.connect(options);
server도 borker 입장에서는 client다.
client.js
const options = {
host: 'stark',
port: 1883,
username: 'client',
password: 'pwd'
}
const client = mqtt.connect(options);
'stark'가 뭐냐구?
hosts 파일에 등록한 mosquitto 서버 이름이다.
C:\Windows\System32\drivers\etc\hosts
192.168.219.101 stark
이름이 왜 stark 냐구? mosquitto example 에 있는 이름 그대로 썼다.
네트웍 중간에 김선생이 청진기 대고 있으면 어떡할건가?
다음은 wireshark으로 패킷 캡쳐한 것이다.
암호화하지 않았을 경우 server/login 으로 넘긴 데이터가 다 보인다.
뜨악😱이다.
이 상태로 플젝 끝했다가는 개폭망이라 봐도 무방하다.
김선생 못 알아보게 만들어야 한다.
다음은 TLS로 암호화한 것이다.
뚫어져라봐도 당췌 뭐가 오고 간 것인지 추측도 하기 어렵지 아니한가 우하하하.
심지어 topic명도 알아 볼 수 없다.
이거 해보자 했는데, 이미 한 분들 많더라.😂
인증서 만드는 것은 이 글을 따라하면 된다.
다만 nodejs 관련 설정은 다음과 같이 하면 된다.
server.js
const fs = require('fs')
const path = require('path')
const KEY = fs.readFileSync(path.join(__dirname, '/tls/server.key'))
const CERT = fs.readFileSync(path.join(__dirname, '/tls/server.crt'))
const TRUSTED_CA_LIST = fs.readFileSync(path.join(__dirname, '/tls/ca.crt'))
const options = {
port: 1883,
host: 'stark',
username: 'server',
password: 'pwd',
key: KEY,
cert: CERT,
rejectUnauthorized: true,
ca: TRUSTED_CA_LIST,
protocol: 'mqtts'
}
const server = mqtt.connect(options);
client.js
const fs = require('fs')
const path = require('path')
const KEY = fs.readFileSync(path.join(__dirname, '/tls/client.key'))
const CERT = fs.readFileSync(path.join(__dirname, '/tls/client.crt'))
const TRUSTED_CA_LIST = fs.readFileSync(path.join(__dirname, '/tls/ca.crt'))
const options = {
port: 1883,
host: 'stark',
username: 'client',
password: 'pwd',
key: KEY,
cert: CERT,
rejectUnauthorized: true,
ca: TRUSTED_CA_LIST,
protocol: 'mqtts'
}
const server = mqtt.connect(options);
사실 보안을 다룰 때 '완벽' 이란 없다.
외부 침투를 아무리 완벽하게 막았다고 하더라도, 대부분 구멍은 내부자에게 있다.
스노든 아저씨를 봐라.
따라서 자격증명 파일, 인증서 파일은 은밀한 곳에 따로 보관하자.
적어도 production 환경이라도...🙏🙏🙏