インターネットでデータをやり取りするとき、その内容が途中で書き換えられていないか、そして本当に正しい相手から送られてきたものなのかを確認することはとても重要です。
こうした「改ざん防止」と「送信者の正当性の確認」に役立つ仕組みの1つがHMAC(HMAC: Hash-based Message Authentication Code)です。
この記事では、暗号の専門家でなくても理解できるように、HMACの基本から動き方、よくある利用シーンまでを丁寧に解説します。
HMACとは何か
HMACとは、ハッシュ関数と秘密鍵を組み合わせて作るメッセージ認証コードです。
難しく聞こえますが、要点は「メッセージに対して、送信者と受信者だけが知っている秘密の鍵を使って“署名”のような値を計算する仕組み」と考えるとイメージしやすくなります。
送信側は、メッセージと秘密鍵からHMAC値を計算し、その結果をメッセージに添えて送信します。
受信側は、受け取ったメッセージに対して自分の持つ同じ秘密鍵を使って再度HMAC値を計算し、送られてきたHMAC値と一致するかどうかを確認します。
一致すれば、「途中で改ざんされておらず、かつ秘密鍵を知っている正しい相手からのメッセージだろう」と判断できるわけです。
ハッシュ関数と「単なるハッシュ」との違い
HMACを理解するために、まずハッシュ関数と「単なるハッシュ」との違いを整理します。
ハッシュ関数は、どんな長さのデータからでも、一定長さの“要約”を計算する関数です。
代表的なものとしては、SHA-256などがあります。
ファイルの整合性チェックなどにも使われており、同じ入力からは必ず同じハッシュ値が得られます。
しかし、ハッシュ値そのものには「誰が計算したのか」という情報がありません。
入力データさえ分かれば、だれでも同じハッシュ値を計算できます。
そのため、「改ざんされていないか」を確認することはできても、「正しい相手が作ったものか」を確認することはできません。
そこで登場するのがHMACです。
HMACでは、ハッシュ値の計算に秘密鍵を混ぜることで、「改ざん検知」と同時に「秘密鍵を持つ正しい相手からのメッセージかどうか」を確認できるようにしています。

このように、HMACはハッシュ関数に「認証」の役割を加えた仕組みだと理解してください。
HMACが解決する2つの問題
HMACは主に、次の2つの問題を解決するために使われます。
1つ目はメッセージの改ざん防止(完全性の確認)です。
悪意ある第三者が途中でメッセージを書き換えた場合、そのメッセージに対する正しいHMAC値を計算することはできません。
なぜなら、正しいHMAC値を計算するには秘密鍵が必要だからです。
2つ目は相手が正しいかどうかの確認(認証)です。
送信者と受信者だけが秘密鍵を共有している前提では、正しいHMAC値を生成できるのは鍵を知っている相手だけです。
そのため、HMACが正しく検証できることは、そのメッセージが鍵を知っている正当な相手から送られた可能性が高いことを意味します。
ここで重要なのは、HMACは「誰か1人を特定する」ための仕組みではないという点です。
秘密鍵を共有している複数のシステムがあれば、その中の誰が送信したかまでは区別できません。
そのため、HMACは「共有鍵による認証」であり、公開鍵暗号を使った電子署名とは目的や性質が少し異なります。
HMACの基本的な仕組み
HMACの内部では、ハッシュ関数を2回使う構造になっています。
代表的なものとしてHMAC-SHA256やHMAC-SHA1などがありますが、どれも基本的な考え方は同じです。

HMACの計算は、概念的には以下のように表されます。
- 内部ハッシュ: ハッシュ( (キー ⊕ ipad) || メッセージ )
- 外部ハッシュ: ハッシュ( (キー ⊕ opad) || 内部ハッシュの結果 )
ここで、⊕はXOR(排他的論理和)、||は連結(つなげること)を表しています。
ipadとopadは、それぞれ「内側のハッシュで使うための定数の並び」「外側のハッシュで使うための定数の並び」です。
なぜハッシュを2回使うのか
ハッシュを2回使う構造には、安全性と実装上の理由があります。
1つは、鍵とメッセージの混ざり方を慎重に設計するためです。
単純に「キー + メッセージ」をハッシュするだけでは、ハッシュ関数の内部構造によっては、理論上の攻撃手法を受けやすくなる可能性があります。
HMACでは、鍵に特定の定数(ipad/opad)をXORしてからハッシュすることで、ハッシュ関数に既知の弱点があっても、実用上安全に使えるよう配慮しています。
もう1つは、鍵をそのままハッシュ関数の内部状態に露出させないという観点です。
HMACの構造により、仮にハッシュ関数自体に何らかの問題が見つかったとしても、鍵そのものが直接漏れにくいよう設計されています。
HMACの計算ステップをイメージで理解する
抽象的な定義だけではイメージしにくいため、HMACの計算をもう少し具体的なステップに分解して説明します。

