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

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

新規登録して質問してみよう
ただいま回答率
85.48%
セキュリティー

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

PHP

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

XSS

XSS【クロスサイトスクリプティング】は、 ソフトウェアのセキュリティホールの一つで、Webサイトに脆弱性が あることからその脆弱性を利用し攻撃する手法です。 主に、入力フォームなどから悪意あるスクリプトを挿入し 該当ページを閲覧したブラウザ上でそのスクリプトを実行します。

CSRF

クロスサイトリクエストフォージェリ (Cross site request forgeries、CSRF)は、 外部Webページから、HTTPリクエストによって、 Webサイトの機能の一部が実行されてしまうWWWにおける攻撃手法です。

Q&A

解決済

5回答

2860閲覧

PHPのセキュリティに関する関数

gsuisk

総合スコア72

セキュリティー

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

PHP

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

XSS

XSS【クロスサイトスクリプティング】は、 ソフトウェアのセキュリティホールの一つで、Webサイトに脆弱性が あることからその脆弱性を利用し攻撃する手法です。 主に、入力フォームなどから悪意あるスクリプトを挿入し 該当ページを閲覧したブラウザ上でそのスクリプトを実行します。

CSRF

クロスサイトリクエストフォージェリ (Cross site request forgeries、CSRF)は、 外部Webページから、HTTPリクエストによって、 Webサイトの機能の一部が実行されてしまうWWWにおける攻撃手法です。

0グッド

2クリップ

投稿2017/11/02 12:00

編集2017/11/06 14:51

PHPでセキュリティ対策の便利な関数があれば是非教えていただきたいです。

一応自分でも作成したのでアドバイス頂けると幸いです。

XSS対策

function escape($data){ if (is_array($data)){ return array_map(__METHOD__, $data); } else { return htmlspecialchars($data, ENT_QUOTES, 'UTF-8'); } }

CSRF対策(トークンの作成とトークンのチェック)

HTML

1<input type="hidden" name="token" value="<?php echo $_SESSION['token']; ?>">

※上記のようにPOSTします。

//トークンの作成 function setToken(){ $bytes=openssl_random_pseudo_bytes(16); $token=bin2hex($bytes); $_SESSION['token']=$token; }
//トークンのチェック function checkToken(){ if(!(hash_equals($_SESSION['token'],$_POST['token'])) || empty($_SESSION['token'])){ exit(); } }

文字コード検証

function checkEncoding(array $data){ $result = true; foreach ($data as $key => $value) { if (is_array($value)){ $value = implode("", $value); } if (!mb_check_encoding($value)){ $result = false; break; } } return $result; }

修正すべき点や他に便利なユーザー定義関数があれば教えてください。
よろしくお願いします。

_____________________________________

以下追記。

HTML

1<input type="hidden" name="token" 2value="<?php echo htmlspecialchars($_SESSION['token'], ENT_QUOTES, 'UTF-8'); ?>">

トークン生成

function setToken(){ if(session_status() === PHP_SESSION_ACTIVE){ return; } $bytes=openssl_random_pseudo_bytes(16); $token=bin2hex($bytes); $_SESSION['token']=$token; }

トークンチェック

function checkToken(){ if(empty($_SESSION['token']) || empty($_POST['token']) || !(hash_equals($_SESSION['token'],$_POST['token']))) { exit(); } }

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

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

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

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

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

guest

回答5

0

下手に関数を作成するぐらいであれば、フレームワークを使用するほうが安全です。

投稿2017/11/02 12:10

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

yambejp

2017/11/02 12:20

まさにこれ
gsuisk

2017/11/02 14:05

ありがとうございます。 PHPの勉強も兼ねて生のPHPで簡単なWebアプリを作成しているのですが、実際に公開するならば小規模なサイトでもLaravel等のフレームワークを利用したほうが良いでしょうか?
退会済みユーザー

退会済みユーザー

2017/11/02 19:50

セキュリティ的な観点で見るとフレームワークを使用したほうが良いです。
gsuisk

2017/11/04 06:49

わかりました。フレームワークの勉強も視野に入れようと思います。 ありがとうございました。
退会済みユーザー

退会済みユーザー

2017/11/07 09:37

