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

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

ただいまの
回答率

88.10%

csrfの対策とSESSIONの持ち方について

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 3
  • VIEW 1,266

score 19

質問失礼します。

ただいま会員システムを自分で作って勉強しております。
会員システムを作る上で気にしないといけないのがセキュリティの問題だと思います。

現在セキュリティの上で気になっているのがcsrfとSESSIONの持ち方です。

csrfを調べた上でこの解釈と対策方法であっているのか教えていただきたいです。

解釈としてはログインする時などユーザーIDとパスワードを入力してログインしますがまずログインページでランダムな文字のトークンを生成する。
それをhiddenで送る。
イメージとしてはユーザーがformのinputで何か入力するページでトークンを生成し、入力した値をチェックするページやinsertするページにトークンチェックのコードを設置すると考えております。
つまりcsrf対策はユーザーが入力した値を受け取る処理があるページ(ログインページや問い合わせフォーム)等で設定しておけばいいと思っているのですがあっていますでしょうか?

下記がトークンの生成コードにまります。

login.php

$_SESSION['token'] = base64_encode(openssl_random_pseudo_bytes(32));
$token = $_SESSION['token'];

次にログイン情報をチェックするページにてhiddenで送られて来たトークンとSESSIONのトークンが一致するか検査。
下記がトークンの検査コードです。
login-check.php

if ($_POST['token'] != $_SESSION['token']){
    $_SESSION['E-message'] = "no-token";
    header("Location: login.php");
    exit();
}

あとは全ページでsession_regenerate_id( true )を記述しています。

また、ログインができればSESSIONにログインしたユーザーid(データベース上で一意なもの)を持ち持ちまわってそのユーザーを特定しているのですがidを持ちまわるのは変でしょうか?
持ちまわるのはSESSIONにidが入っているかいないかでページ上部にログインボタンまたはマイページボタンを表示するために持ちまわっています。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • spcl

    2018/12/22 15:15

    ご指摘ありがとうございます。

    キャンセル

  • MJHSC

    2018/12/22 15:34

    これは非公開の練習目的でしょうか? 本番、公開するサービスでしょうか?

    もし、公開の可能性があるようでしたら、CSRF以外にも考慮すべきセキュリティ要素がありますし、セッション管理を行う外部ライブラリを使うことをおすすめします。

    キャンセル

  • spcl

    2018/12/22 17:33

    最終的には公開目的です。
    他にも考慮するセキュリティはあるのは知っていますがまずはcsrfを知りたいと思う質問させていただいた次第です。

    外部ライブラリについては初めて知った要素になるので調べます!
    アドバイスありがとうございます!

    キャンセル

回答 1

checkベストアンサー

+2

全般的に間違った理解と思われる箇所が多いので、セキュリティの勉強を基礎からやり直されたほうがよいかと思います。

イメージとしてはユーザーがformのinputで何か入力するページでトークンを生成し、入力した値をチェックするページやinsertするページにトークンチェックのコードを設置すると考えております。

違います。
CSRFとは、サーバー上で重要な更新処理などがある場合に行います。たとえば退会処理は入力なしでボタンを押すだけでも実現できますが、そのような場合でもCSRF対策は必要です。入力は関係ありません。

つまりcsrf対策はユーザーが入力した値を受け取る処理があるページ(ログインページや問い合わせフォーム)等で設定しておけばいいと思っているのですがあっていますでしょうか?

違います。
まず、ログインページでは必須ではありません。まだログインしていないからです。
問い合わせフォームは必須ですが、それは入力があるからではなく、問い合わせによりメールが飛んだりデータベースの更新により、問い合わせがあったことによるサイト運営者側のアクションが発生するからです。

下記がトークンの生成コードにまります。

前述のようにログイン処理ではトークンのチェックは必須ではありませんが、実施してもいいでしょう。

次にログイン情報をチェックするページにてhiddenで送られて来たトークンとSESSIONのトークンが一致するか検査。
下記がトークンの検査コードです。

これだと、$_POST['token'] と $_SESSION['token'] がともにNULLの場合にチェックをすりぬけますね。以下の記事を参考にしてください。

問題:間違ったCSRF対策~初級編~
解答:間違ったCSRF対策~初級編~

あとは全ページでsession_regenerate_id( true )を記述しています。

全ページでsession_regenerate_idを呼ぶ必要はありません。これが必要なのは、セッション変数に重要な情報をセットするページのみです。login-check.phpはidをセッションに保存するために必要ですが、それ以外は必須ではありません。全ページでこれをやると、スマホユーザなどがレスポンスをとりこぼすとログインが継続できなくなリます。

また、ログインができればSESSIONにログインしたユーザーid(データベース上で一意なもの)を持ち持ちまわってそのユーザーを特定しているのですがidを持ちまわるのは変でしょうか?

変ではありません。通常のやり方です。

持ちまわるのはSESSIONにidが入っているかいないかでページ上部にログインボタンまたはマイページボタンを表示するために持ちまわっています。

この目的だけであれば、idではなく、ログイン中かどうかのフラグ(falseかtrue)でよいのですが、マイページがあるのであればログインユーザの情報(idや、もし登録してあればメールアドレス等)を表示する必要があるような気もしますがいかがですか?


