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

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

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

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

Q&A

解決済

3回答

2094閲覧

PHPで文字列置換のXSS

ryusan_012

総合スコア59

PHP

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

0グッド

0クリップ

投稿2018/06/27 23:44

編集2018/06/28 02:50

PHPで文字列置換をやっています。
入力ページから送られてきた「文、変更する文字列、変更後の文字列」を表示する画面で置換をして、表示します。

input.PHP

1<!DOCTYPE html> 2<html lang="ja"> 3 4 <head> 5 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 6 <title>入力</title> 7 </head> 8 9 <body> 10 <h2>入力画面</h2> 11 12 <form method="post" action="chara_result.php"> 13 <table> 14 <tr> 15 <td valign="top">文</td> 16 <td><textarea name="change"></textarea></td> 17 </tr> 18 <tr> 19 <td>変更文字列</td> 20 <td><input type="text" name="change_before" value="" /></td> 21 </tr> 22 <tr> 23 <td>変更後文字列</td> 24 <td><input type="text" name="change_after" value="" /></td> 25 </tr> 26 </table> 27 <input type="submit" name="check" value="変更" /> 28 </form> 29 </body> 30</html> 31

置換して表示される文の変更された箇所だけ色をつけて表示したいのですがXSS対策もいれてますのでうまく表示されません

output.php