この回答にマイナスが付くことがあるとは思わなかった^^;
退会済みユーザー

退会済みユーザー

2017/11/08 01:34

またマイナスが増えてるなぁ^^; 質問者と ockeghem さんとのやり取り見るだけでも、自作関数ってしんどいってわかると思うんだけど。。。 マイナス入れた人、コメントよろしく!
guest

0

ベストアンサー

XSS対策用のescape関数はどのような利用を想定しているのでしょうか?
配列を受け取って、まとめてエスケープしてもうまく使えないような気がします。なぜなら、HTMLのエスケープは、表示のタイミングで行うべきだからです。これだと、$_GETや$_POSTを予めまとめてエスケープするのかなと思えてしまいますが、そのような方法は推奨されません。アプリケーションの中では、エスケープしない生の値を用いるべきだからです。
また、フレームワークを用いるべきというte2jiさんのコメントに同意いたします。

投稿2017/11/02 14:06

ockeghem

総合スコア11701

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

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

gsuisk

2017/11/04 06:46

XSS対策用の関数については入門書に書いてあるのを使いました。配列の場合は値を順にエスケープさせる仕様のようです。 HTMLのエスケープは、表示のタイミングで行うべきで、アプリケーションの中では、エスケープしない生の値を用いるべきなのですね。とても参考になります。 ありがとうございました。
ockeghem

2017/11/04 07:00

PHP入門書では、入力値を最初に全部HTMLエスケープしてしまうものが多いですね。それは推奨されない方法ですので、真似しない方がよいと思います。
gsuisk

2017/11/06 14:04

ありがとうございます! トークンの作成とチェックに関する関数は問題ないでしょうか?もしよければアドバイス頂きたいです。
ockeghem

2017/11/06 14:21

いくつか問題がありますね。 (1) トークン表示には htmlspecialcharsを通した方がよいと思います。現状はトークンは16進数なのでエスケープが必要な文字は含まれませんが、将来それは変わるかもしれないし、エスケープ処理がないと局所的にXSS脆弱性があるように見えるのは気持ち悪いです (2) 現状は毎回異なるトークンをセッション変数にセットしていますが、これだとマルチタブで同時に画面を表示した際に動作がおかしくなります。既にセッション変数にトークンがセットされている場合にはトークンを上書きしないようにするか、複数のトークンを保持して、使ったものから順に消し込みするかいずれかの処理が望ましいです (3) emptyのチェックがhash_equals()の後にありますが、前の方がよいです。そうしないと、値がnullの場合に警告が出ます。emptyのチェックが先だと警告は出ません。その意味では$_POSTの方もemptyチェックした方がよいでしょう
gsuisk

2017/11/06 14:53

ご丁寧にありがとうございます! 追記でコードを書いてみたので見ていただけたら幸いです。
ockeghem

2017/11/06 21:30

見ましたが、(1)と(3)は良いと思います。(2)はこれでは駄目ですね。動かしてみましたか?
gsuisk

2017/11/07 13:15

ありがとうございます。 確かにマルチタブの状態でPOSTすると不正なPOSTと認識されてしまいました... (2)に関してですが、トークンを上書きしないようにするには session_status() === PHP_SESSION_ACTIVE 、つまりセッションが有効で、かつセッションが存在する場合はトークンを上書きしないようにreturnし、そうでなければトークンを設定するというのは見当違いでしょうか...(汗) 固定トークンにしたほうが良いでしょうか? またトークンは $_SESSION['token'] よりも session_id() に保存したほうが良いでしょうか? <input type="hidden" name="token" value="<?php echo htmlspecialchars(session_id(), ENT_COMPAT, 'UTF-8'); ?>"> //遷移先でのチェック session_start(); if(session_id() !== $_POST['token']){ die('不正なPOSTです'); } このような感じです。 何度も本当にすみません。ご教示いただけたら幸いです。
ockeghem

2017/11/07 13:22

そうですね。hash_equals()により比較した方がよいとは思いますが、=== による比較でも実害はないと思いますので、許容範囲かと思います。
gsuisk

2017/11/07 14:02

