# 비밀번호·패스프레이즈 — 강한 난수를, 브라우저 안에서

여기서, 본인 브라우저가 만듭니다. 어디로도 보내지 않고, 저장하지 않고, 기록도 남기지 않습니다.

> 강한 무작위 비밀번호를 만들거나, 페이지에 함께 실린 7,776단어 목록에서 다이스웨어 패스프레이즈를 뽑습니다. 브라우저 자체의 암호용 난수로 뽑고, 어디로도 보내지 않으며 저장하지 않습니다. 무료, 가입 없음.

이 페이지는 브라우저 안에서만 동작하는 대화형 도구입니다(https://abox.tools/ko/비밀번호-생성기/). 도구에 넘긴 어떤 것도 업로드되지 않습니다. 아래는 이 페이지가 도구에 대해 글로 설명하는 내용 전부입니다. 도구를 쓰려면 이 주소를 여세요.

## 비밀번호와 패스프레이즈는 **절대 업로드되지 않습니다**. 서버가 아예 없으니까요.

글자 하나하나는 브라우저 자체의 암호용 난수인 `crypto.getRandomValues`에서 나오고, 단어 하나하나는 이 폴더에 들어 있는 `src/wordlist.js`에서 나옵니다. `src/` 어디에도 `fetch`도 `XMLHttpRequest`도 `sendBeacon`도 없으니, 여기서 만든 비밀번호가 저희에게든 누구에게든 닿을 경로 자체가 없습니다. 저장도 하지 않기 때문에, 이 페이지를 새로 고치면 지금까지 보여 드린 비밀번호는 전부 사라집니다.

- ✗ 업로드 없음
- ✗ 계정 없음
- ✗ 저장 안 함
- ✓ 오프라인 작동
- ✓ 소스 공개

## 어떤 사이트에도 보이지 않고 강한 비밀번호를 만드는 방법

1. **비밀번호로 할지 패스프레이즈로 할지 고릅니다.** 비밀번호는 무작위 글자의 나열입니다. 보관하기 짧고, 손으로 치기는 성가시고, 비밀번호 관리자가 대신 채워 주는 수백 개의 계정에는 이쪽이 정답입니다. 패스프레이즈는 목록에서 무작위로 뽑은 단어의 나열입니다. 길지만 외울 수 있고 소리 내어 말할 수 있어서, 머리에서 꺼내 직접 쳐야 하는 몇 안 되는 비밀에 맞습니다. 비밀번호 관리자 자체의 비밀번호, 노트북 비밀번호, 휴대폰 복구 코드 같은 것들입니다.
2. **길이나 단어 수를 정합니다.** 중요한 설정은 이것이고 나머지는 대체로 아닙니다. 지킬 값어치가 있는 것이라면 20자, 또는 여섯 단어가 합리적인 하한입니다. 나머지 전부를 재설정할 수 있는 계정이라면 거기서 더 올리세요. 아래 수치는 손잡이를 끄는 동안 함께 움직이니, 한 글자를 더할 때 무엇이 늘어나는지 바로 보입니다.
3. **가입 양식이 우길 규칙을 켭니다.** ‘종류마다 최소 하나’, 끝에 숫자 하나, 어느 사이트나 받아 주는 짧은 목록의 기호 하나. 어느 것도 더 강하게 만들지 않고, 첫 번째는 오히려 아주 조금 약하게 만듭니다. 그만큼은 페이지가 이미 빼 두었습니다. 다만 여섯 번 다시 만들지 않고 가입 양식을 통과하려면 이것들이 필요합니다.
4. **색이 아니라 숫자를 읽습니다.** 비트 수는 그 문자열을 만들어 낸 설정에서 셉니다. 글자 집합의 크기와 뽑은 횟수, 그것뿐입니다. 이것은 진짜 측정이고, 가입 페이지의 막대와는 다릅니다. 그쪽은 눈앞의 글자에 점수를 매기는 일밖에 못 하고, 그 글자를 사람이 골랐는지 생성기가 골랐는지 알 방법이 없습니다.
5. **떠나기 전에 복사해서 어딘가에 둡니다.** 여기에는 기록이 없고 다시 달라고 할 방법도 없습니다. 새로 고치면 사라집니다. 비밀번호 관리자에 먼저 붙여 넣고 가입 양식에는 그다음에 붙여 넣으세요. 기억해야 하는 쪽이 먼저 가지고 있으면 중간에 무슨 일이 생겨도 잃지 않습니다.
6. **여러 개가 필요하면 한 번에 만듭니다.** 맨 아래 손잡이로 한 번에 최대 100개까지 만들고 텍스트 파일로 저장할 수 있습니다. 내용은 이미 화면에 있는 것을 이 페이지가 그대로 적어 낸 것입니다. 계정을 한꺼번에 만들거나 초기 접속 정보를 나눠 줄 때 쓸모가 있는데, 더 나은 곳으로 옮기고 나면 파일은 지우시는 게 좋습니다. 디스크 위의 비밀번호 가득한 파일은 여전히 비밀번호 가득한 파일입니다.

## 상자 속 다른 도구

- [JSON 포매터](https://abox.tools/ko/json-포맷터/): JSON, XML, HTML, CSS, YAML을 정렬하거나 변환합니다. 남의 서버에 붙여 넣는 것은 없습니다.
- [YAML → JSON 변환기](https://abox.tools/ko/yaml-json-변환/): 양쪽 방향 모두, 그리고 각 방향이 무엇을 치르는지도 말해 줍니다. 그 어느 것도 남의 서버에 붙여 넣지 않습니다.
- [XML 포맷터](https://abox.tools/ko/xml-포맷터/): 읽으라고 펼친 XML, 보내라고 납작하게 누른 XML, 그리고 양쪽으로 오가는 JSON 변환. 그 어느 것도 남의 서버에 붙여 넣지 않습니다.
- [텍스트 비교](https://abox.tools/ko/텍스트-비교/): 두 텍스트를 넣으면 모든 차이가 줄 단위, 단어 단위로 표시됩니다. 남의 서버에 붙여 넣는 것은 없습니다.

## 자주 묻는 질문

### 비밀번호가 어딘가로 전송되거나 저장되나요?

둘 다 아닙니다. 본인 브라우저, 본인 기기 위에서 만들어지고, 이 도구에는 네트워크 기능 자체가 없습니다. 무엇도 받아 오지 않고 무엇도 보내지 않습니다. 저장소에도 아무것도 쓰지 않습니다. localStorage도 쿠키도 기록도 없습니다. 페이지를 새로 고치면 보여 드렸던 비밀번호는 화면에서도 페이지의 메모리에서도 사라집니다. 페이지의 `Content-Security-Policy`에는 연결해도 되는 주소가 전부 적혀 있고 그중 저희 것은 없으니, 무언가가 보내려 한다 해도 받을 곳이 없습니다.

### 난수는 어디에서 오나요?

`crypto.getRandomValues`에서 옵니다. 브라우저가 암호 용도로 제공하는 난수이고, 본인 운영체제의 엔트로피 풀이 씨앗을 주고 계속 다시 줍니다. 브라우저가 TLS 키 재료를 뽑는 것과 같은 출처입니다. 이 도구에서는 `Math.random`을 어디에서도 쓰지 않는데, 이 구분은 트집이 아닙니다. `Math.random`은 빠른 산술 난수이고 내부 상태 전체가 연속된 출력 몇 개만으로 복원됩니다. 그 위에 만든 비밀번호 생성기는 무작위처럼 보일 뿐, 출력 하나를 본 사람이면 전부 열거할 수 있는 비밀번호를 내놓습니다.

### 브라우저에서 만든 비밀번호가 설치형 프로그램에서 만든 것만큼 좋은가요?

난수에 관해서는 그렇습니다. 둘 다 운영체제의 같은 출처에 다른 문으로 닿았을 뿐입니다. 다른 것은 같은 방에 무엇이 더 있느냐입니다. 브라우저 탭은 확장 프로그램과 나란히 돌아가고, 페이지를 읽을 권한이 있는 확장 프로그램은 이 페이지도 읽습니다. 이 페이지를 포함해 웹에 있는 모든 생성기에 해당하는 말이고, 비밀번호 관리자가 있다면 거기 내장된 생성기를 쓰라고 권하는 솔직한 이유이기도 합니다. 계산은 같고, 옆에 서 있는 것이 적을 뿐입니다. 이 페이지는 그것이 손에 없을 때를 위한 것입니다.

### 비밀번호와 패스프레이즈 중 무엇을 써야 하나요?

관리자가 대신 쳐 주는 모든 것에는 비밀번호를 쓰세요. 어차피 볼 일이 없고 길이는 공짜입니다. 머리에서 꺼내 직접 치거나 소리 내어 불러 줘야 하는 몇 안 되는 것에는 패스프레이즈를 쓰세요. 관리자의 마스터 비밀번호, 디스크 암호화 키, 멀리서 설정하는 기기 같은 것들입니다. 긴 목록에서 여섯 단어면 77비트로, 열두 자짜리 무작위 비밀번호보다 강하고, 새벽 네 시에 틀리지 않고 입력하기는 비교가 안 되게 쉽습니다.

### 비밀번호는 몇 자여야 하나요?

전체 글자 집합에서 20자면 약 130비트로, 길이를 걱정할 단계는 한참 지났습니다. 16자도 충분합니다. 잃으면 곤란한 것의 하한이 열두 자이고, 이건 하한이지 목표가 아닙니다. 그 아래로 내려가면 사이트가 제대로 저장해 두었기를 거는 셈인데, 지난 20년의 유출 통지가 그 내기를 말립니다. 길이는 이 페이지의 다른 어떤 설정도 이깁니다. 한 글자를 더하는 쪽이 어떤 글자가 들어가야 한다는 어떤 규칙보다 낫습니다.

### 패스프레이즈는 몇 단어여야 하나요?

긴 목록에서 여섯 단어, 다른 비밀번호를 지키는 것이라면 일곱 단어입니다. 유명한 네 단어 그림은 2011년 것이고 51비트라, 오늘날에는 제대로 된 오프라인 공격의 사정거리 안입니다. 다섯 단어는 64, 여섯 단어는 77입니다. 평범한 계정 하나에 공격자가 쓸 비용을 넘어섭니다. 긴 목록에서 한 단어를 더할 때마다 12.9비트가 늘고, 늘려 주는 것은 단어뿐입니다. 하이픈도 대문자도 아닙니다.

### ‘비트’가 무엇이고, 이 페이지는 왜 그걸 세나요?

1비트는 두 배가 된다는 뜻입니다. 60비트라면 이 페이지가 내놓을 수 있었던, 확률이 똑같은 결과가 2^60가지였다는 말이고, 작동 방식을 정확히 아는 상대도 그만큼은 시도해야 합니다. 이것은 문자열이 아니라 *과정*의 성질입니다. 이 페이지는 고른 당사자이고 몇 번 골랐는지 알기 때문에 정확히 말할 수 있습니다. 가입 양식의 색깔 막대와 다른 점이 바로 여기입니다. 그쪽은 글자를 읽고 짐작할 뿐입니다. 그 막대에서 `correct horse battery staple`은 점수가 나쁘지만 실제로는 44비트이고, `P@ssw0rd!`는 점수가 좋지만 실제로는 거의 아무 값어치도 없습니다.

### ‘기호를 반드시 넣으라’는 규칙이 왜 비밀번호를 약하게 만드나요?

규칙은 가능성을 덜어 내는 일밖에 못 하기 때문입니다. 종류마다 최소 하나를 요구하면, 어쩌다 하나도 들어가지 않은 비밀번호가 전부 빠집니다. 가능한 비밀번호의 집합이 작아지면 뒤져야 할 범위도 작아집니다. 효과는 작아서 보통 길이에서 0.5비트쯤이지만 실재하고, 이 페이지는 자기에게 유리한 숫자를 대는 대신 그만큼을 빼 둡니다. 게다가 그 규칙이 실제로 허용하는 비밀번호의 수를 세어서 정확하게 구합니다.

### 이건 어떤 단어 목록이고, 공격자가 내려받을 수 있다는 게 문제가 되지는 않나요?

Electronic Frontier Foundation의 다이스웨어 목록을 그대로 실었습니다. 긴 쪽이 7,776단어, 짧은 쪽이 1,296단어입니다. 바로 이 용도로 만들어진 목록이라, 불쾌한 단어가 없고, 동음이의가 없고, 붙이면 다른 단어가 되어 버리는 짝이 없으며, 짧은 목록에서는 어떤 단어도 다른 단어의 앞부분이 아닙니다. 그리고 아니요, 목록이 공개되어 있다는 것은 문제가 되지 않습니다. 여기 적힌 강도는 공격자가 목록을 가지고 있고, 이 페이지의 소스를 읽고 있으며, 사용하신 설정을 전부 안다는 전제로 계산한 것입니다. 그가 모르는 것은 매번 7,776개 중 어느 것이 나왔는지뿐입니다. 바로 그 전제가 이 숫자를 믿을 만하게 만듭니다.

### 패스프레이즈는 그냥 사전 공격을 기다리는 것 아닌가요?

이런 식으로 단어를 고르는 한 아닙니다. 사전 공격은 *사람이* 지은 문구에 통합니다. 사람은 서로 어울리는 단어를, 말이 되는 순서로, 매일 쓰는 몇천 개 중에서 고르기 때문입니다. 이 페이지는 고정된 목록에서 단어마다 독립적으로, 고르게 뽑고, 결과가 읽기 좋은지는 전혀 고려하지 않습니다. 그래서 보통은 읽기 좋지 않습니다. 목록도 단어 수도 아는 공격자 앞에 남는 것은 여전히 7,776의 단어 수 제곱입니다.

### 페이지를 떠난 뒤에 비밀번호를 되찾을 수 있나요?

없고, 일부러 그렇게 만들었습니다. 어디에도 적어 두지 않으니 되찾을 것이 없습니다. 기록 창도, ‘최근에 만든 것’ 목록도, 캐시도 없습니다. 지난 화요일의 비밀번호를 보여 줄 수 있는 생성기란 그것을 저장해 둔 생성기이고, 본인이 꺼낼 수 있는 곳에 저장되어 있다는 것은 다른 것도 꺼낼 수 있는 곳에 저장되어 있다는 뜻입니다. 떠나시기 전에 비밀번호 관리자로 복사하세요.

### 클립보드에 복사해도 안전한가요?

평범한 수준의 위험이고, 걱정하기보다 알아 두는 편이 낫습니다. 클립보드는 같은 사용자로 실행되는 모든 것과 공유되고, 보통 다음 복사 때까지 남아 있으며, 설정에 따라 기기 사이에서 동기화되기도 합니다. 그러니 갈 곳에 바로 붙여 넣고 그다음에 다른 것을 복사하는 게 좋습니다. 대신 더 약한 비밀번호를 손으로 칠 이유는 되지 않습니다. 이 페이지는 클립보드를 읽지 못합니다. 쓰는 것만 할 수 있고, 그것도 버튼을 누르셨을 때뿐입니다.

### 같은 것을 여러 곳에 써도 되나요?

안 됩니다. 이 페이지의 다른 모든 조언보다 위에 있는 유일한 조언입니다. 털리는 계정은 거의 다 어딘가 다른 곳에서 먼저 맞았던 비밀번호로 털립니다. 어떤 사이트가 뚫리고, 목록이 공개되고, 같은 주소와 같은 비밀번호가 사방에서 시도됩니다. 사이트마다 다른 비밀번호를 쓰면 유출이 전부가 아니라 계정 하나로 끝납니다. 비밀번호 관리자를 쓰는 이유가 여기에 있지, 그 안에 든 개별 비밀번호의 강도에 있지 않습니다.

### 무료인가요? 계정이 필요한가요?

무료이고, 계정도 로그인도 체험 기간도 없으며, 몇 개를 만들든 제한이 없습니다. 사이트는 광고로 유지되지만, 광고에는 이 페이지가 만드는 것에 대해 아무것도 넘어가지 않습니다. 길이도 강도도 넘어가지 않습니다.

### 오프라인에서도 되나요?

됩니다. 페이지를 한 번 불러온 뒤 인터넷을 끊어도 계속 비밀번호를 만듭니다. 난수는 본인 기기에서 나오고 단어 목록은 이미 페이지 안에 있습니다. 아무것도 받아 오지 않고 아무것도 보내지 않는다는 가장 간단한 증명이기도 합니다. 숫자를 서버에서 받아 오는 생성기라면 선을 뽑는 순간 멈춥니다.

## 이 약속을 직접 확인하는 방법

- **비밀번호는 이 글을 읽고 계신 바로 그 자리에서 만들어집니다.** 이 페이지 안에서, 이 페이지가, 본인 운영체제가 브라우저에 건네주는 난수로 뽑습니다. 만들기 위해 무언가를 받아 오지도 않고, 다 만든 뒤에 무언가를 알리지도 않습니다. `Content-Security-Policy`에는 이 페이지가 연결해도 되는 주소가 전부 적혀 있고 그중 저희 것은 하나도 없습니다. 생성된 비밀번호가 모일 곳이 여기에는 없고, 있다 해도 그리로 보낼 코드가 없습니다.
- **여기에는 무언가를 받아 오는 코드가 없습니다.** `src/` 어디에도 `fetch`도 `XMLHttpRequest`도 `sendBeacon`도 없습니다. 단어 목록도 내려받는 것이 아니라 `src/wordlist.js`라는 파일이고, 페이지의 나머지와 함께 이 출처에서 전송되며, 열어서 읽어 보실 수 있습니다.
- **난수는 브라우저의 것이고, 게다가 올바른 종류입니다.** `crypto.getRandomValues`는 브라우저가 키와 토큰을 위해 제공하는 난수로, 운영체제가 씨앗을 주고 계속 다시 줍니다. `Math.random`은 이 폴더 어디에도 없고, 있었다면 그것은 진짜 결함입니다. 내부 상태가 몇 개의 출력만으로 복원되기 때문에, 출력 하나를 본 사람은 그것이 앞으로 만들 비밀번호를 전부 계산할 수 있습니다.
- **아무것도 저장하지 않으니 지울 기록도 없습니다.** localStorage도 sessionStorage도 쿠키도 URL 매개변수도 없고, 브라우저가 기억해 주겠다고 나설 `<input>`도 없습니다. 화면에 있는 것은 이 페이지 메모리의 배열 하나 안에만 있고, 탭을 닫으면 그것으로 정리는 끝입니다. 여기서 만들어진 것의 사본은 가져가신 것뿐입니다.
- **구글이 불러오는 것과, 구글에게 넘어가지 않는 것.** 광고와 측정 스크립트는 구글 것이고 후원 버튼은 Buy Me a Coffee 것입니다. 그 어느 쪽에도 이 페이지가 만든 것의 글자 하나 넘어가지 않습니다. 길이도, 강도도, 어떤 설정으로 나왔는지도 넘어가지 않습니다. 글자나 단어를 뽑는 코드는 전부 이 출처에서 전송되고 저장소에 그대로 있습니다.
- **오프라인에서도 작동합니다.** 네트워크를 끊어도 이 도구는 그대로입니다. 애초에 안에 네트워크 단계가 없었기 때문입니다. 이것이 가장 간단한 증명입니다. 난수를 서버에서 받아 오는 생성기라면 선을 뽑는 순간 멈춥니다.

**직접 확인해 보세요.** 위에 적은 어느 것도 그냥 믿으실 필요는 없습니다. 이 페이지는 저장소 안의 템플릿과 설정을 빌드 스크립트가 찍어 낸 결과이고, 그 스크립트는 누구나 읽고 직접 돌려 볼 수 있습니다. 결과물은 `dist` 브랜치에 그대로 올라가 있고요. 그래서 실제로 제공되는 파일과 소스를 빌드한 결과를 나란히 놓고 비교해 보실 수 있습니다: https://github.com/A-Box-of-Tools/website

먼저 읽어 볼 파일을 꼽자면, Content-Security-Policy는 `config/site.toml`, 이 페이지와 여기서 만들어지는 모든 비밀번호 사이에 놓인 마흔 줄이 `src/random.js`입니다. 입력은 하나뿐이고 그것이 브라우저 자체의 난수입니다. 설정이 문자열이 되기까지는 `src/generate.js`, 그 숫자 뒤의 계산은 `src/strength.js`이고, 이쪽은 짐작이 아니라 세는 쪽입니다.
