付加データを付き合わせてなりすましを見破るHMAC
前回の勉強内容
勉強のきっかけになった問題
令和2年度秋(2020-10)の情報処理安全確保支援士試験午後1の問題にHMACについての問題が出題されました。
そして、大敗を喫しました・・・ので勉強します。
なりすまし対策としてデータが改竄されていないかを検証します。
「勉強のきっかけになった問題」では、「会員番号をバーコードで表示するアプリのなりすまし対策」にメッセージ認証を用いることになっています。
「他人のバーコードを会員番号から推測して表示」「他人の会員番号を盗んでバーコードを生成」しちゃってなりすしできちゃうので対策をするわけです。
メッセージ認証は、検証用のデータをメッセージに添付する方法です。
ネットワークを伝わっている間にデータが改竄されても検出できるように以下の流れで検証を行います。
- メッセージをやりとりする送信者と受信者で秘密情報(共有鍵など)を共有する
- 送信者がメッセージ本文から秘密情報などをごにょごにょ使って検証用のデータを作る
- 送信者は、メッセージ本文と検証用のデータを受信者に送る
- 受信者がメッセージ本文から秘密情報などをごにょごにょ使って検証用のデータを作る
- 受信者は、送られてきた検証用のデータと自分で作った検証用のデータを比較する
- 2つの検証用のデータが同じであったら改竄されていないと判断する
検証用のデータのことをMACといいます。
- 英語 : Message Authentication Code
- 日本語 : メッセージ認証符号
送信者Aが,受信者Bと共有している鍵を用いて,メッセージからメッセージ認証符号を生成し,そのメッセージ認証符号とメッセージを受信者Bに送信する。このとき,メッセージとメッセージ認証符号を用いて,受信者Bができることはどれか。
答. メッセージの改ざんがないことを判定できる。
HMACは、ハッシュ関数を使って作られたMACのことです。
- 英語 : Hash-based Message Authentication Code
メッセージ本文 + 共有鍵 = MAC メッセージ本文 + 共有鍵 + ハッシュ関数 = HMAC
みたいな感じです。
MAC(Message Authentication Code)は、通信内容の改ざんの有無を検証し、完全性を保証するために通信データから生成される固定長のビット列です。 MACの生成には、共通鍵暗号を用いたもの(DES-MACやAES-MAC)とハッシュ関数を用いたもの(HMAC)がありますが、設問ではブロック暗号を用いてMACを生成しているので共通鍵暗号を用いた方式であることがわかります。
GitHubのWebhookでもHMACを使います。
以前、Backlogの課題にGitHubのコミットを連携する方法 - ponsuke_tarou’s blogをやった時にHMACを使いました。
- GitHubでWebhookを登録する時に合わせて登録するSecretが「メッセージをやりとりする送信者と受信者で秘密情報」になります。
- GitHubは、情報と一緒に検証用のデータを送ってくれます。
- BODY部分のメッセージ本文とSecret(秘密情報)とハッシュ関数でHMAC値を作ります。
- 2つのHMAC値が同じであったら改竄されていないと判断する(下記Pythonのコード参照)
{ ...省略... "headers": { ...省略... "x-hub-signature": "sha1=検証データ", "x-hub-signature-256": "sha256=検証データ" }, ...省略... "body": "BODYに送ってくれた情報がある" ...省略... }
# -*- coding: utf-8 -*- from __future__ import print_function import json, hmac, hashlib def lambda_handler(event, context): # 送信者と受信者で秘密情報であるSecretの値 secret = '3m@6vC5Y_mNwhhA' # GitHubから送られてきた情報にあったHMAC値 sent_hmac = event['headers']['x-hub-signature-256'] print('SHA-256ハッシュ関数用のHMAC値:' + sent_hmac) # Secretの値をbytes型に変換する secret_bytes = bytes(secret, 'utf-8') if (event['isBase64Encoded']): # bodyをbase64でデコードしてbytes型にする body_bytes = base64.b64decode(event['body']) else: # bodyをbytes型に変換する body_bytes = bytes(event['body'], 'utf-8') # 「Secret + メッセージ + ハッシュ関数」でHMAC値を作る created_hmac = 'sha256=' + hmac.new(secret_bytes, body_bytes, hashlib.sha256).hexdigest() print('自分で作ったHMAC値:' + created_hmac) # 2つのHMAC値が同じであったら改竄されていないと判断する if created_hmac == sent_hmac: print('HMAC値で認証できた!') else: print('認証できないHMAC値がGitHubから送られてきた!')
上記は以下の投稿で紹介しているコードを基にしていますので、ご興味のある方はご参照ください。 ponsuke-tarou.hatenablog.com