2차 인증 설정을 위한 QR 코드

오늘은 2차 인증 설정 과정에서 OTP 앱으로 스캔할 수 있도록 코드 대신에 제공하는 QR 코드에 대해서 알아보려고 한다.

RFC 6238

Google Authenticator, Microsoft Authenticator 그리고 Authy와 같은 OTP 인증 앱들은 RFC6238로 정의된 TOTP 표준에 따라 구현되어있고 QR 코드에 포함되는 텍스트는 Key Uri Format로 구성되어야 읽을 수 있다.

# otpauth://TYPE/LABEL?PARAMETERS
otpauth://totp/Mambo:kdevkr@email.com?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=Mambo&algorithm=SHA1&digits=6&period=30

TOTP QR 코드 이미지 만들기

QR 코드 이미지를 만들기 위해서 java-totp 라이브러리를 사용하려고 한다. 이 라이브러리는 비밀키 발급부터 QR 코드를 HTML에서 사용하기 위한 Data URI로 변환하는 Utils.getDataUriForImage 함수도 제공해주고 있다.

dependencies {
    implementation 'dev.samstevens.totp:totp:1.7.1'
    implementation 'com.google.zxing:javase:3.5.3'
}
SecretGenerator secretGenerator = new DefaultSecretGenerator();
String secret = secretGenerator.generate();

QrData qrData = new QrData.Builder()
        .label("kdevkr@gmail.com")
        .secret(secret)
        .issuer("Mambo")
        .algorithm(HashingAlgorithm.SHA1)
        .digits(6)
        .period(30)
        .build();

ZxingPngQrGenerator qrGenerator = new ZxingPngQrGenerator();
qrGenerator.setImageSize(250);
byte[] qrImageBytes = qrGenerator.generate(qrData);
String qrDataUri = Utils.getDataUriForImage(qrImageBytes, qrGenerator.getImageMimeType());
System.out.println(qrDataUri);

Zxing Decoder Online을 사용하여 올바르게 이미지가 만들어졌는지 확인해볼 수 있습니다.

보안 이슈

2차 인증 설정을 위해서 제공하는 QR 코드에는 암호화되지 않은 상태의 보안키가 포함되어있다. 서드 파티인 OTP 앱은 QR 코드를 스캔하여 포함된 텍스트에서 정보를 추출해야하므로 보안키를 암호화 할수는 없다. 아래와 같이 two-factor-auth처럼 QR 코드 이미지 생성을 위해서 외부 주소에 의존하는 것은 좋지 않다.

public static String qrImageUrl(String keyId, String secret, int numDigits, int imageDimension) {
    StringBuilder sb = new StringBuilder(128);
    sb.append("https://chart.googleapis.com/chart?chs=" + imageDimension + "x" + imageDimension + "&cht=qr&chl="
            + imageDimension + "x" + imageDimension + "&chld=M|0&cht=qr&chl=");
    addOtpAuthPart(keyId, secret, sb, numDigits);
    return sb.toString();
}

구글에서 QR 이미지 생성을 제공했던 주소는 제거되었고 대체할 수 있는 주소가 있지만 외부 주소에 보안키를 전달하는 것은 권장하지 않습니다.