質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

セキュリティー

このタグは、コンピューターシステムの安全性やデータの機密性に関連したトピックの為に使われます。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

Q&A

0回答

3320閲覧

HMACを使用したWeb API認証

退会済みユーザー

退会済みユーザー

総合スコア0

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

セキュリティー

このタグは、コンピューターシステムの安全性やデータの機密性に関連したトピックの為に使われます。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

0グッド

4クリップ

投稿2018/01/29 08:03

編集2022/01/12 10:55

質問内容


Secure ASP.NET Web API using API Key Authentication – HMAC Authentication

上記の記事を見てHMACを使用したAPI認証というものを知りました。
これに関して2つの質問があります。

質問1

まずはこの認証方法についてそもそもの理解ができているかの確認したく、
記事のサンプルとは異なりますが自分の理解を兼ねて仕組みを以下に記載します。
※元記事に記載があるナンスやタイムスタンプは省いています

以下の内容に誤りなどありましたらご指摘いただけますでしょうか。

サンプル API Client | | ユーザ識別IDと秘密鍵を共有 |------------------------- | | | | | | | 以下のデータから署名を作成 | | - リクエストURL | | - リクエストBODY | | - 秘密鍵 | | | リクエストにユーザ識別ID,署名を含めて送信 | ここでは仮にHTTP Headerに入れるとする,クエリストリングでも何でもいい | X-Access-Id: ... | | X-Signature: ... | |<-------------------------| | |
  1. API側とClientはユーザの識別を行うためのユーザ識別IDと、HMACの秘密鍵を共有する。
  2. Client側はAPIへのリクエストURLとリクエストBodyの2つの文字列を連結し、1で共有された秘密鍵を使用してHMACで署名を作成してBase64でエンコードする
  3. Clientは1で共有したユーザ識別IDとBase64でエンコードされた署名をリクエストに同封して送信する
  4. APIはリクエストのユーザ識別IDから対応する秘密鍵を探し、その鍵とリクエストのURLとBodyから署名を作成、送信されてきた署名と比較を行い等しければ認証成功とする

質問2

自分でコードを書いてみましたので、セキュリティの観点からレビューをいただきたいです。
Ruby on Railsで使用することを想定しています。

ruby

1class HmacAuthentificator 2 # アクセスIDヘッダ ユーザの識別を行う 3 X_ACCESS_ID_HEADER = 'X-Access-Id' 4 5 # 署名ヘッダ リクエストの正当性検証を担う 6 X_SIGNATURE_HEADER = 'X-Signature' 7 8 # タイムスタンプヘッダ replay attacks攻撃防止用 9 X_TIMESTAMP_HEADER = 'X-Timestamp' 10 11 # 署名作成のハッシュ関数 12 DIGEST_METHOD = 'sha256' 13 14 # タイムスタンプの期限切れ時間(秒) 15 TIMESTAMP_EXPIRATION = 10.0 16 17 # @param [ActionDispatch::Request] request 18 def initialize(request) 19 @request = request 20 end 21 22 # リクエストの正当性検証 23 # @return [Boolean] 24 def valid? 25 # 26 # タイムスタンプ 27 # 28 timestamp = @request.headers[X_TIMESTAMP_HEADER] 29 return false unless timestamp 30 parsed_timestamp = ::Time.zone.parse(timestamp) 31 return false unless parsed_timestamp 32 # タイムスタンプの有効期限検証,制限時間を超えているものと未来のものは拒否する 33 now = ::Time.zone.now 34 return false if now - parsed_timestamp > TIMESTAMP_EXPIRATION || parsed_timestamp > now 35 36 # 37 # アクセスID 38 # 39 access_id = @request.headers[X_ACCESS_ID_HEADER] 40 return false unless access_id 41 42 # 43 # 秘密鍵 44 # 45 secret_token = find_secret_token(access_id) 46 return false unless secret_token 47 48 # 49 # 署名 50 # 51 requested_signature = @request.headers[X_SIGNATURE_HEADER] 52 return false unless requested_signature 53 54 # 55 # 署名の再作成と検証 56 # 57 regenerated_signature = create_signature(secret_token, @request.original_url, @request.raw_post, timestamp) 58 # MITIGATE TIMING ATTACK 59 return false unless ::ActiveSupport::SecurityUtils.variable_size_secure_compare(regenerated_signature, requested_signature) 60 return false unless ::ActiveSupport::SecurityUtils.secure_compare(regenerated_signature, requested_signature) 61 62 return true 63 end 64 65 # @return [String|nil] 66 def find_secret_token(access_id) 67 # secret_tokenはDBに保存しておく 68 end 69 70 # リクエストから署名を作成 71 # 72 # @param [String] token 鍵文字列 73 # @param [String] url リクエストURL 74 # @param [String|nil] body リクエストボディ 75 # @param [String] timestamp - タイムスタンプ(ISO 8601) 76 # @return [String] 77 def create_signature(token, url, body, timestamp) 78 body = '' if body.nil? 79 content = [url, body, timestamp].map(&:strip).join 80 ::Base64.strict_encode64(::OpenSSL::HMAC.digest(DIGEST_METHOD, token, content)) 81 end 82end 83 84# Railsコントローラ 85class ExampleController < ApiBaseController 86 before_action :authentificate_api! 87 88 def index 89 render plain: 'ok' 90 end 91 92 def authentificate_api! 93 authentificator = HmacAuthentificator.new(request) 94 return true if @authentificator.valid? 95 96 fail(AuthentificationError, msg) 97 end 98end

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問