웹 개발을 하다 보면 클라이언트 사이드에서 암호화를 적용해야 할 때가 있습니다. 특히, 회원가입 페이지에서 비밀번호를 암호화하려고 bcrypt.js와 같은 라이브러리를 사용하는 경우, type="module" 환경에서 예상치 못한 문제가 발생할 수 있습니다. 이번 글에서는 이 문제와 해결 방법을 공유합니다.
문제 상황
기존 HTML에서 bcrypt.js를 <script> 태그로 로드하면 window.dcodeIO.bcrypt에 등록되기 때문에 암호화 함수들을 쉽게 사용할 수 있습니다.
<script src="https://cdnjs.cloudflare.com/ajax/libs/bcryptjs/2.4.3/bcrypt.min.js"></script>
<script>
const hashedPassword = bcrypt.hashSync("password123", 10);
console.log(hashedPassword);
</script>
하지만, type="module"이 선언된 자바스크립트 파일에서 bcrypt.min.js를 사용하는 경우, 다음과 같은 오류가 발생합니다.
Uncaught TypeError: Cannot read properties of undefined (reading 'dcodeIO')
원인
- type="module"로 선언된 파일은 전역 스코프를 공유하지 않습니다. 따라서 bcrypt.min.js가 등록한 window.dcodeIO.bcrypt 객체를 인식하지 못합니다.
비슷한 사례: Java로 웹 페이지 개발 시의 정적/동적 자바스크립트 문제
이 상황은 Java를 사용해 웹 페이지를 개발할 때 겪을 수 있는 정적/동적 자바스크립트의 적용 문제와 유사합니다.
예를 들어, Java에서 HTML 템플릿에 동적으로 데이터를 삽입하거나 서버에서 스크립트를 로드할 때 특정 자바스크립트 라이브러리가 정상적으로 동작하지 않는 경우가 있습니다. 이는 정적 파일이 서버와의 상호작용 없이 브라우저에서 직접 로드되기 때문입니다.
모듈(type="module")과 전역 스크립트(<script> 태그로 로드되는 라이브러리) 간의 환경 차이는 이전에 Java로 웹 페이지를 개발하며 경험했던 동적/정적 스크립트의 문제와 유사하다고 느꼈습니다. 하지만 실제로 이 문제를 해결하려니 막막했고 모듈 환경과 전역 스코프의 차이를 이해하고 이를 코드에 적용하는 과정이 쉽지 않았습니다.
해결 방법
문제를 해결하기 위해 전역 객체(window.dcodeIO.bcrypt)를 명시적으로 참조하는 방법을 사용했습니다.
1. HTML 구조
아래와 같이 bcrypt.min.js를 일반 스크립트로 먼저 로드하고, 이후 register.js를 모듈로 로드합니다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>회원가입</title>
<!-- NOTE : bcrypt.js를 전역 스크립트로 로드 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/bcryptjs/2.4.3/bcrypt.min.js"></script>
<link rel="stylesheet" href="/css/register.css">
</head>
<body>
<main>
<h2>회원가입</h2>
<form id="registerForm">
<label for="password">비밀번호</label>
<input type="password" id="password" name="password" required>
<button type="submit">가입하기</button>
</form>
</main>
<!-- NOTE : register.js를 모듈로 로드 -->
<script type="module" src="/js/user/register.js"></script>
</body>
</html>
2. register.js에서 bcrypt 객체 사용
모듈에서 전역 스크립트로 등록된 bcrypt 객체를 사용하려면 window.dcodeIO.bcrypt를 참조해야 합니다.
// NOTE : 전역 객체에서 bcrypt 가져오기
const bcrypt = window.dcodeIO.bcrypt;
document.addEventListener("DOMContentLoaded", () => {
const form = document.getElementById("registerForm");
const passwordInput = document.getElementById("password");
form.addEventListener("submit", (event) => {
event.preventDefault();
const password = passwordInput.value;
const hashedPassword = bcrypt.hashSync(password, 10); // NOTE : 비밀번호 해싱
console.log("Hashed Password:", hashedPassword);
// NOTE : 서버로 해싱된 비밀번호를 전송하는 로직 작성
// ...
});
});
window 객체란?
window 객체는 브라우저 환경에서 전역 객체로 JavaScript가 실행되는 브라우저 창 또는 탭을 나타냅니다. 브라우저 내에서 전역적으로 접근 가능한 모든 함수, 변수 및 API를 포함하는 가장 상위 계층의 객체입니다. 브라우저의 핵심적인 기능을 제공하며 웹 페이지와 브라우저 환경 간의 상호작용을 가능하게 합니다.
- window 객체는 브라우저 환경에서만 사용할 수 있습니다. Node.js와 같은 서버 환경에서는 존재하지 않습니다.
- 서버 환경에서는 global 객체가 대신 사용됩니다.
- JavaScript의 전역 함수나 API(alert, setTimeout, fetch 등)는 모두 window 객체의 메서드로 구현되어 있습니다.
알아야 할 점
- 전역 객체 사용 주의
- window에 등록된 객체는 전역 스코프에서만 접근 가능합니다. 모듈 환경에서 이를 참조하려면 명시적으로 window.dcodeIO.bcrypt를 사용해야 합니다.
- 보안 문제
- 클라이언트에서 암호화를 처리하면 비밀번호가 전송되기 전에 노출될 위험이 있습니다. 가능한 경우, 비밀번호 해싱은 서버에서 처리하는 것이 더 안전합니다.
- 대체 방안
- 브라우저 모듈 환경에 적합한 라이브러리(예: crypto-js)를 사용하는 것도 고려할 수 있습니다.
모듈 환경과 전역 스크립트 환경의 차이는 처음에는 막막했지만 문제를 해결하면서 많은 것을 배웠습니다. 이 사례를 통해 자바스크립트의 동작 방식을 더 깊이 이해하게 되었고 클라이언트와 서버 간의 협력을 고려한 코드 작성의 중요성을 다시 한번 느낄 수 있었습니다. 😂
'카카오 부트캠프 > 내용 정리' 카테고리의 다른 글
네트워크 기초 개념 정리하기 (0) | 2024.12.02 |
---|---|
커뮤니티 비밀번호 암호화 적용 및 bcrypt 학습 (0) | 2024.11.28 |
AWS EC2 중지 후 재시작, DB 연결이 갑자기 안 되는 이유 (0) | 2024.11.26 |
AWS EC2 외부 접속 문제 해결기: 결국 문제는 와이파이였다 (0) | 2024.11.25 |
node.js express에서 MySQL 트랜잭션 적용 (0) | 2024.11.21 |