비밀번호 생성기 고쳐보기

시작하기 전에
작년 초에 비밀번호 생성기를 처음 만들고 며칠전에 리팩토링도 할 겸 다시 수정해보기로 했다. 코드를 다시 살펴보던 중에 몇 가지 문제점을 발견하고 이에 대해 고민해본 흔적을 블로그로 남기려고 한다.
CRA에서 Vite로
사실 이거는 문제점이라고 하기엔 그렇고, 처음에는 CRA로 설치해서 진행했지만 몇 년 전부터 지원을 중단했고 리액트 공식 문서에서도 언급을 하지 않고 있다. 심지어 설치하고 실행하기까지의 시간이 상당히 느려서 다들 Vite로 넘어가는 추세이기도 해서 Vite로 마이그레이션을 진행했다.
마이그레이션 하기
[React] CRA 프로젝트 Vite로 마이그레이션하기
위 블로그를 참고해서 마이그레이션을 시작했다.
패키지 설치
npm install --save-dev vite @vitejs/plugin-react
vite.config.ts 파일 생성
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [react()]
});
블로그에는 서버 포트번호 설정, alias 설정도 했지만, 나는 기본틀만 필요했기에 위 코드 정도로 작성해줬다.
index.html 수정
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See <https://developers.google.com/web/fundamentals/web-app-manifest/>
-->
<link rel="manifest" href="/manifest.json" />
<title>Random Password Generator</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root">
<script src="<https://developers.kakao.com/sdk/js/kakao.js>"></script>
</div>
// 메인 파일 추가
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
트러블 슈팅
ImportMeta 형식에 env 속성이 없습니다.
생성한 비밀번호를 카카오톡으로 공유하기 위해 다음처럼 코드를 작성했었는데
ImportMeta 형식에 env 속성이 없습니다.
라는 오류가 떴다.
구글링 결과 tsconfig.json
에 다음과 같이 추가하면 된다고 하는데
{
"compilerOptions": {
"types": ["vite/client"]
}
}
이게 무슨 역할을 하는것인지 알아보자.
vite/client?
vite/client에 대해 알아보기 전에 ImportMeta 형식에 env 속성이 없습니다.
오류가 왜 발생했는지 알아보자.
import.meta까지만 작성하고 내부에 더 어떤 프로퍼티가 있는지 확인해본 결과다.
global {
interface ImportMeta {
url: string;
/**
* @experimental
* This feature is only available with the `--experimental-import-meta-resolve`
* command flag enabled.
*
* Provides a module-relative resolution function scoped to each module, returning
* the URL string.
*
* @param specified The module specifier to resolve relative to `parent`.
* @param parent The absolute parent module URL to resolve from. If none
* is specified, the value of `import.meta.url` is used as the default.
*/
resolve?(specified: string, parent?: string | URL): Promise<string>;
}
}
보다시피 resolve,url 외에 다른 프로퍼티가 존재하지 않는다. 그렇기 때문에 env 속성이 존재하지 않는 오류가 뜬 것이었다.
이에 대해 vite/client는 import.meta.env
에 대한 타입 정의를 포함해서 환경 변수 접근을 가능하도록 한다.
첫번째 vercel 배포 오류
vercel에 올리니 위와 같은 엄청난 오류가 잔뜩 나왔다.
처음에 설치한 vite 버전과 @types/node 버전이 제대로 안 맞은 문제였다.
두번째 vercel 배포 오류
두 번째 오류는 Output 경로가 잘못됐다는 오류로 나온다. vercel 설정을 보니 Build 세팅이 Create React App으로 설정되어있었다. 이 부분을 Vite로 바꿔주니 제대로 빌드가 되었다.
문제점
기존에 만들어놨던 비밀번호 생성기에 몇 가지 문제점이 있었고, 이것을 고쳐보는 작업을 진행했다.
비밀번호 생성 로직 문제
처음 비밀번호를 생성하는 로직을 구성할 때 Math.random 로직을 사용했었는데 개선점을 더 찾아보던 중에 Math.random
의 취약점을 알게 되었다.
MDN의 문서에 따르면 **Math.random()
**는 암호학적으로 안전한 난수를 생성해주지 않는다.
Note: Math.random() does not provide cryptographically secure random numbers. Do not use them for anything related to security. Use the Web Crypto API instead, and more precisely the window.crypto.getRandomValues() method.
이전 코드
const buildPassword = (length: number, charset: string) =>
Array(length).fill(0).map(() => charset[Math.floor(Math.random() * charset.length)]).join("");
개선 후
const buildPassword = (length: number, charset: string) => {
const array = new Uint32Array(length);
crypto.getRandomValues(array);
return Array.from(array, (num) => charset[num % charset.length]).join("");
};
Web Crypto API의 getRandomValues
메소드를 이용하여 보안을 더 강화시켰다.
Subscribe to my newsletter
Read articles from 정하승 directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