コメントの後半に対して回答します。

スマホユーザなどがレスポンスをとりこぼすとログインが継続できなくなる。
そんなことがあるんですね。
何故そうなるのか理由を探してみます。

考えてもわからなければ、新しい質問いただけたら回答します。

フラグはどのようなものでしょうか?

フラグとは、false/trueあるいは 0/1 のような値(真偽値や二値といいます)をとる変数のことです。

SESSION['flag']のような形でfalseかtrueをセットするということでしょうか?

それでもいいですし、フラグの意味がわかりやすいように、$_SESSION['is_loggedin'] のような形にすることも多いです。

当方は今SESSIONにidを入れて持ち回り、マイページにようこそ○○さん(ユーザーの名前)や登録情報変更 の際inputのvalueに現在登録されている情報を表示するためにidを持ち回っています。
SQLのWHEREでidで検索するためです。

ということは、単に「SESSIONにidが入っているかいないかでページ上部にログインボタンまたはマイページボタンを表示するために持ちまわっています」というわけではないのですね。回答側は質問文のみが頼りですので、正確に書くようにしましょう。

マイページでユーザーに自身のデータベース上のidや登録しているメールアドレスを表示する理由は何でしょうか?

ユーザー自身が確認するためです。あるいは、「マイページにようこそ○○さん(ユーザーの名前)や登録情報変更 の際inputのvalueに現在登録されている情報を表示するためにidを持ち回っています」と書かれたこともほぼ同じですよね。そのことを指しています。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/12/23 11:36

    ockeghem様

    連休中にもかかわらずご丁寧な回答ありがとうございます。
    どの回答も今までネットで見て勉強したページより分かりやすく鳥肌が立っています。

    >違います。
    >CSRFとは、サーバー上で重要な更新処理などがある場合に行います。たとえば退会処理は入力なしでボタンを押すだけでも実現できますが、そのような場合でもCSRF対策は必要です。入力は関係ありません。
    >違います。
    >まず、ログインページでは必須ではありません。まだログインしていないからです。
    >問い合わせフォームは必須ですが、それは入力があるからではなく、問い合わせによりメールが飛んだりデ>ータベースの更新により、問い合わせがあったことによるサイト運営者側のアクションが発生するからです。

    csrfへの理解はまだ浅いですがcsrfが行われるタイミングを知れたのは大変ありがたいです。


    >これだと、$_POST['token'] と $_SESSION['token'] がともにNULLの場合にチェックをすりぬけますね。以下の記事を参考にしてください。

    $_POST['token'] 、 $_SESSION['token']が共にNULLのことは全く頭になかったです。
    ありがとうございます。


    >全ページでsession_regenerate_idを呼ぶ必要はありません。これが必要なのは、セッション変数に重要な情報をセットするページのみです。login-check.phpはidをセッションに保存するために必要ですが、それ以外は必須ではありません。全ページでこれをやると、スマホユーザなどがレスポンスをとりこぼすとログインが継続できなくなリます。


    スマホユーザなどがレスポンスをとりこぼすとログインが継続できなくなる。
    そんなことがあるんですね。
    何故そうなるのか理由を探してみます。

    >この目的だけであれば、idではなく、ログイン中かどうかのフラグ(falseかtrue)でよいのですが、マイページがあるのであればログインユーザの情報(idや、もし登録してあればメールアドレス等)を表示する必要があるような気もしますがいかがですか?

    なるほどです。
    フラグはどのようなものでしょうか?
    SESSION['flag']のような形でfalseかtrueをセットするということでしょうか?
    当方は今SESSIONにidを入れて持ち回り、マイページにようこそ○○さん(ユーザーの名前)や登録情報変更の際inputのvalueに現在登録されている情報を表示するためにidを持ち回っています。
    SQLのWHEREでidで検索するためです。
    >idや、もし登録してあればメールアドレス等)を表示する必要があるような気もしますがいかがですか?
    マイページでユーザーに自身のデータベース上のidや登録しているメールアドレスを表示する理由は何でしょうか?

    長文になりましたが再度ご回答いただけると幸いです。
    よろしくお願い申し上げます。

    キャンセル

  • 2018/12/26 14:14

    返信遅くなり申し訳ございません。

    度々のご回答まことにありがとうございます。

    >考えてもわからなければ、新しい質問いただけたら回答します。

    ありがとうございます。
    できる限り頼らず自分で調べてみます!

    >単に「SESSIONにidが入っているかいないかでページ上部にログインボタンまたはマイページボタンを表示するために持ちまわっています」というわけではないのですね。回答側は質問文のみが頼りですので、正確に書くようにしましょう。

    かしこまりました。
    最初からidを持ち回る意味もきちんと書いていればよかったですね。
    次回より気をつけます。

    この度は本当に詳しくご教授いただきありがとうございました。
    できるだけ自分で調べ抜きますがどうしても解決できない場合はまたお力添えいただけますと幸いです。

    キャンセル

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

  • ただいまの回答率 88.10%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る