티스토리 뷰
1. 일반적으로 데이터베이스의 저장은 hashing을 많이 사용하지만 암호화를 사용하는 경우도 많다.
1-1 관공소의 데이터베이스는 XecureDB, D'amo 같은 암호화 모듈을 사용하여 저장한다.
2. node.js에서 mongo DB를 사용할 때는 편의성 때문에 mongoose를 대부분 사용한다.
2-1 mongoose를 사용할 경우 mongoose-encryption를 사용하면 간단하게 암호화 처리를 할 수 있다.
3. mongoose-encryption은 하나의 키를 가지고 암호화, 복호화를 진행하는 대칭형 AES-256-CBC를 사용한다.
3-1 즉 암호키를 알면 모든 것을 다 복호화하여 다시 plain text를 만들 수 있다.
3-1-1 암호화 는 수학적으로 다양한 연산을 사용하는데 알 필요가 없다. 별짓을 다해도 결국 key가 있으면 끝난다.
3-2 인증 방식은 HMAC-SHA-512를 사용한다.
3-2-1 HMAC는 hashing를 기본으로 한 메시지 인증방식으로 메시지의 integrity와 authenticity를 검증한다.
3-2-2 HMAC은 MD5, SHA 같은 방식의 해싱과 공유비밀키를 가지고 수행한다.
3-2-3 HMAC-SHA-512는 메시지 인증 시 SHA 512방식의 hashing을 사용한다는 의미이다.
3-3 사용방식 - 디지털 서명과 거의 유사하다.
3-3-1 사용자 A, B가 공유된 비밀키를 가지고 있고 A가 메시지 작성 후, 공유비밀키와 메시지를 함께 해싱한다.
3-3-2 해싱 알고리즘에 따라 HMAC-SHA-512, HMAC-SHA-256, HMAC-MD-5 같이 불려 진다.
3-3-3 만들어진 hash와 메시지를 함께 A는 B에게 전송한다.
3-3-4 B는 수신한 메시지를 공유 비밀키로 A가 한 것과 같이 동일한 방식으로 hash를 생성한다.
3-3-5 B가 만든 hash가 A가 보내 준 것과 동일하면 정상적인 인증이 완료된다.
3-4 mongoose-encryption은 암호화 할 데이터를 JSON으로 변경, 암호화한 후 Binary구조로 _ct라는 필드에 저장한다.
3-4-1 복호화 과정은 대칭키이기 때문에 _ct를 복호화하고 JSON을 객체로 변경한다.
3-5 인증하는 과정은
3-5-1 암호키가 서버에 있기 때문에 _id와 _ct 등의 필드와 함께 서명 암호키로 hash를 만들어 _ac 필드에 저정한다.
3-5-2 검증 시 사용자에서 받은 정보로 DB에서 유저정보를 찾아 동일하게 hash를 만들어 일치하는지를 확인한다.
4. 프로그램의 사용
4-1 암호화 관련된 기본적인 내용이 이해하기 까다로운 것이지 프로그램은 아주 간단하다.
4-1-1 mongoose-encryption을 설치하고 require로 가져온다.
4-1-2 암호키와 인증키를 같은 것을 사용해도 되지만 다른 것을 사용하는 것이 좀 더 안전하다.
4-1-2-1 아래 처럼 openssl을 사용하면 좀 더 편리하게 키를 만들 수 있다.
4-1-3 암호키는 64 비트기반의 32바이트를 요구하고, 인증키는 64비트 기반 64바이트의 길이의 키를 요구한다.
4-1-4 dotenv를 사용하여 외부에 환경변수를 사용하는 것이 이런 키를 저장하는데 안전하다.
4-1-4-1 .env 파일에 다음과 같이 속성들을 정의해 둔다.
ENCKEY=Sak+W4OLlL5hv/rCzN3usphWT731vACAWV8AuSfDXwg=
SIGKEY=Ec8+VkvilBm6dMPSz3aUIpVEFeX5w0msB+MccreqY2rcAvYgr+rli7vwUWaPqlrEJbcCAKQFww8A06wXV1euIg==
4-1-5 encKey, sigKey를 받아와서 저장해 두고 mongoose에 암호화 기능을 추가하기 위해서 plugin에 등록한다.
4-1-5-1 등록할 때 각 키도 같이 option으로 등록해야 하고 암호화 할 필드를 지정할 수 있다.
4-1-5-2 아래는 password 부분만 암호화 하도록 하였다.
4-1-6 mongoose의 save를 호출할 경우 암호화되고 서명된 후에 저장되고 find가 호출될 때 인증 및 복호화 된다.
const express = require('express')
const mongoose = require('mongoose')
const encrypt = require('mongoose-encryption')
require('dotenv').config()
const app = express()
const userSchema = new mongoose.Schema({
email: String,
password: String
})
// openssl rand -base64 32; openssl rand -base64 64;
const encKey = process.env.ENCKEY
const sigKey = process.env.SIGKEY
userSchema.plugin(encrypt, {
encryptionKey: encKey,
signingKey: sigKey,
encryptedFields: ['password']
})
// we have to connect all the plugins to the schema before making model
const User = mongoose.model("User", userSchema)
app.use(express.urlencoded({ extended: true }))
app.use(express.static("public"))
app.set("view engine", "ejs")
mongoose.connect("mongodb://localhost:27017/userDB", {
useNewUrlParser: true,
useUnifiedTopology: true
}, function(err) {
if (!err) {
console.log('Connected to mongodb at 27017 port')
} else {
console.log('Could not connect to mongodb on localhost');
}
})
app.get("/", function (req, res) {
res.render("home")
})
app.get("/register", function (req, res) {
res.render("register")
})
app.get("/login", function (req, res) {
res.render("login")
})
app.post("/register", function (req, res) {
const user = new User({
email: req.body.username,
password: req.body.password
})
user.save(function(err, user) {
if (err) {
res.redirect("/register")
} else {
console.log(user)
res.render("secrets")
}
})
})
app.get("/secrets", function(req, res) {
res.redirect("/")
})
app.post("/login", function(req, res) {
User.findOne({ email: req.body.username }, function(err, user) {
if (err) {
res.redirect("/login")
} else {
if (user) {
if (user.password === req.body.password) {
res.render("secrets")
} else {
res.redirect("/login")
}
} else {
res.redirect("/login")
}
}
})
})
app.get("/logout", function(req, res) {
res.redirect("/login")
})
app.listen(3000, function () {
console.log("Server is runnong on port 3000");
})
4-2 위의 코드를 보면 register가 회원등록인데 다른 코드와 다른 점이 없다.
4-3 post의 /login을 보면 사용자가 입력한 username으로 DB를 검색하여 찾아 user로 데이터를 받을 때 복호화 된다.
4-3-1 복호화가 되었기 때문에 데이터베이스에서 가져온 user 객체는 password가 plain text로 보여진다.
4-3-2 사용자가 입력한 password와 복호화 된 password를 비교하여 사용자 검증을 하게 된다.
'Side Technologies' 카테고리의 다른 글
VS Code: 여러 개의 자바버전 관리하기 (0) | 2021.05.05 |
---|---|
Node : JavaScript 키보드로부터 입력 받기 stdin (1) | 2021.05.03 |
Kafka : CLI에서 Consumer Group 사용하기 (0) | 2020.09.15 |
Kafka : CLI로 메시지 전송 및 수신 (0) | 2020.09.15 |
Kafka : 윈도우에서 TOPIC 생성 및 관리, 서버 기동과 다운 (0) | 2020.09.14 |
- Total
- Today
- Yesterday
- 도커 개발환경 참고
- AWS ARN 구조
- Immuability에 관한 설명
- 자바스크립트 멀티 비동기 함수 호출 참고
- WSDL 참고
- SOAP 컨슈머 참고
- MySql dump 사용법
- AWS Lambda with Addon
- NFC 드라이버 linux 설치
- electron IPC
- mifare classic 강의
- go module 관련 상세한 정보
- C 메모리 찍어보기
- C++ Addon 마이그레이션
- JAX WS Header 관련 stackoverflow
- SOAP Custom Header 설정 참고
- SOAP Custom Header
- SOAP BindingProvider
- dispatcher 사용하여 설정
- vagrant kvm으로 사용하기
- git fork, pull request to the …
- vagrant libvirt bridge network
- python, js의 async, await의 차이
- go JSON struct 생성
- Netflix Kinesis 활용 분석
- docker credential problem
- private subnet에서 outbound IP 확…
- 안드로이드 coroutine
- kotlin with, apply, also 등
- 안드로이드 초기로딩이 안되는 경우
- navigation 데이터 보내기
- 레이스 컨디션 navController
- raylib
- Spring Security
- Many-To-Many
- Spring
- hibernate
- 하이버네이트
- 설정
- Validation
- Security
- 상속
- mapping
- XML
- form
- Rest
- 매핑
- RestTemplate
- login
- 자바
- 로그인
- Angular
- 스프링
- 설정하기
- MYSQL
- crud
- 스프링부트
- one-to-many
- spring boot
- jsp
- WebMvc
- 외부파일
- one-to-one