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

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

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

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

セッション

Sessionはクライアントがサーバに送ったすべてのリクエストのことを指します。

Q&A

解決済

2回答

8419閲覧

セッションの安全な管理方法について

yukihiro_

総合スコア30

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

セッション

Sessionはクライアントがサーバに送ったすべてのリクエストのことを指します。

0グッド

11クリップ

投稿2017/02/19 09:23

ログイン認証無しの一般的なメールフォーム等の入力、確認、完了ページをセッションで管理する場合についてお聞きしたいので教えていただけないでしょうか。

セッションIDの保存にクッキーを使用しているのですが、

1 どのタイミングでセッションを再生成すればよいか。

現在は入力フォームに入った段階で、セッションスタート後すぐにsession_regenerate_idをしています。
その後、リロードした場合や確認ページから入力内容の編集で戻ってきた場合に指定秒経過ごとに再度session_regenerate_idをしています

2 セッションクッキーのタイムアウトについて

入力ページで決めうちでsession_set_cookie_paramsを使用し、expire属性に例えば3600(1時間)と設定するのが良いのか、もしくは、setcookieでページ遍移ごとに有効期限をリセットして延長する方法が良いのか、どちらが良いのか疑問です。

また、セッションクッキーには時間を設定せずに「 0(ゼロ) 」にした方がクッキーをクライアントのメモリのみに保存するので安全にも思います。

どうか、ご教授いただけないでしょうか。

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

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

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

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

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

ikedas

2017/02/20 07:17

ソースコードで、ご質問で述べておられる処理をしている箇所を示していただいたほうがいいと思います。
guest

回答2

0

ベストアンサー

ご質問のテーマについては、以下の二種類の観点を持つことがよいと考えます。

(a)他に脆弱性がなくても単独で情報漏えい等が発生する脆弱性という観点
(b)他に(クロスサイトスクリプティングなどの)脆弱性がある場合に被害を緩和する観点

まず、(a)に関して言えば、ログインせずに、セッション変数で情報を持ち回りする場合、「ログイン前セッションIDの固定化攻撃」が成立する場合があります。
これは、セッションIDのクッキー(デフォルトではPHPSESSID)の値を外部の攻撃者にセットされた場合、そのセッションIDは攻撃者がわかっているので、セッション変数に値が入ったタイミングで攻撃者がサイトにアクセスすると、入力途中の値を攻撃者に閲覧される可能性がある、というものです。

それでは、セッションIDのクッキーを外部からセットする方法ですが、以下のようなものがあります。

  1. クッキーモンスターバグによる方法(地域型JPドメイン名、都道府県型JPドメイン名を使用していて、IE利用の場合)
  2. HTTPSを使用しているサイトで、通信路上に攻撃者がいる場合

クッキーモンスターバグとは、IEを利用していると、Set-Cookie時に domain=tokyo.jp など広範囲に適用されるクッキーが作れてしまう問題のことです。例えば、東京都のドメイン名は metro.tokyo.jp ですが、地方公共団体以外でも xxxx.tokyo.jp のドメイン名を持つサイトは非常に多いです。(Googleで site:tokyo.jp で検索してみてください)これらのサイト全てで、domain=tokyo.jpのクッキーを発行できる(ただしIEユーザのみ)ので、クッキーの汚染は現実的な問題になります。
HTTPSを利用している場合については下記の記事を参照ください。

HTTPSを使ったほうが危険になるのかと驚かれるかもしれませんが、そうではありません。HTTPSを使っておらず通信路上に攻撃者がいる場合は、クッキーの盗聴も改変も可能ですし、そもそも生の個人情報等も盗聴できるので、こちらは問題外ということになります。それを防ぐためのHTTPSであるわけですが、(クッキーの盗聴は防げるが)クッキーの改変は防げない、という問題です。

さて、ログイン前セッションIDの固定化攻撃を防ぐ確実な方法は、適切なタイミングでセッションIDを変更することです。そして、適切なタイミングを下記に示します。

  • 秘密情報をセッション変数に格納する直前

このタイミングでセッションIDを変更すると、「攻撃者が知っているセッションID」には秘密情報は入らないので、確実な対策になります。
ログインを前提とするサイトの場合は、ログイン確認直後、かつセッション変数にログイン情報をセットする前にセッションIDを変更するべきですが、これも同じ理由です。

