본문 바로가기
WIKI 기술 지식 베이스

HMAC

원문 보기 위키 갱신

출처: HMAC

본문

HMAC

Traefik Hub 기능

이 미들웨어는 Traefik Hub에서만 사용할 수 있어요. Traefik Hub의 고급 기능에 대해 더 알아보세요.

이 미들웨어는 HTTP 요청의 내용과 공유 비밀(shared secret)을 이용해 계산한 디지털 서명을 검증합니다. 공유 비밀은 Authorization 또는 Proxy-Authorization 헤더를 통해 프록시로 전달돼요.

검증이 보장해 주는 것은 두 가지예요:

  • 발신자의 신원(인증): 서명이 프록시에서 검증되면, 발신자가 실제로 그 공유 비밀을 소유하고 있다는 뜻이에요. 그 결과 발신자의 신원이 증명된 것으로 간주됩니다.

  • 요청의 무결성: 서명이 HTTP 요청의 일부를 기반으로 만들어지기 때문에, 서명이 프록시에서 검증됐다면 그 서명을 만드는 데 쓰인 요청이 발신자와 프록시 사이에서 수정되지 않았다는 뜻이에요. 이 미들웨어는 Digest 헤더를 이용해 내용(콘텐츠) 무결성을 검증하는 것도 지원합니다.

이 미들웨어는 HTTP Signature 초안(Draft)을 기반으로 하고 있어요.

구성 예시

아래는 HMAC 미들웨어를 활성화하고, 비밀 하나를 설정하고, 요청 본문의 다이제스트 합(digest sum) 검증을 켜고, 지정한 헤더들이 반드시 요청 서명 계산에 포함되도록 하는 고급 구성입니다.

Middleware HMAC

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: hmac-auth
spec:
  plugin:
    hmac:
      keys:
        - id: secret-key
          key: secret
      validateDigest: true
      enforcedHeaders:
        - (request-target)
        - (created)
        - (expires)
        - host

구성 옵션

| Field | Description | Default | Required | | keys | HMAC 미들웨어가 사용할 정적 비밀 키 집합. | | Yes | | validateDigest | 미들웨어가 요청 본문의 다이제스트 합을 검증할지 여부. | true | No | | enforcedHeaders | 요청 서명 계산에 반드시 포함돼야 하는 헤더 집합. | | No |

인증 메커니즘

발신자와 프록시는 keyId로 식별되는 공통 비밀을 공유합니다. 발신자가 비밀을 어떻게 얻고 안전하게 보관하는지는 이 문서의 범위 밖이에요.

Authorization 헤더 만들기

요청을 인증하려면 발신자가 HMAC 인증 방식을 충족하는 Authorization 또는 ProxyAuthorization 헤더를 제공해야 합니다.

이 헤더는 여러 파라미터를 담고 있어요:

Authorization: Hmac ***"secret-id-1",algorithm="hmac-sha256",headers="(request-target) (created) (expires) host x-example",signature="c29tZXNpZ25hdHVyZQ==",created="1584453022",expires="1584453032"

| Parameter | Description | Example | | keyId | 발신자가 서명을 만드는 데 사용하는 키의 식별자 | keyId="secret-key-1" | | algorithm | 서명을 생성하는 데 쓰는 알고리즘. 지원 값은 hmac-sha1, hmac-sha256, hmac-sha384, hmac-sha512예요. | algorithm="hmac-sha512" | | headers | 서명 문자열을 만드는 데 사용할 헤더 목록. 각 항목은 소문자여야 해요. | headers="host content-type" | | signature | 요청의 디지털 서명. 서명 계산 방법을 참고하세요. | signature="c29tZXNpZ25hdHVyZQ==" | | created | 서명이 만들어진 Unix 타임스탬프 | created="1574453022" | | expires | 서명이 만료되는 Unix 타임스탬프 | expires="1574453022" |

시간 민감성

created 타임스탬프가 미래이거나 expires 타임스탬프가 과거라면, 미들웨어는 요청을 거부합니다. 이런 동작 때문에 이 미들웨어는 클라이언트와 서버 사이의 클럭 오차(clock skew)에 민감해져요.

클라이언트와 서버의 클럭이 동기화돼 있는지 꼭 확인하세요.

서명 계산하기

서명은 signature string과 발신자의 secret key로 계산한 HMAC 서명 알고리즘 결과를 base64로 인코딩한 값입니다.

예를 들면:

signature=base64(HMAC(signatureString, secret))

서명 문자열 만들기

서명된 HTTP 요청은 게이트웨이, 프록시, 기타 엔티티를 지나면서 전송 중에 생기는 사소한 변경에는 관대해야 합니다. 따라서 요청 전체에 서명하는 것은 좋은 방법이 아니에요. 헤더 하나만 바뀌어도 서명이 유효하지 않게 되거든요.

이 문제를 피하기 위해 이 미들웨어는 인증 헤더의 headers 파라미터로 발신자가 지정한 헤더 값들의 일부로 signature string을 구성합니다.

