안녕하세요? 2차 인증(Two-Factor Authentication)을 위해 OTP에 대해 공부하던 중 알게된 사실들에 대해 정리해보려고 합니다.

OTP(One-Time Password, 일회용 비밀번호)의 동작 원리는 사용자가 인증을 시도할 때마다 한 번만 사용할 수 있는 비밀번호를 생성하고 검증하는 것을 의미 합니다. OTP는 보안성을 높이기 위해 고안된 방식으로, 주요하게 두 가지 방식이 있습니다: 시간 기반 OTP(Time-based OTP, TOTP)와 카운터 기반 OTP(HMAC-based OTP, HOTP). 여기서 TOTP가 더 일반적으로 사용됩니다. 오늘 알아볼 내용도 TOTP에 대해 알아봅니다 :)

제가 알아본 방법은 commons-codec 방식과 warrenstrange/googleauth 라이브러리 방식이 있는데요. 이 둘중에 무엇을 활용할지는 프로젝트 요구사항과 선호하는 개발 스타일에 따라 달라질 수 있습니다. 두 가지 접근 방식의 장단점은 아래와 같습니다.

 

 

Commons-Codec 방식

장점:

  1. 경량성: commons-codec는 일반적인 인코딩/디코딩 작업을 위한 라이브러리로, OTP 생성에 필요한 HMAC-SHA 알고리즘을 구현하는 데 사용할 수 있습니다. 이 라이브러리는 상대적으로 가볍습니다.
  2. 유연성: 라이브러리를 사용하여 직접 OTP 알고리즘을 구현하면, 특정 요구사항에 맞게 커스터마이징할 수 있습니다. HMAC-SHA1, SHA256, SHA512 등의 다양한 해시 알고리즘을 사용할 수 있습니다.
  3. 통제: OTP 생성 로직을 직접 구현하기 때문에 세부 사항을 커스텀 할 수 있습니다.

단점:

  1. 개발 복잡성: OTP 알고리즘을 직접 구현하려면 추가적인 코딩 작업이 필요하며, 표준 준수 및 보안성을 확보하기 위해 신중한 구현이 필요합니다.
  2. 버그 발생 가능성: 직접 구현할 경우 실수로 인한 버그가 발생할 가능성이 있습니다.

 

Warrenstrange/Googleauth

장점:

  1. 간편함: warrenstrange/googleauth는 구글 OTP 알고리즘(TOTP) 구현을 위한 라이브러리로, 설정과 사용이 간편합니다. 복잡한 구현 없이 쉽게 OTP 기능을 추가할 수 있습니다.
  2. 신뢰성: 이미 검증된 라이브러리를 사용함으로써 보안성과 신뢰성을 확보할 수 있습니다. 널리 사용되는 라이브러리이기 때문에 커뮤니티와 문서를 쉽게 찾을 수 있다는 장점이 있어요.
  3. 통합: 구글 OTP 표준을 준수하므로, 구글 인증 앱 등과 쉽게 통합할 수 있습니다.

단점:

  1. 제한된 유연성: 라이브러리의 기능과 설정에 제약이 따릅니다. 즉 특정 요구사항에 맞게 커스터마이징하기 어려울 수 있습니다.
  2. 외부 의존성: 외부 라이브러리에 의존하게 되므로, 라이브러리 업데이트 및 유지보수에 대한 추가적인 고려가 필요합니다.

 

결론

  • 단순하고 빠른 구현이 필요한 경우: warrenstrange/googleauth 라이브러리
  • 커스터마이징과 세부 제어가 필요한 경우: commons-codec

 

TOTP (Time-based OTP)의 동작원리

TOTP는 시간에 기반하여 OTP를 생성합니다. 사용자는 일정한 시간 간격마다 변경되는 비밀번호를 사용하여 인증을 받아야 하는 방식이죠. 일반적으로 우리는 사용자 측면에서만 TOTP를 이용해왔습니다. 우선 1차 로그인을 하면, 구글 OTP와 같은 앱을 켜서 정해진 시간마다 변동돼는 6자리 숫자를 모바일로 확인해서 웹화면에 입력하죠. 그렇다면 이러한 일련의 과정은 전체적으로 어떤 과정이 일어나기에 가능한걸까요? 이번에는 TOTP의 그 동작 원리에 대해 확인해 봅시다.

  1. 공유 비밀 키(Secret Key): 서버와 클라이언트(사용자)는 미리 공유된 비밀 키를 가지고 있어야 합니다.
  2. 시간 동기화: 서버와 클라이언트는 시간을 동기화해야 합니다. 일반적으로 Unix 타임스탬프(1970년 1월 1일 00:00:00 UTC부터의 초)를 사용합니다.
  3. 시간 슬롯 계산: 현재 시간을 일정한 간격(예: 30초)으로 나누어 슬롯을 계산합니다. 이 간격을 시간 틱(Time Tick)이라고 합니다.
  4. HMAC 계산: 현재 시간 슬롯과 비밀 키를 사용하여 HMAC-SHA1 알고리즘을 적용합니다. 여기서 HMAC은 키를 사용한 해시 기반 메시지 인증 코드입니다.
  5. OTP 생성: HMAC의 결과로부터 특정 길이(예: 6자리)의 숫자를 추출하여 OTP를 생성합니다. 일반적으로 OTP는 HMAC 결과의 일부를 사용하여 6자리 또는 8자리 숫자로 변환됩니다.
  6. 검증: 사용자가 입력한 OTP를 서버에서 동일한 방식으로 생성된 OTP와 비교하여 검증합니다. 시간 슬롯이 짧기 때문에 OTP는 매우 짧은 시간 동안만 유효합니다.

 