HMACの計算は、おおまかに次のような流れで行われます。
- 鍵の長さ調整
使用するハッシュ関数には「ブロックサイズ」と呼ばれる単位長があります。例えば、SHA-256なら通常64バイトです。まず、秘密鍵の長さがこのブロックサイズに合うように調整します。長すぎる場合は一度ハッシュして縮め、短い場合は0で埋めてブロックサイズに合わせます。 - 内側用の値を作成
ブロックサイズに揃えた鍵に、ipad(内部パディング)をXORします。これをKiとします。そこにメッセージをつなげたKi || メッセージをハッシュして、内部ハッシュ値を求めます。 - 外側用の値を作成
同じく、鍵にopad(外部パディング)をXORしたものをKoとします。そこに、先ほどの内部ハッシュ値をつなげたKo || 内部ハッシュ値をハッシュします。 - 最終的なHMAC値の取得
上記の外側ハッシュの結果が、最終的なHMAC値となります。この値をメッセージに添えて送信します。
実装では、これらのステップを隠ぺいしてシンプルなAPI(cst-code>HMAC(key, message)など)として提供することが多いため、利用者は複雑な内部処理を意識せずに使うことができます。
HMACの検証方法
HMACの検証は、送信時と同じ処理をもう一度行って、結果が一致するかどうかを見るだけです。
受信側が行う処理は次の通りです。
- メッセージ本体と、送信側から送られてきたHMAC値を受け取る。
- 自分が保持している秘密鍵とメッセージから、同じアルゴリズムでHMAC値を計算する。
- 計算されたHMAC値と、受け取ったHMAC値を比較する。
- 一致すれば「改ざんなし・正当な送信者からの可能性が高い」と判断し、不一致なら破棄する。
ここでポイントになるのが、HMAC値の比較方法です。
実装上は==のような単純な比較演算子を使わず、「タイミング攻撃」を避けるために、比較にかかる時間が入力値に依存しない方法を用いることが推奨されます。
これは、比較の途中で不一致を検出して処理を打ち切るような実装だと、不一致箇所によってわずかに処理時間が変化し、それが攻撃者にヒントを与えてしまう可能性があるためです。
HMACでよく使われるハッシュ関数
HMACは、さまざまなハッシュ関数と組み合わせて使うことができます。
代表的な組み合わせは次の通りです。
| 種類 | 説明 |
|---|---|
| HMAC-SHA256 | 現在もっとも一般的に使われる組み合わせの1つ。APIの署名や認証トークンなど、幅広く利用される。 |
| HMAC-SHA1 | 以前は主流だったが、SHA-1自体の安全性懸念から新規利用は推奨されない。 |
| HMAC-SHA512 | より長いハッシュ値を必要とする場合に使われる。RSAなどの大きな鍵サイズと組み合わせる用途など。 |
新しいシステムでは、原則としてHMAC-SHA256以降のアルゴリズムを選択することが推奨されます。
既存システムの中にはHMAC-SHA1が残っているケースもありますが、可能であれば計画的な移行が望まれます。
HMACの典型的な利用シーン
HMACは、日常的に利用している多くの仕組みの裏側で活躍しています。
ここでは代表的な利用シーンを挙げて、その役割を説明します。
1. Web APIのリクエスト署名
クラウドサービスや外部APIでは、APIリクエストにHMACによる署名を付与する方式がよく使われます。
クライアントとサーバーが共有している秘密鍵を使い、リクエストの内容(HTTPメソッド、URL、ボディ、タイムスタンプなど)からHMACを計算し、その結果をHTTPヘッダーに載せて送信します。