し・か・し・な・が・ら、ログインをしないケースでは、上記を実施しているウェブサイトはあまり多くないように見受けます。その理由は、セッションIDの固定化攻撃が成立する条件が厳しいわりに、攻撃により得られる「成果」があまり多くない(ログイン状態を乗っ取れるわけではない)ので、脆弱性を許容していると考えられます。(単に知らないだけという可能性ももちろんあります)。

一方、(b)に関しては、セッションタイムアウトの設定が有効です。こちらは、セッションのexpires指定による方法もありますが、より望ましい方法は、セッション変数として「最終クセス日時」を保存して、アクセスの度に確認することです。こうすれば、クッキーにはexpiresを指定しないため、クッキーがパソコンのファイルに保存されることもなくなります。

投稿2017/02/24 11:38

ockeghem

総合スコア11705

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

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

yukihiro_

2017/02/24 14:34

徳丸さんですよね。。。? 徳丸様直々にご教授いただきましてありがとうございます。 安全なWebアプリケーションの作り方 を拝読させてもらおうと思います、 お答えいただきありがとうございました。
ockeghem

2017/02/24 14:39

はい。徳丸です。 失礼ながら、ベストアンサーは間違っていますよ。
yukihiro_

2017/02/24 15:38

徳丸様の最下部のコメント読みました。 「フォームから入力された値をセッション変数に書き込む直前」ということになります。 入力フォーム時点で新しいセッションIDを発行しても、それからユーザが操作をしている間に、セッションIDのクッキーが変更されてしまう可能性があります。 やはりログイン認証仕様を実装しない場合は、確認ページに入った段階でsession_regenerate_idですね。(入力ページで文字入力→確認ページへの遍移ボタンsubmitでセッションファイルに入力データが書き込まれるため)
guest

0

(2/24 ご質問の1への回答を若干編集しました)
(2/25 コメントを受けてセッション開始の条件を訂正)

まず、参考資料を示します。

これはひと通り読まれるとよいと思います。

要点はいろいろありますが、セッションIDを守ることに絞ると、次の3つにまとめられるようです。

  1. セッションIDの推測に対する対策
  2. セッションIDの奪取に対する対策
  3. セッションIDのお膳立てに対する対策

このうち1.と3.については、PHPのセッション管理機構を使っていれば通常は問題ないでしょう。

また2. については、cookieの使用は効果的です。ただしcookieを使うだけでは十分でなく、通信路の暗号化を必須とする (HTTPSにした上で、cookieにsecure属性をつける) ことや、スクリプトによるアクセスを防ぐ (httponly属性をつける) ことも検討するべきでしょう。

前置きおわり。


1 どのタイミングでセッションを再生成すればよいか。

session_regenerate_id()は、あまり必要ないと思います。

セッション開始時はsession_start()だけでいいです。実装上は、IDを生成するたびにOSの(疑似)乱数生成器を使っているだけなので、あらためてsession_regenerate_id()しても暗号論的な強度は変わりません。

また、セッションの生成と破棄ですが、次の原則を守るべきです。

  • 守りたい通信が開始するときにセッションを開始する。
  • 守りたい通信が終了したら即座にセッションを破棄する。

今回の場合は、入力フォームで最初に入力があった段階でセッションを開始し、送信完了 (または取り消し) 時にセッションを破棄するようにします。

なお、セッションの破棄のしかたについては末尾[1]に補足します。また、今回はログインはしないとのことですが、する場合について[2]に補足します。

次に、セッション中のセッションID再生成について考えます。

上記1. (セッションIDの推測) については、再生成しても特に乱数の強度が上がるとは思えません。また、2. (セッションIDの奪取) に対して効果はありません。対策は上で述べた通り、通信路を守るなどするしかありません。3. (セッションIDのお膳立て) に対しても特に効果はないです。

一方で、次のような場合は問題が発生します。

  • フォームの送信ボタンの2度クリックをしてしまった場合。
  • リンクの2度クリックをしてしまった場合。
  • ページ中に埋め込まれたコンテンツ (画像など) も、セッション管理の対象である場合。