ありがとうございます。上記の記事を参考にして、 $success = hash_equals(self::generate(), $token); //このようにhash_equals()を利用する。 value="<? echo htmlspecialchars(CsrfValidator::generate(), ENT_QUOTES, 'UTF-8');?>" //このようにトークン表示には htmlspecialcharsを通す。 としました。 細かいことまで教えていただきありがとうございました!
gsuisk

2017/11/07 14:24

value="<? echo htmlspecialchars(CsrfValidator::generate(), ENT_QUOTES, 'UTF-8');?>" とすると動作しませんでした。この場合は value="<?=CsrfValidator::generate()?>" でないとダメみたいです。原因を考えてみます... 念のため報告させていただきました。
ockeghem

2017/11/07 14:37

value="<?php echo htmlspecialchars(CsrfValidator::generate(), ENT_QUOTES, 'UTF-8');?>" あるいは value="<?= htmlspecialchars(CsrfValidator::generate(), ENT_QUOTES, 'UTF-8');?>" でうまくいきませんか?
gsuisk

2017/11/07 14:49

すみません、おっしゃる通りタグ記述ミスでした。正常に動作しました。 マルチタブで同時に二つPOSTした場合は問題なくPOSTされ、別に用意したページのフォームからPOSTするとCSRF validation failed. と表示され期待通りの動作が確認できました。
gsuisk

2017/11/07 14:50

親切に本当にありがとうございました。
guest

0

基本的には

  • htmlspecialchars
  • urlencode
  • filter_input

を利用すること
またなるべくclassを利用した上で、変数の取扱をセッタ/ゲッタで行いカプセル化すること
DBへのアクセスが必要な場合は「PDO + prepare処理」で行うことこと

投稿2017/11/02 12:17

編集2017/11/02 12:20
yambejp

総合スコア114769

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

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

gsuisk

2017/11/04 06:49

基本的な注意点を教えていただきありがとうございます。参考にさせていただきます。
guest

0

CSRFはブラウザの履歴などから該当URLにアクセスした際や、
別のどこかページから誤ってリンクが貼られている場合など、
不正アクセスの意図が無いユーザーも排除してしまう可能性があります。

checkToken() 関数内で exit() してますが、
これですとなんのエラー表示もなしに画面が真っ白になってしまって
ユーザは何が起こっているかわからず混乱するでしょう。
少なくともexit前にログにエラーを残す処理を加えて無いと、
システム管理者もログに何もエラーが残っていないため、
サイト内のどこかのページで誤ってリンクが貼られてあったとしても
問題に気付くことがないまま放置されることになります。

関数内でexit()をするのは極力避けて、return falseなど返して呼び出し側でなんとかするか、
または throw new \RuntimeException("CSRF Token mismatch");など例外を投げる形とし、
表示側にtry/catchを入れてそこでユーザに正しい入口の案内をしましょう。

ログに関しては trigger_error()か、error_log() 関数などを調べると良いと思います。

投稿2017/11/07 02:25

TakeoSaki

総合スコア97

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

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

gsuisk

2017/11/07 13:24

ありがとうございます! exit()だけだとユーザーに不親切ということですね。ログは管理者として把握すべきですね。わかりました。 https://qiita.com/mpyw/items/8f8989f8575159ce95fc 例外処理を使うということは上記のようなコードになりますかね?
guest

0

__METHOD__
はクラスのメソッド名を示すものでarray_mapで呼び出した関数を呼び出したい場合は
__METHOD__ ではなく __FUNCTION__ と書かないと適用されません。

書式指定式でエスケープさせたい場合は以下のようにします。

php

1function escape() 2{ 3 $args = func_get_args(); 4 $text = array_shift($args); 5 $args = array_map('h', $args); 6 return vsprintf($text, $args); 7} 8function h($s) 9{ 10 return htmlspecialchars($s, ENT_QUOTES, "UTF-8"); 11} 12$a = '<b>テスト</b>'; 13<div><?php echo escape("%s", $a); ?>

投稿2017/11/02 15:20

編集2017/11/02 15:27
naohiro19_

総合スコア178

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

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

gsuisk

2017/11/04 06:47

__METHOD__ ではなく __FUNCTION__を使用するのですね。 コードまで載せていただき、ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問