(1) 이해
프론트엔드 개발자는 서버에 데이터를 전달할 때 백엔드 개발자가 제공한 API를 이용한다. 이때, API 자체에 데이터를 보호하는 기능이 없어 데이터가 평문 그대로 전달되는 문제점이 존재한다. 때문에 데이터를 안전하게 전달할 수 있는 방법이 필요한데 그 방법이 바로 데이터 암호화이다.
암호화(Encryption)는 데이터를 보호하기 위해 평문을 읽을 수 없도록 변환하는 과정을 의미한다. 때문에 데이터가 전송되거나 저장되는 중에 제 3자가 해당 정보를 열람하지 못하도록 방지하는 것을 목적으로 사용되고 있다.
![[그림 6-4] 암호화를 통해 평문에서 암호문으로 바뀌는 과정](https://www.notion.so/image/https%3A%2F%2Fprod-files-secure.s3.us-west-2.amazonaws.com%2F6d7fa230-23c2-4b9c-b287-fdeb076e90bd%2F3ddde64f-6932-45d5-9d9a-93e208fa180c%2Fimage.png?table=block&id=fff1bb7e-371a-817e-b07e-c3d6f4f67a6d&cache=v2)
데이터 암호화(Data Encryption)는 웹 브라우저에서 데이터를 전송하기 전에 암호화를 수행하는 작업이다. 따라서 HTTPS와 다르게 전송하는 중간에 암호화를 진행하는 것이 아닌, 프론트엔드 내에서 fetch나 axios 등으로 데이터를 전송하기 전 과정에서 암호화를 진행한다.
(2) 종류
웹 서비스 상황에 따라 사용되는 데이터 암호화 방식이 다르다. 암호화 방식에는 단방향 암호화와 양방향 암호화가 존재하는데, 각 방식마다 수행 주체와 처리 과정이 다른 특징을 가지고 있다.
1) 단방향 암호화
단방향 암호화는 단순히 암호화만 진행하는 특징을 가진 암호화 방식이다. 웹 사이트 내에서 인증 정보를 암호화할 수 있는 기본적인 방법으로 사용한다. 클리앙, 뽐뿌와 같은 간단한 정보를 얻을 수 있는 사이트에서 주로 사용되고 있다.
2) 양방향 암호화
양방향 암호화는 암호화도 진행하고, 복호화도 진행하는 특징을 가진 암호화 방식이다. 복호화(Decryption)는 암호화된 데이터를 원래의 형태로 되돌리는 과정이다. 양방향 암호화는 반드시 데이터가 안전하게 전달되어야 하는 사이트에서 중요한 정보를 암호화해야 할 때 사용한다. 은행, 비트코인, 주식과 같은 금융적인 서비스를 제공하는 곳에서 주로 사용되고 있다.
방식 | 수행 주체 | 복호화 여부 | 주요 사용처 |
단방향 암호화 | 프론트엔드 | 불가능 | 커뮤니티 사이트 |
양방향 암호화 | 프론트엔드, 백엔드 | 가능 | 금융 사이트 |
(3) 실습
단방향 암호화 방식을 사용하여 웹 브라우저 내에서 간단하게 사용자 정보를 암호화하는 사이트를 만들어보고 데이터 암호화를 수행했을 때의 결괏값을 확인해본다.
아래 코드는 아이디와 비밀번호를 입력하면 비밀번호를 단방향 암호화를 수행한 다음, fetch를 통해 로그인 요청을 하는 예시이다. 예시 내 주석을 살펴보면 “해시”과 “SHA-256”라는 내용이 등장한다. 해시(Hash)는 입력 데이터에 대해 고정 길이의 고유한 출력을 생성하는 암호화된 값으로, 데이터의 무결성을 검증하거나 비밀번호를 안전하게 저장하는 데 사용한다. SHA-256은 암호학적 해시 함수로서 단방향 암호화에서 많이 사용되는 함수이다.
<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>로그인 화면</title> </head> <body> <div class="login-container"> <h2>로그인</h2> <form onsubmit="hashPassword(event)"> <div class="input-group"> <label for="username">사용자 이름</label> <input type="text" id="username" name="username" required /> </div> <div class="input-group"> <label for="password">비밀번호</label> <input type="password" id="password" name="password" required /> </div> <button type="submit" class="login-button">로그인</button> </form> <div class="register-link"> <a href="#">회원가입</a> </div> </div> <script> async function hashPassword(event) { event.preventDefault(); // 기본 제출 방지 const url = "https://example.com"; const passwordInput = document.getElementById('password').value; const encoder = new TextEncoder(); const data = encoder.encode(passwordInput); // SHA-256 해시 생성 const hashBuffer = await crypto.subtle.digest('SHA-256', data); const hashArray = Array.from(new Uint8Array(hashBuffer)); const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); // 해시된 비밀번호를 서버에 제출 const formData = new FormData(); formData.append('username', document.getElementById('username').value); formData.append('password', hashHex); // 서버에 로그인 요청 (여기서는 가상의 URL 사용) fetch(`${url}/login`, { method: 'POST', body: formData, }).then(response => { if (response.ok) { alert('로그인 성공!'); } else { alert('로그인 실패!'); } }).catch(error => { console.error('로그인 중 오류 발생:', error); }); } </script> </body> </html>