안전하고 깔끔한 32자 SECRET 생성기 만들기 (openssl rand 대안)
웹 애플리케이션을 개발하다 보면 .env 환경 변수 파일에 세션 암호화, JWT 서명 또는 OAuth 설정 등을 위한 32자 이상의 SECRET 키 를 등록해야 하는 일이 자주 발생합니다.
이때 흔히 사용하는 명령어 중 하나가 바로 openssl rand 입니다.
openssl rand -base64 32
하지만 이 명령어를 사용하면 몇 가지 불편한 점이 생깁니다.
- 길이 문제: 32바이트의 난수 데이터를 Base64로 인코딩하므로 최종 출력의 길이가 32자가 아닌 44자 가 됩니다.
- 특수문자 문제: 마지막에 패딩 문자인
=가 계속 붙고, 중간에/나+같은 특수문자가 섞여 나옵니다. 이 문자들은 간혹 환경 변수 파싱 오류를 일으키거나 소스 코드 내에서 문자열 처리를 할 때 골칫거리가 되곤 합니다.
이러한 문제를 해결하기 위해 특수문자 없이 대소문자와 숫자를 모두 사용하여 보안성을 극대화한 32자 시크릿 생성기를 직접 구현해 봅니다.
1. 16진수(Hex) 방식의 한계
가장 쉬운 대안은 16진수(Hex) 인코딩을 사용하는 것입니다. 16바이트의 난수를 16진수로 출력하면 정확히 32자가 됩니다.
openssl rand -hex 16
# Example output: a4f8b2c6d7e0f1a2b3c4d5e6f7a8b9c0
이 방식은 특수문자 없이 0-9와 소문자 a-f로만 구성되어 안전하고 편리합니다.
하지만 사용 가능한 문자의 종류가 16개 로 제한되다 보니, 대소문자와 숫자를 모두 섞어 쓸 때보다 조합의 수(엔트로피)가 떨어지는 단점이 있습니다.
- Hex (16진수) 32자: 16³² = 2¹²⁸가지 조합 (128비트 보안성)
- 알파벳 대소문자 + 숫자 (62진수) 32자: 62³² ≈ 2¹⁹⁰가지 조합 (190비트 보안성)
더 높은 보안 강도를 유지하면서 특수문자만 제거한 깔끔한 시크릿을 얻기 위해서는 대소문자와 숫자가 섞인 62개의 문자 풀(Pool) 을 활용해야 합니다.
2. 62개 문자 조합으로 시크릿 생성하기
macOS 및 리눅스에 기본 탑재된 암호학적 난수 생성 장치 /dev/urandom과 문자 필터링 도구 tr을 조합하면 이를 쉽게 구현할 수 있습니다.
LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 32
# Example output: 8dKfG3sR9tY1wPqL2mNbVxZpQoWnEjHi
LC_ALL=C:tr명령어가 바이트 단위로 오차 없이 원활하게 작동하도록 로캘(Locale)을 표준 C로 고정합니다.tr -dc 'A-Za-z0-9': 입력 흐름에서 지정한 문자군(A-Z,a-z,0-9)을 제외한 모든 문자를 삭제(delete)하고 보존(complement)합니다.head -c 32: 최종적으로 나온 문자열에서 정확히 32바이트(자)만 잘라냅니다.
3. 쉘 스크립트로 자동화하기 (gensecret.sh)
매번 이 긴 명령어를 입력하거나 찾아서 복사하는 대신, 터미널에서 옵션에 따라 편리하게 사용할 수 있는 유틸리티 스크립트를 작성해 봅니다.
요구사항은 다음과 같습니다:
- 기본 동작: 생성한 시크릿 텍스트를 화면(stdout)에 바로 출력합니다.
- 길이 변경 가능: 인자로 숫자를 입력하면 해당 길이만큼 시크릿을 생성합니다. (기본값: 32)
- 클립보드 연동:
-c옵션을 붙여 실행하면 터미널 화면에는 값을 노출하지 않고, 조용히 클립보드에 복사합니다.
작성한 gensecret.sh 스크립트 코드입니다.
#!/usr/bin/env bash
# Exit immediately if a command exits with a non-zero status
set -e
# Default settings
COPY_TO_CLIPBOARD=false
LENGTH=32
# Parse arguments flexibly (order does not matter)
for arg in "$@"; do
if [[ "$arg" == "-c" ]]; then
COPY_TO_CLIPBOARD=true
elif [[ "$arg" =~ ^[0-9]+$ ]]; then
LENGTH="$arg"
fi
done
# Generate a cryptographically secure random string using A-Z, a-z, and 0-9
SECRET=$(LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | head -c "$LENGTH")
# Handle output based on options
if [ "$COPY_TO_CLIPBOARD" = true ]; then
if command -v pbcopy >/dev/null 2>&1; then
echo -n "$SECRET" | pbcopy
else
# Fallback to stdout with a warning if pbcopy is not available (e.g. Linux)
echo "Warning: pbcopy not found. Printing to stdout instead." >&2
echo "$SECRET"
fi
else
# Default behavior: print the secret directly to stdout
echo "$SECRET"
fi
4. 사용 및 활용 팁
스크립트 작성이 완료되었다면 실행 권한을 부여합니다.
chmod +x gensecret.sh
다양한 실행 명령어 예시
# 1. Print 32 characters to stdout (default)
./gensecret.sh
# Output: u8WqLmYzXwRvUtSrQpOnMlKjIhGfEdCb
# 2. Print 16 characters to stdout
./gensecret.sh 16
# Output: aB3eR2yL1nV8tG5j
# 3. Copy directly to clipboard without printing to stdout (-c option)
./gensecret.sh -c
# (No stdout; ready to paste with Cmd+V into .env files)
# 4. Combined options (generate 64 characters and copy to clipboard)
./gensecret.sh -c 64
./gensecret.sh 64 -c
전역 명령어로 등록하기
현재 폴더가 아닌 곳에서도 언제든지 gensecret 명령어로 사용하고 싶다면, 아래 두 가지 방법 중 하나를 선택할 수 있습니다.
방법 A: /usr/local/bin에 복사 (가장 권장)
sudo cp gensecret.sh /usr/local/bin/gensecret
이제 터미널을 열고 어디서나 gensecret -c 48 같은 방식으로 바로 실행할 수 있습니다.
방법 B: .zshrc에 Alias 등록
alias gensecret="~/bin/gensecret.sh"
자신의 환경에 맞는 편리한 경로에 파일을 보관한 뒤 alias를 설정해 두면 손쉽게 호출 가능합니다.
이제 불안정하고 입력이 번거로운 특수문자가 섞인 암호 대신, 강력하고 깔끔한 무작위 문자열 생성 유틸리티를 활용해 소중한 시간을 절약해 보세요!