複数回のリクエストがほぼ同時に発行されるため、その間にセッションIDが再生成されると、クライアントが最新のセッションIDを受け取り損ね、セッションが切れてしまう可能性があります。

ですので、上で述べた対策がとられている限り、ログインセッション中にセッションIDを再生成する必要はないと思います。次で述べるセッションクッキーのタイムアウトが設けられていればいいでしょう。

2 セッションクッキーのタイムアウトについて

cookieのタイムアウトの長さは、作ろうとするシステムの仕様次第だと思います。ただし、絶対的なタイムアウトは設けるべきです。

再度アクセスしたときも継続して使いたい情報があるのなら、cookieにタイムアウトを明示的に設定すればいいと思います。そういうものがなければ、cookieにExpire属性やMax-Age属性を設定せず、ブラウザを閉じた時にcookieが消えるようにすればいいと思います。

ただし、cookieのタイムアウト設定はクライアントが正しく処理してくれることが前提なので、サーバ側では絶対的なタイムアウトを設けて、それを過ぎたセッション情報をサーバから消去すべきです。

絶対的なタイムアウトも、仕様に応じて数時間から数日までいろいろでしょう。


[1] セッション破棄のしかたはPHPのマニュアルにも例がありますが、説明を補足しておきます。

$_SESSION = array(); # セッションデータを消す。 $params = session_get_cookie_params(); # cookieを期限切れにして消す。 setcookie(session_name(), '', time() - 42000, $params["path"], $params["domain"], $params["secure"], $params["httponly"] ); session_destroy(); # セッションを破棄する。

まずセッションデータを消しておかないと、セッションを破棄するまでの間にcookieを送り込まれる可能性があります。ですので、厳密にやるのなら上のようになります。

[2] ログインする場合について補足します。

上で述べた原則により、基本的にはログイン成功したときにsession_start()し、ログアウトしたらすぐにsession_destroy()するようにします。

なお、ログイン中以外でもセッションを使っているかもしれませんが、ログイン後に同じセッションを使いまわす (session_regenerate_id()でIDだけ変える) ようにしないほうがいいでしょう。ログインしていない間に攻撃者から情報を注入されたときに、それを信頼してログイン後にも使ってしまうようなコードを書けてしまいます。

投稿2017/02/23 06:01

編集2017/02/25 05:30
ikedas

総合スコア4443

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

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

yukihiro_

2017/02/23 15:05

修正依頼メッセージを送っていただいていたのですね... 回答だけではなく修正依頼が付いた場合もteratailさんで質問者側にメール送信 される仕様となっていれば良いのですが... 大変失礼しました。 セッション管理については、 ・充分な強度でIDを生成する ・セッションIDを保持するクッキー名の変更 ・IDをURLパラメータに付与しない ・secure属性をtrueにして暗号化されたhttps接続のみを信頼する ・httponly属性をtrueにしてJavaScript等のスクリプト言語からアクセスされても参照できない ようにする 等々、色々しなければならないことがありますが、セッション管理については2重3重の対策を した方が良いのではと考えています。 その対策の中で session_regenerate_id でセッションIDを更新することでセッションIDの 固定化攻撃を回避できるものだと認識していました。 1 どのタイミングでセッションを再生成すればよいか。の部分で誤記がありました。    入力ページ session_start()    確認ページ session_start() + session_regenerate_id(true) + トークンチェック    (IDの更新頻度はページ遍移の度にtime()関数を使用して指定秒ごとに更新)   の誤りでした。 2のセッションクッキーに有効期限を持たせることですが、 ブラウザを一度閉じても再アクセス時に入力内容を一定時間保持した仕様が良いのではと考えていましたが、セッション管理にはセッションクッキーに有効期限を持たせるべきではないという記事を見ました。 https://blog.ohgaki.net/session-and-cookie 確かに有効期限をもたせなければセッションクッキーをメモリのみに保存するので安全だとは思うのですが、この記事を見てsession_set_cookie_paramsやsetcookieで有効期限を持たせるのはかなりの悪手なのでは... と感じてしまい、質問させていただきました。 ikedas様、とても丁寧にお答えいただき、また参考資料まで提示していただきありがとうございます。
ikedas

2017/02/24 08:37 編集