Warrenstrange/Googleauth를 이용한 키 제너레이트 및 검증

 

pom.xml

<dependency>
    <groupId>com.warrenstrange</groupId>
    <artifactId>googleauth</artifactId>
    <version>1.5.0</version>
</dependency>

 

import com.warrenstrange.googleauth.GoogleAuthenticator;
import com.warrenstrange.googleauth.GoogleAuthenticatorKey;
import com.warrenstrange.googleauth.GoogleAuthenticatorQRGenerator;

public class GoogleAuthExample {

    public static void main(String[] args) {
        // Create an instance of GoogleAuthenticator
        GoogleAuthenticator gAuth = new GoogleAuthenticator();

        // Generate a new key
        GoogleAuthenticatorKey key = gAuth.createCredentials();
        String secret = key.getKey();
        System.out.println("Secret key: " + secret);

        // Generate a QR code URL to be scanned by Google Authenticator app
        String userName = "user@example.com";
        String issuer = "ExampleIssuer";
        String qrCodeUrl = GoogleAuthenticatorQRGenerator.getOtpAuthURL(issuer, userName, key);
        System.out.println("QR Code URL: " + qrCodeUrl);

        // Simulate the OTP that the user would provide from their Google Authenticator app
        int otp = gAuth.getTotpPassword(secret);
        System.out.println("Generated OTP: " + otp);

        // Verify the provided OTP
        boolean isCodeValid = gAuth.authorize(secret, otp);
        System.out.println("Is the OTP valid? " + isCodeValid);
    }
}

getOtpAuthURL로부터 알아낸 URL을 실제로 접속하면 QR코드로서 확인해 볼 수 있습니다. 그런데 이렇게 하면 api.qrserver.com에 귀속된 URL을 알려주게 되는데, api.qrserver.com은 구글 서버가 아닙니다. api.qrserver.com은 goqr.me라는 웹사이트에서 제공하는 QR 코드 생성 서비스의 API 라고하네요. goqr.me는 QR 코드를 생성하고 관리하는 데 특화된 서비스로, 다양한 형태의 QR 코드를 쉽게 만들 수 있도록 도와줍니다. 하지만, 이런 의존적인 방식이 마음에 안들경우 직접 QR을 생성할 필요성이 있는데, 이 부분에 대해서는 ZXing 라이브러리를 사용하여 자체적으로 QR을 생성하는 방식으로 해결하였습니다!

 

QR 코드 자체생성하기

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.google.zxing</groupId>
        <artifactId>core</artifactId>
        <version>3.4.1</version>
    </dependency>
    <dependency>
        <groupId>com.google.zxing</groupId>
        <artifactId>javase</artifactId>
        <version>3.4.1</version>
    </dependency>
</dependencies>

 

QR을 만들어내는 서비스 로직을 아래와 같이 만들어봅시다.

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@Service
public class QRCodeService {

    public byte[] generateQRCode(String text, int width, int height) throws WriterException, IOException {
        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        Map<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");

        BitMatrix bitMatrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, width, height, hints);
        ByteArrayOutputStream pngOutputStream = new ByteArrayOutputStream();
        MatrixToImageWriter.writeToStream(bitMatrix, "PNG", pngOutputStream);
        return pngOutputStream.toByteArray();
    }
}

 

이제, 컨트롤러 입니다.

import com.google.zxing.WriterException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;

@RestController
public class QRCodeController {

    @Autowired
    private QRCodeService qrCodeService;

    @GetMapping("/generateQRCode")
    public ResponseEntity<byte[]> generateQRCode(@RequestParam String text) {
        try {
            byte[] qrCodeImage = qrCodeService.generateQRCode(text, 350, 350);
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.IMAGE_PNG);
            return ResponseEntity.ok().headers(headers).body(qrCodeImage);
        } catch (WriterException | IOException e) {
            return ResponseEntity.status(500).body(null);
        }
    }
}

 

이제 http://localhost:8080/generateQRCode?text={인코딩하고자 하는 데이터} 를 요청하면, 자체적으로 생성된 QR PNG를 확인해 볼 수 있습니다 :)

어때요? 근사하죠? 읽어주셔서 감사합니다.

실수로 merge를 하였을 경우 다음과 같이.. reset을 해버리자

git reset --merge ORIG_HEAD