서명 문자열을 만들려면 클라이언트가 headers 파라미터에 지정된 각 헤더의 값을 그 순서대로 가져온 뒤, 각각에 다음 로직을 적용해야 합니다:

  • 헤더가 특수 헤더라면, 특수 헤더 값 섹션에 따라 그 값을 평가합니다.

  • 헤더가 특수 헤더가 아니라면, 소문자 헤더 이름 뒤에 ASCII 콜론 :, ASCII 공백 , 헤더 값을 붙입니다. 헤더에 값이 여러 개라면 그 값들을 ASCII 쉼표 ,와 ASCII 공백 으로 구분해 붙입니다.

  • 값이 마지막 값이 아니라면 ASCII 줄바꿈 \n을 붙입니다. 서명 문자열은 끝에 ASCII 줄바꿈을 포함하면 안 됩니다.

Warning

모든 헤더 값은 공백이 제거됩니다."

특수 헤더 값

설계상 HTTP 요청의 모든 정보가 헤더로만 제공되지는 않습니다. 그래도 헤더를 이용해 요청을 보호하는 것은 의미가 있어요.

이를 위해 headers 파라미터는 사용할 수 있는 특수 헤더 이름을 허용합니다.

| Value | Description | Signature String Example | | (request-target) | 소문자 :method, ASCII 공백, :path 의사 헤더(HTTP/2에서 정의됨)를 연결해 얻습니다. | (request-target): get /api/V1/resource?query=foo | | (created) | 인증 헤더의 created 파라미터 값 | (created): 1584453022 | | (expires) | 인증 헤더의 expires 파라미터 값 | (expires): 1584453082 |

이들의 평가 값은 특수 헤더 이름 뒤에 ASCII 콜론 :, ASCII 공백 , 지정된 값을 붙여 얻습니다.

Example

(created): 1929494939
(request-target): get /foo/bar

서명 문자열 예시

인증 헤더 파라미터가 다음과 같이 설정된 예시를 볼게요:

  • headers="(request-target) (created) (expires) host x-example x-emptyheader cache-control"

  • created="1584466921"

  • expires="1584466931"

Request

GET /foo HTTP/1.1
Host: example.org
X-Example: Example header
    with some whitespace.
X-EmptyHeader:
X-NotIncluded: always
Cache-Control: max-age=60
Cache-Control: must-revalidate

Expected Signature String

(request-target): get /foo
(created): 1584466921
(expires): 1584466931
host: example.org
x-example: Example header with some whitespace.
x-emptyheader:
cache-control: max-age=60, must-revalidate

강제 헤더 (Enforced Headers)

미들웨어를 구성해 서명 문자열을 만드는 데 반드시 필요한 최소 헤더 집합을 강제할 수 있어요. 즉, 서명에 강제 헤더가 없는 요청은 모두 체계적으로 거부됩니다.

이 옵션은 인증을 시작할 때 반환되는 헤더 목록도 구성합니다.

기본값은 (request-target) (created) (expires)입니다.

항상 (created)와 (expires)를 강제하세요

created와 expires 헤더 파라미터는 재전송 공격(replay attack)을 막아줍니다. 이 값이 전송 중 수정되지 않도록 하려면, (created)와 (expires) 특수 헤더 값을 이용해 항상 이 파라미터 값들을 서명에 포함시키는 것이 좋습니다.

그렇게 하려면 미들웨어가 항상 (created)와 (expires)를 강제하도록 구성하는 것을 권장합니다.

인증 시작하기

인증은 프록시가 시작할 수 있어요. Hmac 인증 방식을 사용하라고 알려주는 WWW-Authenticate 헤더와 함께 401 Unauthorized 응답이 반환됩니다.

WWW-Authenticate: Hmac headers="(request-target) (created) (expires) host x-example"

이 헤더는 발신자가 Hmac 인증 방식을 충족하는 Authorization 헤더를 제공해야 한다는 것을 알려줍니다. 또한 headers 파라미터를 이용해 서명에 포함해야 하는 헤더 목록을 알려줍니다.

강제 헤더

WWW-Authenticate 헤더에 담긴 헤더 목록은 미들웨어 구성에 지정된 강제 헤더 목록입니다.

요청 본문 무결성 검증

다이제스트 헤더를 서명 문자열에 포함하면, 수신된 요청의 본문이 전송 중 변경되지 않았는지 확인할 수 있어요.

이 미들웨어는 기본적으로, 본문이 있다면 그 본문의 다이제스트 합을 검증합니다.

체크섬 계산에는 SHA-256과 SHA-512 체크섬만 지원됩니다.

잠재적인 CPU·메모리 사용량

다이제스트를 검증하면 미들웨어가 요청 본문을 읽고 체크섬을 계산해야 합니다. 그 결과 프록시에서 메모리와 CPU 사용량이 높아질 수 있어요.

이 기능을 끄고 인증만 수행하려면 미들웨어 구성에서 validateDigest 옵션을 false로 설정하세요.

Traefik OSS를 프로덕션에서 사용하시나요?

직장에서 Traefik을 사용한다면, 엔터프라이즈급 API 게이트웨이 기능이나 Traefik OSS 상용 지원을 추가하는 것을 고려해 보세요.

  • API Gateway 데모 영상 보기

  • 24/7/365 OSS 지원 요청

Traefik OSS에 API 게이트웨이 기능을 추가하는 것은 빠르고 매끄러워요. 기존 구성을 교체하거나(rip and replace) 버릴 필요 없이 그대로 유지됩니다. 짧은 영상으로 직접 확인해 보세요.

더 알아보기 (Learn more)