わかりにくくなっていたので、回答を少し編集しました。 > セッション管理については2重3重の対策を > した方が良いのではと考えています。 ただ、効果のある対策でないといけないわけで、セッションIDの変更は現実には効果がないと思うのです。かつてHTTPSを使うのが今ほど一般的でなかったころに、セッションIDを隠すことが難しかったために「セッションIDを次々に変えてやれば攻撃者を眩暈できるのではないか」という発想で行われた対策なのだろうと思います。 > その対策の中で session_regenerate_id でセッションIDを更新することでセッションIDの > 固定化攻撃を回避できるものだと認識していました。 少し違うと思います。「セッションIDの付け替え」は、まずそれ以前のセッションを破棄し、新しいセッションを開始することを指すと思います。セッションIDだけ変えるのではないと思います。 IPAの資料では「セッションIDの付け替え」を「ユーザがログインに成功した時点でまったく新しいセッションIDを発行し、それまでのセッションIDを無効にするというもの」と説明しています。今回の場合はログインしないということですので、「送信フォームに入った時点」が「セッション付け替え」のタイミングだと思います。 > ブラウザを一度閉じても再アクセス時に入力内容を一定時間保持した仕様が良いのではと考えていましたが、セッション管理にはセッションクッキーに有効期限を持たせるべきではないという記事を見ました。 必要ない情報は持たないのが一番です。情報流出を避けるため、情報を保存しなくていいのならしないにこしたことはありません。そういう意味でその記事は正しいです。 一方で、実はセッションの情報はサーバ側に保存されているので (クライアントに保存されるのはセッションIDだけ)、クライアントでクッキーの情報を削除するようにしただけでは十分ではないです。サーバに保存する情報にこそ期限をつけるべきです。 逆に言うと、ちゃんとセッションの情報が消えるように対策されているのなら、必要に応じてクッキーに有効期限を設定してもかまわないです。
yukihiro_

2017/02/24 15:55 編集

ikedas 様 編集して頂いたり、今回も親切にご教授いただきありがとうございます。 提供していただいた参考資料や他の資料も改めて読み直してみました。 確かにIDの振り直しをするならばセッションファイルに入力データが書き込まれる前(入力フォームに 入ってきた時点で振り直し)ですね。 さらに絶対的タイムアウトやセッションクッキーのExpire属性付与に関しても今回も親切に ご教授いただき、重ね重ね御礼申し上げます。
ockeghem

2017/02/24 14:38

> IPAの資料では「セッションIDの付け替え」を「ユーザがログインに成功した時点でまったく新しい > セッションIDを発行し、それまでのセッションIDを無効にするというもの」と説明しています。今回 > の場合はログインしないということですので、「送信フォームに入った時点」が「セッション付け替え」 > のタイミングだと思います。 これは間違いです。「ユーザがログインに> 成功した時点でまったく新しいセッションIDを発行」というのは、そのタイミングがログイン情報をセッション変数に書き込むタイミングだからです。 ログインがない場合は、入力フォームに入った時点ではなく、「フォームから入力された値をセッション変数に書き込む直前」ということになります。 入力フォーム時点で新しいセッションIDを発行しても、それからユーザが操作をしている間に、セッションIDのクッキーが変更されてしまう可能性があります。
ikedas

2017/02/24 20:56 編集

> ログインがない場合は、入力フォームに入った時点ではなく、「フォームから入力された値をセッション変数に書き込む直前」ということになります。 > 入力フォーム時点で新しいセッションIDを発行しても、それからユーザが操作をしている間に、セッションIDのクッキーが変更されてしまう可能性があります。 そうでしょうか。この場合、セッションが必要なのは、確認画面や取り消し画面、再編集画面への遷移があるので、入力を保持するためでは。「セッション変数に書き込む」タイミングは1回ではないです。
ikedas

2017/02/25 05:41 編集

ああ、そうか。たしかに、新しいセッション (セッションIDではなく) を生成するのは「最初に入力フォームから入力があったとき」ですね。その後、入力画面に再び遷移したときにどうするかは、アプリの仕様次第 (入力ずみとしてもいいでしょうし、セッション破棄してもいい) ということですね。 ちょっと修正しておきます。 いずれにせよ、セッションIDだけ変える (サーバのセッションデータストアは変えない) ということは避けたほうがよいと思うので、session_regenerate_id()の出る幕はないですね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問