こうすることで、リクエスト内容が途中で改ざんされていないことと、秘密鍵を持っているクライアントからの正当なリクエストであることを確認できます。
2. 認証トークンやセッションIDの保護
JWT(JSON Web Token)や各種セッショントークンでは、トークンの改ざん検知にHMACが使われることがあります。
トークンのヘッダーやペイロード部分を文字列として連結し、その結果に対してHMACを計算します。
トークンの受け取り側は、同じ秘密鍵でHMACを再計算し、一致するかどうかを確認します。
この仕組みにより、トークンの内容(権限、ユーザーID、有効期限など)が途中で書き換えられても検知できるようになります。
ただし、HMACベースのトークンは「共有鍵」方式であるため、検証を行うすべてのサーバーが同じ秘密鍵を持つ必要があります。
3. TLSやVPNなどの通信プロトコル
TLS(HTTPSの基盤となるプロトコル)やIPsec VPNなどでは、パケットやレコード単位での改ざん検知にHMACが利用されています。
暗号化されたデータとセットでHMACが送られ、受信側で検証することで、途中で攻撃者によってデータが書き換えられていないかを確認します。
こうしたプロトコルでは、暗号化とHMACによる認証を組み合わせて、機密性(盗み見防止)と完全性(改ざん防止)の両方を実現しています。
HMACを安全に使うための注意点
HMAC自体は十分に検証された仕組みですが、使い方を誤ると安全性が損なわれることがあります。
ここでは、実務で意識したいポイントを整理します。
鍵の管理と長さ
まず重要なのは秘密鍵の管理です。
HMACの安全性は、ほぼ鍵の安全性に依存します。
鍵が漏洩すれば、攻撃者は正規の送信者を装って正しいHMACを計算できてしまいます。
そのため、以下のような点に注意が必要です。
- 鍵はソースコードにベタ書きせず、環境変数や専用の秘密情報管理サービス(Secret Managerなど)で扱う。
- 鍵の権限を最小限にし、アクセスできるシステムや人を限定する。
- 定期的な鍵のローテーション(更新)を検討する。
また、鍵の長さも重要です。
一般に、ハッシュ関数の出力長と同程度か、少し長い程度の鍵を使うことが推奨されます。
たとえばHMAC-SHA256であれば、32バイト(256ビット)前後のランダムな鍵を用いるとよいでしょう。
メッセージのどこまでをHMACに含めるか
HMACは、「どの部分をメッセージとみなしてHMACの対象にするか」によって安全性が変わります。
たとえばWeb APIの署名では、次のような項目を1つの文字列にまとめてからHMACを計算するケースが多いです。
- HTTPメソッド(GET/POSTなど)
- リクエストパス(/api/v1/…)
- クエリパラメータ
- HTTPヘッダーの一部(日付、ホスト名など)
- リクエストボディ(必要に応じて)
これらの一部をHMAC対象から漏らしてしまうと、その部分が攻撃者に改ざんされるリスクが生じます。
したがって、「改ざんされたくない情報」は必ずHMACの対象に含めることが大切です。
実装は「自前で暗号を書く」ことを避ける
暗号アルゴリズムを自分で一から実装するのは、よほどの専門知識がない限り避けるべきです。
HMACについても同様で、各プログラミング言語の標準ライブラリや、信頼できる暗号ライブラリに備わっている実装を利用するのが基本です。
たとえば、以下のような高レベルAPIが用意されていることが多いです。
HMAC_SHA256(key, message)crypto.createHmac('sha256', key).update(message).digest()
これらのAPIは、鍵長の調整やipad/opad処理、タイミング攻撃を避ける比較などを考慮した実装になっていることが多いため、独自実装するよりも安全で堅牢です。
まとめ
HMACは、ハッシュ関数と秘密鍵を組み合わせて「メッセージの改ざん防止」と「送信者の認証」を実現する仕組みです。
単なるハッシュ値と違い、秘密鍵を持つ者だけが正しいHMAC値を計算できるため、途中でメッセージが書き換えられていないこと、そして正当な相手から送られたものである可能性を検証できます。
内部的にはハッシュ関数を2回使い、ipadやopadといった定数を用いることで、ハッシュ関数の構造上の弱点を補いながら高い安全性を実現しています。
実際の利用場面としては、Web APIのリクエスト署名、トークンの改ざん防止、TLSやVPNといった通信プロトコルなど、現代のシステムには欠かせない存在になっています。
一方で、HMACの安全性は鍵の管理と正しい実装に大きく依存します。
鍵を安全に保管し、改ざんされたくない情報を漏れなくHMAC対象に含め、信頼できる暗号ライブラリを利用することが重要です。
HMACの仕組みを理解しておくことで、API設計や認証・認可の仕組みを検討するときに、どこでどのようにメッセージ認証コードを利用すべきかを判断しやすくなります。
本記事をきっかけに、自身のシステムや利用しているサービスがどのようにHMACを活用しているのか、あらためて目を向けてみてください。