1<?php 2 if (isset($_POST["change"])) { 3 $write = $_POST["change"]; 4 $write_before = $_POST["change_before"]; 5 $write_after = $_POST["change_after"]; 6 7 //CRLFを改行1文字にする 8 $write = str_replace("\r\n", "\n", $write); 9 10 //未入力チェック 11 if (($write == "")||($write_before == "")||($write_after == "")) { 12 $result = "入力してください。"; 13 //文入力数チェック 14 } elseif (mb_strlen($write, 'utf-8') > 100) { 15 $result = "100文字以内で入力してください。"; 16 //変更後入力数チェック 17 } elseif (mb_strlen($write_before, 'utf-8') > 100) { 18 $result = "100文字以内で入力してください。"; 19 //変更後入力数チェック 20 } elseif (mb_strlen($write_after, 'utf-8') > 100) { 21 $result = "100文字以内で入力してください。"; 22 } else { 23 $after = "<span style='color: #ff0000'>$write_after</span>"; 24 //文字列置換 25 $result = str_replace($write_before, $write_after, $write); 26 } 27 } else { 28 $result = "入力していません。"; 29 } 30?> 31<!DOCTYPE html> 32<html> 33 <head> 34 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 35 <title>結果</title> 36 </head> 37 <body> 38 <h2>結果画面</h2> 39 <table> 40 <tr> 41 <td valign="top">結果</td> 42 <td valign="top"> 43 <?php 44 $result = htmlspecialchars($result, ENT_QUOTES, "UTF-8"); 45 echo nl2br($result); 46 ?> 47 </td> 48 </tr> 49 </table> 50 <a href="chara_input.php">入力画面へ</a> 51 </body> 52</html>

htmlspecialcharsでエスケープされる[<>"&]など変更するとき変換語[< &gt &quot &]ではなく記号のまま変換でき、、尚且つ表示時に変更された文字の色を変えたい。
上のプログラムだと表示されるのが色変更のコードも表示されます
ヒントでもいいのでお願いします

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

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

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

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

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

guest

回答3

0

$after = "<span style='color: #ff0000'>$write_after</span>"; //文字列置換 $result = str_replace($write_before, $write_after, $write);

上記のstr_replaceのところ

$result = str_replace($write_before, $after, $write);

ではないでしょうか?

それはさておき、質問は「ユーザが入力した「文、変更する文字列、変更後の文字列」をXSS対策としてhtmlspecialchars()でエスケープして表示したい、変更後の文字列は色付けしたいのでspanタグで囲みたい、そうすると色付け用のspanタグの<>や'までエスケープされてspanタグがそのまま表示されてる。。どうしよう?」という意図と思いましたがどうでしょうか?

であれば、htmlspecialchars()のエスケープ処理を最初に持ってくればよいと思います。
文字数が問題なければエスケープ処理をして、その後に色付けspanタグの追加処理を行いましょう。

$write = htmlspecialchars($_POST["change"], ENT_QUOTES, "UTF-8"); $write_before = htmlspecialchars($_POST["change_before"], ENT_QUOTES, "UTF-8"); $write_after = htmlspecialchars($_POST["change_after"], ENT_QUOTES, "UTF-8"); //以降置換処理~

エスケープ後の文字列でもstr_replace()での置換は正常に動作すると思います。問題あればまた質問下さい。

投稿2018/06/28 02:45

編集2018/06/28 02:50
SE-studying-now

総合スコア351

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

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

ryusan_012

2018/06/28 05:46

回答にあるPOSTのプログラムですがそれは文字数チェックのあとに書くプログラムですか? そうなると文字数を確認できないような気がしますが
SE-studying-now

2018/06/28 08:22

$_POSTの値は何度でも参照可能です。 チェック後のelse内で$afterに値を設定する前に呼び出して下さい。 $_POSTの値を何度も参照するのに問題があれば、チェック後のelse内で$afterに値を設定する前に各値を以下のようにエスケープしてあげて下さい。$writeのみ例を書きます。  $write = htmlspecialchars($write, ENT_QUOTES, "UTF-8"); 上記対応したコードを実際に動かしてみて下さい。 動かして問題があればまた質問下さいね。
ryusan_012

2018/06/29 03:01

ありがとうございました 何とか理解して動かせれるようになりました
guest

0

ヒントや回答では無いですが、コメントと処理内容が合ってない気が・・・

//改行を空白1文字にする
$write = str_replace("\r\n", "\n", $write);

↑ 改行コードCRLFを空白1文字ではなくLFにしてるのでは?

投稿2018/06/28 00:17

SakuBlade

総合スコア375

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

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

ryusan_012

2018/06/28 01:21

申し訳ないです、修正します
guest

0

ベストアンサー

※修正しました

ヒント:
先にhtmlspecialchars()

投稿2018/06/28 00:02

編集2018/06/28 00:12
m.ts10806

総合スコア80850

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

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

m.ts10806

2018/06/28 00:23

補足: 今回の例については一番最後の出力時にhtmlspecialchars()をする必要はありません。 なぜならXSS対策はユーザからの入力によって入れ込まれるものなので、 プログラム上で入れ込まれる出力用記述については開発者側がコントロールできるものだからです。 ※DBからの取得値などは同様に取得時点でhtmlspecialchars()をしておきます
ryusan_012

2018/06/28 01:26

もし特殊文字を置換する場合だとはじめにエスケープしてもいけますか?
m.ts10806

2018/06/28 01:38 編集

どのような特殊文字を想定しているか分かりませんが、まずやってみてから聞いてください。 もし想定している特殊文字があるのであればそれは要件なので質問に追記してください。 重箱の隅をつつくようで申し訳ないですが、その”特殊文字の置換”がはじめのエスケープでダメなら、 出力時のエスケープでもダメですよね。
ryusan_012

2018/06/28 02:21

もしPOSTで受け取った後にエスケープしますと<なら&lt;って判断して入力数チェックで引っかかります。 表示するときだけエスケープすると問題はないのですが、変更後文字がソースごと出てしまうんです
退会済みユーザー

退会済みユーザー

2018/06/28 02:21

> mts10806 さん > ※DBからの取得値などは同様に取得時点でhtmlspecialchars()をしておきます 読みやすさ/メンテナンス性を考えるのであれば、やはり、表示の直前でエスケープするのが正しいように思います。 今回であれば、エスケープ+置換処理を行う関数を作り、それを表示の直前で適用するのがきれいじゃないかなぁ。。。
m.ts10806

2018/06/28 02:26 編集

ryusan_012さん 入力数チェックは$_POST情報そのままでいいんじゃないでしょうか。 質問時点のコードであっても変数で受けた時点で別のものと捉えます。 te2jiさん 最初は正規表現による置換を考えたんですけども、一番簡単にできそうなのが先にhtmlspecialchars()をすることかなと。 もちろん”エスケープ+置換処理を行う関数”が最適ではありますが、質問者さんにとっては次の段階だと思ってます。
退会済みユーザー

退会済みユーザー

2018/06/28 02:32

※印のところが、一般論にまで言及していたので、ちょっとコメントしたくなりました。 質問者への回答として、関数が適切って指摘ではないです。 横道それちゃってすまんです^^;
m.ts10806

2018/06/28 02:36

私のほうもすみませんでした。実は私のほうはDB取得時にエスケープしていることも多くて(その後のした処理も対応した上ではありますが) 表示に至るまでの置換なり何なりはシステム側の都合と捉えていることもままあります。 そこも要件によりかもしれませんね。
ryusan_012

2018/06/28 02:39

皆様ありがとうございますm(__)m ゆっくりですけど分かるようになっていってるのでこれから使うこともあるかもなんで助かります
ryusan_012

2018/06/29 03:00

ありがとうございました<(_ _)> すごくわかりやすかったです
m.ts10806

2018/06/29 03:19

解決済みとなりましたが、最終的にどのように解決されたのでしょうか?
ryusan_012

2018/06/29 04:45 編集

入力数チェックのあとに一度変更後文字列をエスケープし、それをspanタグで色変更。 そのあとは文字列置換時にまたエスケープ処理をして置換された文字列をさらに色を変更するために置換しました --- $write_change = htmlspecialchars($write_after, ENT_QUOTES, "UTF-8"); //置換後文字列の色を変える $write_after = "<span style='color: #ff0000'>$write_change</span>"; //文字列置換 $write_result = htmlspecialchars(str_replace($write_before, $write_after, $writel), ENT_QUOTES, "UTF-8"); $write_result = str_replace(htmlspecialchars($write_after, ENT_QUOTES, "UTF-8"), $write_after, $write_result); --- ちょっと可読性が悪いとは思いますが…
m.ts10806

2018/06/29 05:12

そうですね まずはきちんと動くコードにすること そのあとは同じ処理を関数にまとめたり大きくなりそうならクラス化したり徐々に調整していけばよいと思います。
ryusan_012

2018/06/29 05:18

細かなところまでありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問