보안 암호 관리자: MERN Stack 애플리케이션 - Cryptor 암호화 패키지 사용
보안 암호 관리자 도입🔐
암호를 암호화하여 데이터베이스에 저장하여 민감한 정보의 유출을 피하는 안전한 암호 관리자
Disclaimer: Please don't enter in your original passwords yet and also its an open showcase app, so whatever you enter can be seen to other people with the same link. Use it to experience the different functionalities and dynamic features of the app.
라이브 링크 https://main.d3qwkjcxzk7m67.amplifyapp.com/
소스 코드: https://github.com/GeoBrodas/aws-password-manager/tree/main
특징:👀
aes-256-gcm
알고리즘으로 암호화.기술 스택 및 리소스⚛️
영감.💡
나는 보통 비밀번호를 브라우저에 저장하지만, 맑은 날, 나의 구글 브라우저에서 갑자기 그들의 데이터베이스에 데이터가 유출되었고, 일부 비밀번호가 유출되었기 때문에 그것들을 바꾸는 것이 절실하다는 경고가 나왔다.
그리고 나는 모든 비밀번호를 바꾸는 것에 싫증이 났어. 알고 싶어...만약에 내가 자신의 암호 관리자를 만들 수 있다면 데이터베이스에서 암호화하여 노출의 기회를 줄일 것이다. 물론 나만 이 프로그램에 접근할 수 있다. 그때부터 나는React와 Cryptor를 사용하여 서버 측에 안전한 암호 관리자를 구축하여 암호화하기 시작했다.따라서 더 이상 먼지를 털지 말고 개발의 여정을 시작하자!
응용 프로그램 개발 과정의 각 단계🚶🏽♂️
그래서 저는 먼저 구축 과정을 5단계로 나누어 매일 각 단계에 집중하고 5일 안에 응용 프로그램을 준비할 수 있습니다. -
색채 영감🎨
이거 진짜 멋있다.나는 애니메이션에서 구조 장갑에 사용되는 팔레트를 사용했다.
1. 앞면에서react를 사용하여 동적 렌더링을 합니다.👁️
그래서 첫날에 저는 전방에 주의를 기울였습니다. 기본적으로 카드를 만들고'모두'단추를 누르면 동적 표현을 위해 카드를 삭제하고 싶습니다.이를 위해서는 먼저 두 개의 입력을 포함하는 폼이 필요합니다. 사용자가 입력한 계정 이름과 비밀번호를 받을 수 있습니다.그 다음은 사용자 입력 증명서를 표시하는 카드 구성 요소입니다.그 다음에 모든 카드에는 삭제 단추가 포함되어 있어야 한다.여느 때와 같이 카드를 추가하기 위해서 저는 두 입력 모두에 onChange 속성을 부여하고useState 갈고리를 사용하여 입력한 증명서를 저장합니다.정보를 제출하기 위해 도구를 만들었습니다. 이 도구는useState에 대한 설명
credit
대상을 받아들일 것입니다.const [credit, setCredit] = useState({
accName: "",
pass: "",
});
function handleChange(event) {
const { name, value } = event.target;
setCredit((prevNote) => {
return {
...prevNote,
[name]: value,
};
});
}
function submitCred(event) {
props.onAdd(credit);
setCredit({
accName: "",
pass: "",
});
event.preventDefault();
}
그리고 이 도구들을 메인 프로그램에 전달합니다.jsx 파일.const [allCreds, setCred] = useState([]);
function addCred(newCred) {
setCred((prevCreds) => {
return [...prevCreds, newCred];
});
}
<InputTextArea onAdd={addCred} />
이것은 데이터를 allCreds 그룹에 대상으로 저장하고 맵 함수를 사용하여 모든 정보를 카드 구성 요소에 렌더링할 수 있습니다.<div className="flexbox">
{allCreds.map((cred, index) => {
return (
<Card
key={index}
id={index}
name={cred.accName}
pass={cred.pass}
onDelete={deleteCred}
/>
);
})}
</div>
이 카드 구성 요소는 onDelete라는 다른 도구를 받을 것입니다. 이 도구는 onClick 이벤트를 촉발할 때 되돌아오는 카드 인덱스를 되돌려줍니다.id
인덱스 매개 변수가 매핑 함수를 통해 설정됩니다.function removeCard() {
props.onDelete(props.id);
}
주 응용 프로그램에서jsx 파일 삭제 함수는 필터 함수를 포함하고, 이 함수는 인덱스를 제외한 카드 구성 요소를 제외한 모든 카드 구성 요소로 되돌려줍니다.function deleteCred(mid, id) {
setCred((prevCreds) => {
return prevCreds.filter((cred, index) => {
return index !== id;
});
});
}
이 점을 통해 우리는 React 응용 프로그램에서 모든 완전한 전단 목표를 실현하였다.2. MongoDB 데이터베이스를 설정하고 앞에서 읽고 만들고 삭제합니다.🗂️
우선, 클라우드에서 당신의 데이터베이스를 위탁 관리할 몬고 DB Atlas가 필요합니다.MongoDB는 초기 응용 프로그램을 테스트할 수 있는 512MB의 무료 층 계획을 가지고 있다.그리고 나는 나의 응용 프로그램을 몬godB 데이터베이스에 연결했다.우선, 백엔드와 프런트엔드 Axios에express,cors,mongoose를 설치하여 백엔드에 API 요청을 보냅니다.Cors는 백엔드와 프런트엔드 간의 연결을 지원합니다.
Mongodb 데이터베이스에 전송된 각 요청의 모델 모델은 다음과 같습니다. -
const CredSchema = new mongoose.Schema({
accName: {
type: String,
required: true,
},
pass: {
type: String,
required: true,
},
});
그래서 모든 설정을 완성한 후에 첫 번째 임무를 시작합니다. - 전방에서 후단까지 증명서를 제출합니다.사용자가 제출 버튼을 클릭할 때 Axios Post 요청을 보낼 수 있습니다.Axios.post("https://localhost:3001/insert", {
accName: newCred.accName,
pass: newCred.pass,
});
서버에서, 우리는 Axios로부터 API 요청을 받은 다음, Mongoose를 사용하여 데이터베이스 항목을 만들어야 한다.app.post("/insert", async (req, res) => {
const name = req.body.accName;
const password = req.body.pass;
const newCred = new CredModel({
accName: name,
pass: password,
});
try {
newCred.save();
res.send("Inserted Data");
} catch (err) {
console.log(err);
}
});
한 가지 일을 완성했으니 두 가지 더 있다!현재, 우리는 페이지를 불러올 때 데이터베이스에 있는 모든 정보를 앞에 보여야 한다.이를 위해, 페이지를 처음 불러올 때useEffect 갈고리를 사용하여 Axios Get 요청을 보낼 수 있습니다.요청한 응답을 설정allCreds
상태로 사용할 수 있습니다.useEffect(() => {
Axios.get("https://localhost:3001/read").then(
(response) => {
setCred(response.data);
}
);
}, []);
마지막으로 사용자가 삭제 단추를 눌렀을 때 카드를 삭제하는 것은 까다로운 문제이다.이제 Get이 데이터베이스에 있는 모든 데이터를 반환할 것을 요청하면 속성 이름
_id
이 있는 고유한 ID가 반환됩니다.mid
in for MongoDB id로 명명하겠습니다. 데이터베이스에 있는 모든 증거를 보여주는 데 사용할 맵 함수 mid
를 만들 수 있습니다.Note: I don't want all the code to clutter and hence I'm removing some props to make you'll understand😊
{allCreds.map((cred, index) => {
return (
<Card
key={index}
mid={cred._id}
/>
);
})}
이 도구는 두 번째 매개 변수로 카드 구성 요소의 delete 함수를 전달할 수 있습니다.function removeCard() {
props.onDelete(props.mid, props.id);
}
우리 프로그램에서jsx 파일은 이 mid
도구를 통과합니다.이 URL은 Axios 삭제 요청에서 ""이(가) 아닌 뒤에 있는 확인란에 포함되어 있습니다.이것은 자바스크립트의 매우 유용한 기능이다.
mid
도구를 ${mid}
에 봉하여 백엔드에 전달하는 방법에 주의하십시오.function deleteCred(mid, id) {
setCred((prevCreds) => {
return prevCreds.filter((cred, index) => {
return index !== id;
});
});
Axios.delete(`https://localhost:3001/delete/${mid}`);
//use back-tickssss--importantttt!!!!
}
서버에서 삭제 루트를 만들고 몬고우스findByIdAndRemove
방법으로 데이터베이스에서 mid
와 일치하는 항목을 찾아서 삭제합니다.app.delete("/delete/:id", async (req, res) => {
const id = req.params.id;
await CredModel.findByIdAndRemove(id).exec();
res.send("deleted item: " + id);
});
3. 암호를 표시하기 위해 서버에서 암호화하고 복호화합니다.🔐
암호화 형식으로 암호를 저장하는 암호화에 대해 우리는
cryptr
라는 간단한 npm 패키지를 사용할 수 있다.이제 키를 만들어서 설정할 수 있으며, Cryptor에서 제공하는 encrypt
함수와 decrypt
함수를 호출해서 문자열을 암호화하고 복호화할 수 있습니다.const Cryptr = require("cryptr");
const cryptr = new Cryptr("yoursecretkey");
우리는 클라이언트가 Axios의 post 요청을 받은 후 즉시 비밀번호를 암호화하기를 희망합니다.const name = req.body.accName;
const password = cryptr.encrypt(req.body.pass);
const newCred = new CredModel({
accName: name,
pass: password,
});
암호는 현재 저희 데이터베이스에서 aes-256-gcm
알고리즘을 사용하여 암호화됩니다.나를 믿어라. 이것은 개발 과정에서 가장 어려운 부분이다. 즉, 사용자가 비밀번호를 눌렀을 때 사용자에게 원시 비밀번호를 표시하는 것이다👁 버튼을 누릅니다.
현재, 나는 사용자로 하여금 onClick 이벤트를 터치하게 하고, 이 함수는 두 개의 인자를 받아들여 주 프로그램에 전달하는 함수를 전달한다.jsx 파일.
function showP() {
props.seePassword(props.pass, props.id);
}
내 주 프로그램에서jsx 파일에서 이 도구를 Map 함수의 카드 요소에 함수로 전달합니다.{allCreds.map((cred, index) => {
return (
<Card
key={index}
id={index}
seePassword={getPassword}
pass={cred.pass}
/>
);
})}
GetPassword 함수에서 암호화된 비밀번호를 전달합니다.Map 함수를 사용하여 이 비밀번호를 클릭하고, Axios를 사용하여 서버에 post 요청을 보내서 모든 암호화된 비밀번호를 전방으로 보낼 수 있습니다.//App.jsx file
function getPassword(password, id) {
Axios.post("https://localhost:3001/showpassword", {
password: password,
}).then((response) => {
setCred(
allCreds.map((cred, index) => {
return index === id
? {
accName: response.data,
pass: cred.pass,
}
: cred;
})
);
});
}
//index.js file at server-side
app.post("/showpassword", (req, res) => {
res.send(cryptr.decrypt(req.body.password));
});
모든 암호를 포함하는 서버에서 받은 응답은 맵 함수를 통해 실행할 수 있습니다.map 함수는 복호화된 암호만 되돌려줍니다. 이 암호는 사용자가 클릭한 카드 구성 요소 id
와 일치합니다.삼원 연산자를 사용하면,useState의 setCred 함수를 사용하여 allCreds 그룹의 상태를 설정할 수 있습니다. 방법은 증빙서류의 이름을 응답과 같게 하는 것입니다.4. 우리의 코드가 환경 변수를 더욱 안전하게 사용하도록 한다.🛡️
이것은
dotenv
라는 npm 패키지로 완성하는 것이 가장 좋다.우리가 열쇠를 저장하는 비밀을 기억해라.GitHub에 코드를 자주 제출하면, 제출을 통해 코드 변경을 인용하는 사람이 있다면, 이 키는 노출되기 쉽다.따라서 환경 변수를 먼저 저장한 다음 에 추가해야 합니다.gitignore 파일을 원격 저장소에 제출합니다.
//index.js file ---Server side
//require the dotenv module at the earliest in your file.
require("dotenv").config();
const cryptr = new Cryptr(process.env.SECRET);
//.env file ----Server side
SECRET=yoursecretkey
dotenv 모듈이 지정한 형식을 따라야 합니다. 즉, 상수는 완전히 대문자로 써야 하며, 키 주위에는 인용부호가 없습니다.5. 배포🚀
서버 파일을 Heroku에 배치합니다.나는 한동안 Heroku를 사용하지 않아서 많은 오류가 있었지만, 동영상과 참고 문서를 보면서 그것을 배치하려고 했다.
나는 내가 개발 구축이 아니라 React의 생산 구축을 배치해야 한다는 것을 안다.나는 React 프로젝트를 배치한 적이 없지만 AWS Amplify 컨트롤러에 직접 갔다. 이것은 나를 위해 자동으로 구축 설정을 생성했다. 이것은 나를 놀라게 했다. 왜냐하면 Netlify 등 위탁 관리 플랫폼이 없기 때문에 개발자는 구축 설정을 언급해야 한다.이 과정은 겨우 4분 만에 프로그램이 시작되고 실행되었다.🚀
Thank you for reading till here!
Hope you liked this blog, if yes hit a ❤
Do let me know if you want the source code for the back-end part. I didn't share it for security reasons, as there are environment variables in it and the password to the MongoDB cluster.
Hit me up or this blog if you liked it.
For me building this app was a big leap because I didn't have the confidence to build a full-stack app like this.
Reference
이 문제에 관하여(보안 암호 관리자: MERN Stack 애플리케이션 - Cryptor 암호화 패키지 사용), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/geobrodas/secure-password-manager-mern-stack-app-using-cryptr-encryption-package-5874텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)