위 명령어를 사용하면 원격지와의 head와 로컬의 head가 상이하여 push시도시 에러가 발생한다.

git push -f origin master

-f (force)를 사용하여 강제로 push해야한다.

요즘 만들고 있는 사이드 프로젝트에서 필요한 API를 찾다가 MAP API를 간략하게나마 정리하게 되었습니다. 너프하게 찾은 자료지만 쉽게 보시기엔 편할거에요 :)

 

NAVER : MAP API (1day, 200000 call)

KAKAO : MAP API (1day, 300000 call, dev guide is perfect)

  • KAKAO MAP API는 상당히 여러가지 기능과 인터페이스를 제공한다. 심지어 30만콜이 무료이며 가이드가 상당히 잘 짜여져있다.
  • http://apis.map.kakao.com/web/guide/

Google : MAP API (payment required.. : 200,000won credit free when creating an account.)

NAVER : local API (1day, 25000 call)

  • 이건 맵 API가 아니라 Local 검색 API이다. 서비스를 만들 때 특정 매장 등과 같은 정보를 검색 할 수 있는 기능을 만들어야 하는데 이러한 상황에서 쓰면 유용하다 1일 25000콜 무료이다.
  • https://developers.naver.com/docs/search/local/

 

 

결론 : 저는 검색의 경우 NAVER API(한국 서비스를 만들거라면 아무래도 네이버가 제일 나은 플랫폼이라고 생각해요), 여기서 검색한 결과를 지도에 뿌려주는 것은 KAKAO API를 이용하려고 합니다.

'Develop Issue > Open Source, API' 카테고리의 다른 글

Google OTP 개발하기  (0) 2024.08.06
git merge 취소하기  (2) 2020.06.01
날짜별 지역별 날씨 API 제공 사이트 총정리  (2) 2016.01.19

날씨에 대한 정보를 제공해주는 서비스들은 다양하다.

개발하는 애플리케이션에서 사용하고자 하는 목적에 따라 활용한다면 좋은 자료가 될 것이라 생각되어

관련 정보들을 종합해서 실질적으로 개발에 유용 할 만한 좋은 사이트들을 간추려서 정리했다.


회사 및 API명 

 URL

설명 

케이웨더 날씨 API

http://api.kweather.co.kr/

 - 국내 3,800개 읍/면/동 단위 현재날씨 및 시간별/주간 예보 콘텐츠 (기상청 예보/ 케이웨더 예보 선택적 제공 가능)

 - 국내 교통/레저/스포츠 지점에 대한 11개 테마 날씨 콘텐츠

 - 1일 5000개까지 비상업적인 용도로는 무료로 사용 할 수 있다.

 - 개인적으로 사용하기에 편리한 REST API 구조를 가지고 있기에 추천하는 방식. 설명도 잘 되어있는 것 같다.

 웨더아이 날씨 API

http://www.weatheri.co.kr

 - web, email, mobile phone 등 다양한 매체를 통해 기상정보와 기상콘텐츠를 고객에게 제공

 - 현재 한국관광공사, 이마트, 네이버, 연합뉴스, SK텔레콤, 삼성물산 등 다양한 기업에 기상정보 서비스를 제공하고 있을 정도로 양질의 기상 예측 정보 및 콘텐츠를 생산

HAMweather Aeris API

http://www.hamweather.com/support/documentation/aeris/

 - 해외 사이트라서 국내 서비스에는 개발 효율이나 서비스 질에 불편함이 다소 없지 않아 있을 것으로 염려된다. JSON을 통해 서비스 받을 수 있다. 

기상청 날씨정보

http://www.kma.go.kr/weather/lifenindustry/sevice_rss.jsp 

 RSS, 날씨 위젯 등에 대한 서비스를 제공한다.

OpenWeatherMap API

http://openweathermap.org/API

 - 40,000개 이상의 기상 관측소의 데이터 기반으로 업데이트 된 70,000도시의 현재 날씨 정보를 제공한다.

 - 사용예시 : http://api.openweathermap.org/data/2.5/forecast?lat=35&lon=125

 - 지오코딩을 활용한 도시이름으로 날씨 검색이 가능하며 7일 가량의 일기예보를 제공한다.

 - 강수량, 구름, 온도 등의 정보를 포함한 날씨 지도 제공이 가능

 연도별오존경보발령현황

(안전행정부)

http://data.seoul.go.kr/openinf/sheetview.jsp?infId=OA-2229 

 서울시 연도별 오존 경보발령 횟수, 일수, 최대농도 정보를 제공

 야후 날씨정보

https://developer.yahoo.com/weather/ 

 야후에서 개발한 SQL인 YQL을 사용하여 서비스를 사용 할 수 있다.


'Develop Issue > Open Source, API' 카테고리의 다른 글

Google OTP 개발하기  (0) 2024.08.06
git merge 취소하기  (2) 2020.06.01
네이버 Map, 카카오 Map, Google Map API 비교  (1) 2019.09.23

+ Recent posts