그래도 해결했으니 설령 UPDATE 기능이 안되더라도 대처할 수 있겠다 싶었는데 UPDATE는 웬만한 시도를 다 해봤으나 동작하지 않았다.
UPDATE에서 막힐 거라고는 생각도 못했었는데 DELETE보다 안 되니까 이쯤되면 사실 DELETE도 완벽하게 구현된 게 아닌가? 라는 생각이 들었다.
일단 update, updateOne, findAndModify, findOneAndUpdate 등등 시도해봤고 앞에 컬렉션이름.~, db이름.~ 등 다 갖다붙여봤고 DELETE 구현할 때 시도해봤던 FindOne/Find 사용해보고 아예 없애보기도 했는데 5일동안 구현하지 못했다.
그래서 이제 수정 기능만 구현하면 되는데 마침 마이페이지-개인정보수정 기능을 넣으면 딱이겠다, 싶어서 만들기 시작했다.
다른 공식 페이지들을 보면 개인정보 수정하러 들어가면 폼에 기존 값이 입력되어져있다.
즉, 수정 페이지에 들어가면 화면에 DB값을 입력시켜 놓아야 한다는 것이다.
문제1 json 전송
DB값을 가져와 VUE에 뿌려야했는데 이 부분이 문제였다.
보통은 res.json/res.send로 json을 vue로 보내는 방식을 쓰는 듯한데 내가 res.json/send를 쓰면 페이지가 아래처럼 된다.
빈 화면에 값만 출력된다.
새로고침해도 저런 화면으로 뜨는 데 테스트를 여러 번 해보니 get 방식으로 전송하는 페이지를 새로고침할 경우 새로고침하면 그 페이지의 get 요청이 실행되어버린다.
그래서 처음엔 새로고침을 막을까도 생각했지만 근본적인 해결이 안되기때문에 고민하다가 도메인 연결할 때 참고했던 포스팅에서 frontend랑 backend 경로를 다르게 설정했던 게 떠올랐다.
frontend에서는 /login로, backend에서는 /api/login로 설정하고 frontend랑 backend랑 ip도 다르게 설정하셨던 것 같은데 처음 봤을 때는 왜 굳이 이렇게 설정하지? 라는 생각이 들었는데 구글링하다보니 이렇게 설정하시는 분이 많아서 나도 이렇게 해야하나..? 라는 생각까지 들었다.
그래도 난 저렇게 설정 안해도 문제 없었고 굳이? 라는 생각이 들어서 넘겼는 데 갑자기 이 기억이 생각나면서
배포 전에 보안 처리를 해야하는 데 나는 어차피 GIT에 모든 코드가 올라가있기 때문에 보안 상 다 뚫려있지만 실제 상업용 사이트를 배포하는 것처럼 세팅을 해놓을 것이다.
그 동안은 회원가입/로그인 기능 테스트를 위해 패스워드를 암호화하지 않았지만, 이제 배포를 앞두고 보안 처리를 해야 한다.
먼저 패스워드를 암호화해서 저장하고 로그인 시 암호화 된 문자열을 비교해 회원 가입 여부를 판단할 수 있도록 구현할 것이다.
참고한 사이트
여기는 암호화의 종류와 개념을 이해하기 쉽게 설명되어 있다.
여기는 실제로 코드에 구현할 때 참고하기 좋다.
두 사이트 모두에서 코드를 참고했다.
패스워드 암호화해서 DB에 저장하기
사실 암호화하는 코드는 참고한 사이트에서 보면 생각보다 짧아서 어렵지 않구나 하고 생각했는데 salt를 어떻게 저장해야 하는 가에서 약간 헤맸다.
구글링을 해보면 salt는 돌릴 때마다 값이 달라지니 로그인 기능을 구현하려면(동일 값 여부 확인) 하려면 암호화 할 당시의 salt 값이 필요하고(사용자마다 고유한 salt 값 가짐) 그러려면 어딘가에는 저장해야 한다고 나와 있었다.
근데 저장해야 한다면 DB가 제일 먼저 생각났는데 DB에 암호화된 패스워드랑 salt 값을 같이 저장하면 암호화한 의미가 없어지지 않나? 라는 생각이 들어서 망설여졌다.
게다가 DB에 저장하는 경우도 찾아봤는데 그냥 암호화 개념 설명을 편하게 하기 위해 DB에 저장하는 듯한 느낌이어서 DB에 저장해도 되나 라는 생각이 들었다.
그런데 다시 생각해보면 패스워드를 암호화하는 이유는 DB가 해킹 당했을 때 패스워드를 알아보지 못하게 하기 위함이고 그러면 DB에 암호화된 패스워드와 salt 값을 같이 넣어도 어떤 방식으로 암호화했는 지는 DB가 아니라 코드에 나와있기 때문에 같이 저장해도 되는 거 아닐까 라는 생각이 들었다.
그래서 나는 일단 DB에 salt 값을 같이 저장했다.
var password = request.body.password;
crypto.randomBytes(64, (err, buf) => {
const salt = buf.toString('base64')
crypto.pbkdf2(password, salt, 107529, 64, 'sha512', (err, key) => {
User.create ({ //DB 생성
id:request.body.id,
password:(key.toString('base64')),
salt : salt,
name:request.body.name,
phone:request.body.phone,
});
});
});
암호화한 패스워드 값 비교하기(로그인)
사용자가 입력한 id 값으로 DB에서 사용자를 찾고 DB에 같이 저장된 salt 값을 가져와서 동일한 방식으로 암호화해서 패스워드 동일 유무를 확인하는 방식으로 코드를 작성했다.
User.findOne({id : req.body.id},(err, users) => { // id를 먼저 체크해서
if(!users || err){ //id가 DB에 없으면(즉, id가 틀렸거나 회원가입이 안되어 있거나)
res.redirect('/login');
}
else {
var cpassword = req.body.password; // 사용자가 입력한 패스워드를 가져와서
crypto.randomBytes(64, (err, buf) => {
crypto.pbkdf2(cpassword, users.salt, 107529, 64, 'sha512', (err, key) => {
cpassword = key.toString('base64') // DB에 저장했던 동일한 방식으로 암호화
if (users.password == cpassword) { // 저장된 패스워드와 암호화된 입력받은 패스워드 비교
res.cookie('session', users.name, {
maxAge : 6000000 // 쿠키 1시간 유지
});
res.redirect('/');
}
});
});
}
})