• 締切済み

PHPでショッピン管理システムを作る

お世話になっております。 少し前に質問させて頂いたのですが、回答がつかなかったのでカテゴリを変えて改て質問させて頂きます。 前回、質問させて頂いた内容の続きになるのですが、前の質問はこちらを(http://okwave.jp/qa/q7453193.html)どうぞ。 根本的な事をお伺いしたく、質問させて頂きます。 まず、私が実現したい内容からご説明させて頂きます。 複数あるサイト(A・B・C)サイトがあります。それぞれ、販売している物はバラバラです。 現在は、サイトごとにお問い合せフォームを用意していて、お問い合せフォームから注文が入ります。 フォームからメールが来て完結しているのですが、顧客情報を管理していきたいので、A・B・Cのサイトから管理サイトEを作って、各商品の情報をPOSTなどで、管理サイトEに飛ばし、管理サイトEで顧客情報の入力や注文内容の入力を行なっていただくと、一括管理が出来て、システムさえ作れば、メルマガなどの発行も容易になると考えています。 ポイントは、管理サイトEは商品情報は持たずに、販売サイトA・B・CからPOSTで飛ばされた情報を元に注文処理を行いたいと考えています。 理由は、商品全てを管理サイトEにも登録すると、非常に手間がかかり、現実的に管理が難しいと思うので・・・・ そこで、質問です。 よくAPIサービスなどでカートのみのレンタルのサービスがありますが、私の知る限り、このAPIのシステムにも、商品を登録するタイプが殆どです。 この理由はなぜでしょうか? 商品情報を持たずに、飛ばされた情報で注文をすすめると、セキュリティなどに問題が生じるからでしょうか? ちなみに、クレジット決済などは利用する予定はありませんが、やはりクレジットを使った場合などでは、問題が生じるのでしょうか? どうぞ宜しくお願いします。

みんなの回答

回答No.6

先の回答では書いていませんで、長らく時間が立ちましたが、暗号化してなおかつタイムアウトを付ける場合は例えばこんな感じでしょうか。ここまで来るとわざわざ電子署名だけ別の方法で送る必要もないので、arrayに入れて、serializeして送るようにしました。 実行するにはこれまで書いたTimeoutSigner、TimeoutVerifier、後述するstr_hash_pbkdf2の実装が必要です。また、送信時の容量を削減するためにzlibモジュールのgzcompress、gzuncompressを使っています。 $password = "abc"; $data = array( 0 => array( 'title' => 'Hamlet', 'category' => 'book', 'price' => '1000', 'unit' => 'yen', 'number' => 1, ), ); $tc = new TimeoutCipher($password); $encrypted = base64_encode($tc->encrypt($data)); print "$encrypted\n"; var_dump($tc->decrypt(base64_decode($encrypted))); /** * Encrypt / Decrypt given data. * Encrypted data contains TimeoutSigner's signature. * @package default * @author Hanabutako. */ class TimeoutCipher { const PBKDF2_COUNT = 4096; const SIGNER_KEY_LENGTH = 16; function __construct($password) { $this->td = mcrypt_module_open('rijndael-128', '', 'ctr', ''); // make key and iv for encrypt/decrypt and sign. $is = mcrypt_enc_get_iv_size($this->td); $ks = mcrypt_enc_get_key_size($this->td); $total_size = $is + $ks + TimeoutCipher::SIGNER_KEY_LENGTH; $k = str_hash_pbkdf2($password, $salt, TimeoutCipher::PBKDF2_COUNT, $total_size, 'sha256'); $this->key = substr($k, 0, $ks); $this->iv = substr($k, $ks, $is); $signer_key = substr($k, $ks + $is, TimeoutCipher::SIGNER_KEY_LENGTH); $this->signer = new TimeoutSigner($signer_key); $this->verifier = new TimeoutVerifier($signer_key); } function __destruct() { mcrypt_module_close($this->td); } /** * Encrypt data. * * @param array $data to encrypt. * @return binary string represents encrypted data and signature. */ function encrypt($data) { // encrypt mcrypt_generic_init($this->td, $this->key, $this->iv); $serialized_data = serialize($data); $encrypted = mcrypt_generic($this->td, gzcompress($serialized_data)); mcrypt_generic_deinit($this->td); // sign $sig = $this->signer->sign($serialized_data); // combine. $signed_data = array('data' => $encrypted, 'sig' => $sig); return serialize($signed_data); } /** * Decrypt data. * * @param string $data to decrypt. * @return decrypted data if verification success. Otherwise null. */ function decrypt($data) { $unserialized = unserialize($data); $encrypted = $unserialized['data']; $sig = $unserialized['sig']; // decrypt. mcrypt_generic_init($this->td, $this->key, $this->iv); $decrypted = gzuncompress(mdecrypt_generic($this->td, $encrypted)); mcrypt_generic_deinit($this->td); // verify. if ($this->verifier->verify($decrypted, $sig)) { return unserialize($decrypted); } else { return null; } } } これまでのやつはkeyが短くてもそのまま使っていて、あまり強力ではなかったのでその部分をPBKDF2を使ってちょっと修正しました。(PBKDF2_COUNTの値は適宜調整してください。大きいほど強力ですが、遅くなります。) 行数の関係でPBKDF2の実装および、これまで書いたTimeoutSigner、TimeoutVerifierは書いていません。 なお、str_hash_pbkdf2の実装はここから手に入ります。 http://php.net/manual/ja/function.hash-hmac.php 極力元のデータに対して電子署名をつけるようにしているので、gzcompressで圧縮する前の値に署名をしています。また、ちゃんとした方法で暗号化すると圧縮で小さくなることはないので、圧縮してから暗号化するようにしています。 TimeoutSigner、TimeoutVerifierを使っているので一定時間を経過するとデータが無効となり、decryptがnullを返します。 まぁ、参考までに。

すると、全ての回答が全文表示されます。
回答No.5

> 私が今回、気付かされたのではデータを渡すと際のデータをいかに予測のつかない値に変えて渡すかと言うことと、その方法が非常に勉強になりました。 プログラムにほとんど説明をつけていない自分も悪いのですが、非常に誤解されている気がします。そういうことを目的にはしているコードを書いたつもりはありません。このプログラムの目的は次の3つであり、データの機密性を保つという目的はありません。 - 任意のデータ形式をHTML内に埋め込み、壊れない形にエンコードする - データの完全性を確認する手段を提供する - 無駄なデータを送らない また、データの完全性の確認手段は次の2つの方針で作りました。 - 任意のタイミングで鍵を変更できる (受け取り側で新旧両方の突合が可能) - 一定時間後に署名が無効になるようにでき、リプレイ攻撃を難しくする もし、データの機密性も要件に含まれるなら、難読化ではなく、暗号化を行います。難読化は機密性を保つのには何の役にも立ちません。攻略したい場合、攻撃者は何度も試行をして、難読化されたデータのルールをすぐに見つけ出せます。Base64くらいひと目で見抜きます。 > [送り側] > TimeoutSignerクラスを使って、変数keyのハッシュを行い、substrで一部分を切り出す。 これは、TimeoutSignerで署名に使った鍵でTimeoutVerifierが検証していることを保証するために行います。あるいは、どの鍵でTimeoutSignerが署名をしたかをTimeoutVerifierに教えるために使います。 ハッシュ値が同じなら、元のデータが同じ可能性が高いというのはご存知のとおりだと思います。 つまり、署名に使った鍵のハッシュ値と、検証に使った鍵のハッシュ値が一致すれば、同じ鍵を使った可能性が高いことが言えます。 TimeoutVerifier側で両方の鍵で検証をしないといけないのは鍵が変わってしばらくなので、せいぜい数本しか正しい鍵の候補がないと考えます。SHA256のハッシュ値は32バイト使いますが、これをFINGERPRINT_LENGTHの長さで切り取っても数本ならそうそうハッシュ値が衝突することはないと考えられますので、その長さに切って署名に消費するバイト数を節約します。 (snip) > singメソッドはtime()関数で現在のタイムスタンプを取るこの時、pack関数でタイムスタンプをバイナリ文字列にする←簡単にタイムスタンプをわからなくするため。 いいえ。データを固定長にするためです。 TimeoutVerifierにある次の行を見てください。 $timestamp = substr($signature, TimeoutSigner::FINGERPRINT_LENGTH, 4); ここで、4という値が使えるのは、タイムスタンプが必ず4バイトで表現されていることが保証されているからです。 また、タイムスタンプはすでに4バイト全て使わないと表現できなくなっていますから、4バイトの固定値にしても無駄にはなりません。 余談ですが、データを保存したり、ネットワークで転送したりするときは、一般に次の3つのやり方でエンコードします。 1. 固定長にする 2. 可変長にし、長さを最初に書く 3. 可変長にし、終了文字 あるいは 継続を示すフラグを使う それぞれ、メリットデメリットがあるので、使用事例とそれを比べてからどういうエンコードをするか決めます。ちなみに、2で述べた長さの書き方にも、固定長になっている場合と最初のビットが立っていると次のバイトを読むなどのルールで可変長になっていることがあります。 time()はすでに4バイト使っていますし、一番作りやすいので1という方針を取りました。 > また、データとタイムスタンプとkey変数を、先日伺ったhash_hamacで"sha256"アルゴリズムで送るデータとタイムスタンプをハッシュする。 このハッシュ値が改ざんを検出するための署名です。 あるいは、MAC (メッセージ認証符号)です。 ハッシュ値を計算される値にタイムスタンプを含めている理由はタイムスタンプに対する改ざんを検出するためです。 > その後、finger_print変数とタイムスタンプとhmacではッシュしたデータを組み合わせて、base64_encodeでエンコードし、返り値とする。 > base64_encodeする理由は、簡単に内容を読まれないようにするため。 違います。ブラウザの誤動作を防ぐためです。 Base64でエンコードされたデータなんて見る人が見たらそのパターンから一発でわかります。 Base64を使うのは、一般にバイナリデータをアルファベットなど表示可能な文字列に変換するためです。 finger print、タイムスタンプ、hmac値にどのようなデータが来るかはやってみるまでわかりません。 例えば、よってその中に表示すると"や<、>\などになるデータが出てきて、それをそのまま表示した場合、ブラウザはそれを字面通り解釈する可能性があります。その状況を防ぐためにBase64をかけてそれらの文字が出てこないようにします。あるいは、それ以外にも表示不可能な文字がHTMLで出てきた場合に、それを勝手にスクリプトだと思って実行したり、その文字コードを無理やり予測して画面の表示をしようとしたり、その文字を制御コードだとして動作したりするなどの状況も予測されます。これを防ぐためのBase64エンコードです。 送るデータをserializeした上でBase64エンコードするのも同じ理由です。 なお、送るデータ量が多すぎると感じる場合は送受信する前にgzencode、gzdecodeしてからBase64 encode/decodeしてもよいでしょう。 > [受信側] > TimeoutVerifierクラスでコンストラクタはTimeoutSignerクラスと同じ内容を行う。 (snip) > まず初めに、finger_print変数を比較する。 > 内容の相違があれば終了 これは署名を作った鍵と同じ鍵で検証しようとしているか確認しています。 finger_printが違うということは署名を作った鍵と違う鍵がTimeoutVerifierに設定されているということなので終了します。署名を作った鍵と違う鍵で検証しても無意味ですからね。 なお、複数の検証鍵がある場合は、TimeoutVerifierのオブジェクトを鍵ごとに作っておき、それぞれでverifyを呼び出すことで対応します。 > 取り出したtimestamp変数と現在の時間の差を設定した時間TIMEOUT_DURATION定数と比較してTIMEOUT_DURATIONを超えていれば終了 タイムアウトということでverify失敗と判断します。 タイムアウトはMAC値が一致するか否かにかかわらず判断されるので、true/falseの代わりにエラーの理由を返すようにプログラムを書き換えた場合は注意が必要です。 (snip) > といった流れになると思います。 > 以上の解釈で大凡のズレはないでしょうか? ブラウザでのトラブルを減らすために行ったエンコードを難読化だと誤解しているところは間違っていますが、流れはそれで合ってます。プログラムのコメントとしては流れをそのまま書くよりは、「なぜそれを行うか?」を書いたほうが良いと思いますが。 もう一度言いますが、難読化はセキュリティに全く寄与しません。もちろん、別の目的を達成したら結果的に難読化されてしまったということはあります。packは署名のデータを送りやすくするためですし、Base64エンコードはブラウザの誤動作を防ぐために行なっています。機密性を保ちたい場合はhttp://www.php.net/manual/ja/function.mcrypt-encrypt.php (推奨)かhttp://pear.php.net/package/Crypt_Blowfish でも使うとよいでしょう。

すると、全ての回答が全文表示されます。
回答No.4

> この部分ですが、hmacのハッシュする部分にタイムスタンプを入れると言うことでしょうか? そのとおりです。 一点確認しておきますが、タイムスタンプはそのデータが生成された時刻を示す値であって、現在時刻ではありません。よって、ここでのタイムスタンプとはサイトAからサイトEに転送するデータの電子署名が作成された時刻のことを指します。 実際の手順としては、電子署名にタイムスタンプを含めておき、そのタイムスタンプを使ってハッシュ値を計算します。また、一定時間以上前のタイムスタンプの場合に検証エラーとすることで、古いタイムスタンプの値を送ってくるのを防ぎます。 > 上記にかんしましても上の部分と共通するかもしれませんが、全ての値を:などで順に連結・・・」ありますが、この部分ももう少し詳しくご教授頂くことは可能でしょうか? #3で他の方が回答されている通り、どんなデータ形式でも良いのですが、自分が提案していたのは:ですべてのデータをつなげるという原始的な方法です。 例えば、合計金額10000円、会員番号 10番などだと10000:10とすれば良いのでは?と言っているに過ぎません。 #3の回答に出てきたJSONでもXMLでも良いですし、PHPということでPHPのserializeでも良いでしょう。(PHPのserializeは何かと問題持ちだといいますが...) と、言葉で言っていても通じにくいところもあると思いますので実際にコードを書いてみました。 データは連想配列の配列をserializeした後にBase64エンコードして、転送が簡単に出来る形式に変換したあとにTimeoutSignerを使って電子署名を計算しています。また、TimeoutVerifierで電子署名の検証もしています。 $key = "abc"; $data = array( 0 => array( 'title' => 'Hamlet', 'category' => 'book', 'price' => '1000', 'unit' => 'yen', 'number' => 1, ), ); $encoded_data = base64_encode(serialize($data)); $signer = new TimeoutSigner($key); $sig = $signer->sign($encoded_data); $verifier = new TimeoutVerifier($key); if ($verifier->verify($encoded_data, $sig)) { $decoded_data = unserialize(base64_decode($encoded_data)); print $decoded_data[0]['title']; } else { print "verify error."; } /** * Signer that sign data with timestamp. * * @package default * @author Hanabutako. */ class TimeoutSigner { const FINGERPRINT_LENGTH = 8; function __construct($key) { $this->key = $key; $this->finger_print = substr(hash("sha256", $key, true), 0, TimeoutSigner::FINGERPRINT_LENGTH); } /** * Sign the data. * * @param string $data to calculate signature. * @return string Base64 encoded signature with timestamp. */ function sign($data) { $timestamp = pack("N", time()); // Calculate hash value with timestamp. $hash_value = hash_hmac("sha256", $timestamp . $data, $this->key, true); $signature = $this->finger_print . $timestamp . $hash_value; return base64_encode($signature); } } /** * Verifier that verifies signature signed by TimeoutSigner. * * @package default * @author Hanabutako. */ class TimeoutVerifier { const TIMEOUT_DURATION = 3600; // 1 hour. function __construct($key) { $this->key = $key; $this->finger_print = substr(hash("sha256", $key, true), 0, TimeoutSigner::FINGERPRINT_LENGTH); } /** * Verify the signature. * * @param string $data to calculate signature. * @param string $b64_signature Base64 encoded signature to be verified. * @return bool true if verified, otherwise false. */ function verify($data, $b64_signature) { $signature = base64_decode($b64_signature); $finger_print = substr($signature, 0, TimeoutSigner::FINGERPRINT_LENGTH); $timestamp = substr($signature, TimeoutSigner::FINGERPRINT_LENGTH, 4); $hash_value = substr($signature, TimeoutSigner::FINGERPRINT_LENGTH + 4); if ($finger_print != $this->finger_print) { return false; } // Check timestamp is not too old. $decoded_timestamp = unpack("N", $timestamp)[1]; if (time() - $decoded_timestamp > TimeoutVerifier::TIMEOUT_DURATION) { return false; } // Verify hash value with timestamp. if (hash_hmac("sha256", $timestamp . $data, $this->key, true) != $hash_value) { return false; } return true; } } このコード自体は、先日の回答で書いたKeyCzarのTimeoutVerifierに着想を得ています。 http://code.google.com/p/keyczar/source/browse/java/code/src/org/keyczar/TimeoutVerifier.java というわけで、HMACを計算する値にタイムスタンプを入れますが、電子署名を送るときにそれをつけて送ります。そして、そのタイムスタンプが古過ぎない場合にのみ、それを使ってHMACを計算します。 すべての値を:でつなげるというのはデータをどう送るかという話ですが、PHPだとserializeが使えるならserializeを使えば良いのではないでしょうか。

yysuruo
質問者

補足

hanabutakoさん 返信が大変遅くなり申し訳ありません。 教えて頂いたコードで、テスト環境で色々試してみました。 はじめに、私の想像を超えた素晴らしい内容で大変勉強になりました。 本当に質問させて頂きよかったです。 ありがとうございます。 誠に図々しいお願いなんですが、自分なりに解釈してみたので、下記私の解釈が違う部分がございましたら、ご指摘頂ければ幸いです。 まず [送り側] TimeoutSignerクラスを使って、変数keyのハッシュを行い、substrで一部分を切り出す。 切り出す文字数のFINGERPRINT_LENGTH定数は任意の数字で構わないが、TimeoutVerifierクラスのコンストラクタで仕様するので同じ値にする必要がある。 そこから、finger_print変数にkeyのハッシュを行い切り出した一部の文字列を入れ、signメソッドで仕様する。 singメソッドはtime()関数で現在のタイムスタンプを取るこの時、pack関数でタイムスタンプをバイナリ文字列にする←簡単にタイムスタンプをわからなくするため。 また、データとタイムスタンプとkey変数を、先日伺ったhash_hamacで"sha256"アルゴリズムで送るデータとタイムスタンプをハッシュする。 その後、finger_print変数とタイムスタンプとhmacではッシュしたデータを組み合わせて、base64_encodeでエンコードし、返り値とする。 base64_encodeする理由は、簡単に内容を読まれないようにするため。 また、送るデータとして、serialize関数でシリアル化を行い、エンコードする。 [受信側] TimeoutVerifierクラスでコンストラクタはTimeoutSignerクラスと同じ内容を行う。 verifyメソッドで送られたきたデータと鍵情報を引数にして、下記情報をデコードし、それぞれの必要なデータを作る まず初めに、finger_print変数を比較する。 内容の相違があれば終了 取り出したtimestamp変数と現在の時間の差を設定した時間TIMEOUT_DURATION定数と比較してTIMEOUT_DURATIONを超えていれば終了 次に、hash_value変数を比較して、内容が違っていれば終了する 以上の鍵を全てクリアすると、戻り値でtrueを返す。 OKの場合はデータをデコードしてunserialize関数で元の値に戻す。 といった流れになると思います。 以上の解釈で大凡のズレはないでしょうか? 私が今回、気付かされたのではデータを渡すと際のデータをいかに予測のつかない値に変えて渡すかと言うことと、その方法が非常に勉強になりました。 長くなってしまいましたが、ありがとうございます。 また、この他にもご回答頂いたみなさまありがとうございました。

すると、全ての回答が全文表示されます。
  • dscripty
  • ベストアンサー率51% (166/325)
回答No.3

[ANo.2]> 日付+時刻も一定時間内であることをチェックします。そうすると、改ざんがあればHMAC値が変わりますし、同じHMAC値を使ったリプレイ攻撃も一定時間以降は無効化されます。 > この部分ですが、hmacのハッシュする部分にタイムスタンプを入れると言うことでしょうか? > しかし、これだと送り側と受け側が一致する事がないように思います。 > できましたら、もう少し詳しくご教授頂けないでしょうか? [ANo.2]> HMACの値はこれ以外のすべての値を:などで順に連結したものをメッセージとして、送り元・送り先で共有した鍵で計算して作ります。 > 上記にかんしましても上の部分と共通するかもしれませんが、全ての値を:などで順に連結・・・」ありますが、この部分ももう少し詳しくご教授頂くことは可能でしょうか? この図を見るとわかりやすいとおもう。 「メッセージ認証符号 - wikipedia.org」 → http://ja.wikipedia.org/wiki/メッセージ認証符号#.E4.BE.8B あくまで、共通鍵を含めた何かのアルゴリズムで、 メッセージから MAC値を算出するだけだから、 メッセージにタイムスタンプを入れても全く問題ないよ? あと、メッセージの中の書式は、カンマ区切りやコロン区切りでもいいし、構造的なデータにしたいなら、JSON でもいいし XML でもいい。 だから、質問者さんが使いやすい書式で!

すると、全ての回答が全文表示されます。
回答No.2

この条件だけで思いつく攻撃は2つ。 1. ABCサイトからEサイトへの情報伝達の際の商品データの改ざん 2. EサイトへのXSRF攻撃で、購入するつもりがないものを購入させられる。 前回の説明でどういうリスクがあるのかあまり理解していないように見えるので、具体的なシナリオを書きますね。 悪意のあるユーザーが掃除機 1万円 1台、紙パック 1,000円 3組をサイトAで購入します。 決済でサイトEに飛ぶ前にブラウザのHTMLエディターでhidden値を書き換え、掃除機 9,000円、紙パック 800円に変更し、合計値も13,000円から11,240円に変更します。サイトEに飛ぶと、11,240円として請求書が出されます。 まぁ、ありえない金額ではないので11,240円払われたのを確認した時点で発送。まんまと1,760円安く買われてしまうわけです。 XSRF攻撃のシナリオは、「お前の家にピザ注文してやる!」というのに近いですね。 xmlhttprequest (XHR)を使えばPOSTでデータを投げるのは簡単に出来ますから、上記の決済でPOST送信されるものと同じものがサイトEに送られるようにしたサイトを作ります。 様々なところで宣伝して、そのページに人を誘導します。 すると、一人訪れるたびに注文がサイトEに送られます。 業務妨害しつつ、注文先として使われた人にも迷惑をかける嫌がらせができてしまいます。 1の防御方法は先の質問の答にある通り2種類あって、ひとつはユーザーにデータを運ばせる時にそのデータに電子署名を付ける方法で、もう一つはサーバー間で直接情報の受け渡しをする方法です。 2の防御方法は、サーバー間で通信して確認するか、サーバーEで認証させるという方法が良いでしょう。認証が通った場合のみ注文を受け付けます。 > この理由はなぜでしょうか? 先に書いた通り、料金データなどを改ざんできなくするためだと思います。 例えば、Aサイトで商品を100円で売っていても、Eサイトがそのことを確認できなければ、10円に書き換えられてもそれで決済が通ってしまいます。 Eサイトに商品データがあれば、個数のデータだけを送ると値段が必然的に決まりますから、個数データを送るだけになり、改ざんの意味がなくなります。例えば、改ざんで10個を1個にされた場合、1個の購入として扱えばよいだけなので、店舗は損しません。 クレジット決済であろうがなかろうが改ざんされた値段で支払い確認となる問題は変わりません。むしろ、クレジット決済だと人手を介さずに決済まで出来るのでこの手の攻撃に気づきにくいかもしれません。 要は、#1さんがおっしゃっている通り、 > POSTで送信する情報は > ユーザが改竄できる。 ということです。 先の質問の回答で既に出ていますが、防ぎ方は、次の2つです。 1. 改ざんを検出できるようにする (先の質問の#1の解法) 2. 改ざんの可能性があるところでセンシティブなデータの授受をしない。 2の場合、サイトABCからサイトEに同一人物が来たことを示すための文字列 (トークン) を渡すことになりますが、このトークンは類推しにくいものにしなくてはなりません。例えば下記の方法でurandomから乱数値を32文字くらい取ったものをbase64 encodeするなどすればよいでしょう。 http://www.php.net/manual/en/function.mt-rand.php#105587 urandomが使えない場合はmt_randomの値を幾つか連結してsha256を計算してトークンにするとよいでしょう。類推できると他人になりすましたアクセスを許してしまいますからね。

yysuruo
質問者

補足

hanabutakoさん いつもご返信ありがとうございます。 前回のご回答の理解が浅かったようですみません。 現在のところ頂いている解決策 1、ユーザーにデータを運ばせる時にそのデータに電子署名を付ける方法 2、サーバー間で直接情報の受け渡しをする方法 色々検討したのですが、1の方法で考えていきたいと思っています。 そこで、質問なんですが1の方法で、前回の質問の時に頂いた >+ 鍵のIDなど (*後述) >+ HMAC値 (*後述) の件なんですが、PHPで制作を考えているので、hmacに関して色々調べてみました。 そこで、phpの関数でhash_hmacと言う関数に注目しています。 http://php.net/manual/ja/function.hash-hmac.php 上記関数の理解としては、hash_hmac(アルゴリズムの選択,ハッシュするメッセージ,共通KEY)と言う引数を使い、送信側と受け側で共通のKEYを使い送信側からpostされたhmac値と受け側で出力したhmac値が同じかどうかを見ると言うことだと思うのですが、理解できない部分があります。 前回頂いた回答で >日付+時刻も一定時間内であることをチェックします。そうすると、改ざんがあればHMAC値が変わりますし、同じHMAC値を使ったリプレイ攻撃も一定時間以降は無効化されます。 この部分ですが、hmacのハッシュする部分にタイムスタンプを入れると言うことでしょうか? しかし、これだと送り側と受け側が一致する事がないように思います。 できましたら、もう少し詳しくご教授頂けないでしょうか? >HMACの値はこれ以外のすべての値を:などで順に連結したものをメッセージとして、送り元・送り先で共有した鍵で計算して作ります。 上記にかんしましても上の部分と共通するかもしれませんが、全ての値を:などで順に連結・・・」ありますが、この部分ももう少し詳しくご教授頂くことは可能でしょうか? お手数をお掛けして申し訳ありませんが、どうぞ宜しくお願いします。

すると、全ての回答が全文表示されます。
  • dscripty
  • ベストアンサー率51% (166/325)
回答No.1

いま、質問者さんに必要なのは、 POSTで送信する情報は ユーザが改竄できる。 ということを知ることだとおもう。

yysuruo
質問者

お礼

dscriptyさん お返事ありがとうございます。 PSOT値は改竄が可能であると言う事は知っているのですが、前回の質問や上の回答者様が答えて頂いている内容で、改竄の対策ができたとして、何か考えられるリスクをお聞きしたかったのです。 私の質問が言葉足りずでした。 ご返信ありがとうございました。

すると、全ての回答が全文表示されます。

関連するQ&A