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

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

ただいまの
回答率

90.50%

  • PHP

    20358questions

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

PHPで文字列置換のXSS

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 260

ryusan_012

score 47

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

<!DOCTYPE html>
<html lang="ja">

    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>入力</title>
    </head>

    <body>
        <h2>入力画面</h2>

        <form method="post" action="chara_result.php">
            <table>
                <tr>
                    <td valign="top"></td>
                    <td><textarea name="change"></textarea></td>
                </tr>
                <tr>
                    <td>変更文字列</td>
                    <td><input type="text" name="change_before" value="" /></td>
                </tr>
                <tr>
                    <td>変更後文字列</td>
                    <td><input type="text" name="change_after" value="" /></td>
                </tr>
            </table>
            <input type="submit" name="check" value="変更" />
        </form>
    </body>
</html>


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

<?php
    if (isset($_POST["change"])) {
        $write = $_POST["change"];
        $write_before = $_POST["change_before"];
        $write_after = $_POST["change_after"];

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

        //未入力チェック
        if (($write == "")||($write_before == "")||($write_after == "")) {
            $result = "入力してください。";
        //文入力数チェック
        } elseif (mb_strlen($write, 'utf-8') > 100) {
            $result = "100文字以内で入力してください。";
        //変更後入力数チェック
        } elseif (mb_strlen($write_before, 'utf-8') > 100) {
            $result = "100文字以内で入力してください。";
        //変更後入力数チェック
        } elseif (mb_strlen($write_after, 'utf-8') > 100) {
            $result = "100文字以内で入力してください。";
        } else {
            $after = "<span style='color: #ff0000'>$write_after</span>";
            //文字列置換
            $result = str_replace($write_before, $write_after, $write);
        }
    } else {
        $result = "入力していません。";
    }
?>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>結果</title>
    </head>
    <body>
        <h2>結果画面</h2>    
        <table>
            <tr>
                <td valign="top">結果</td>
                <td valign="top">
                    <?php
                        $result = htmlspecialchars($result, ENT_QUOTES, "UTF-8");
                        echo nl2br($result);
                    ?>
                </td>
            </tr>
        </table>
        <a href="chara_input.php">入力画面へ</a>
    </body>
</html>


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

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 3

checkベストアンサー

+1

※修正しました

ヒント:
先にhtmlspecialchars()

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/06/28 09:23

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

    キャンセル

  • 2018/06/28 10:26

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

    キャンセル

  • 2018/06/28 10:36 編集

    どのような特殊文字を想定しているか分かりませんが、まずやってみてから聞いてください。
    もし想定している特殊文字があるのであればそれは要件なので質問に追記してください。

    重箱の隅をつつくようで申し訳ないですが、その”特殊文字の置換”がはじめのエスケープでダメなら、
    出力時のエスケープでもダメですよね。

    キャンセル

  • 2018/06/28 11:21

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

    キャンセル

  • 2018/06/28 11:21

    > mts10806 さん
    > ※DBからの取得値などは同様に取得時点でhtmlspecialchars()をしておきます

    読みやすさ/メンテナンス性を考えるのであれば、やはり、表示の直前でエスケープするのが正しいように思います。
    今回であれば、エスケープ+置換処理を行う関数を作り、それを表示の直前で適用するのがきれいじゃないかなぁ。。。

    キャンセル

  • 2018/06/28 11:25 編集

    ryusan_012さん
    入力数チェックは$_POST情報そのままでいいんじゃないでしょうか。
    質問時点のコードであっても変数で受けた時点で別のものと捉えます。

    te2jiさん
    最初は正規表現による置換を考えたんですけども、一番簡単にできそうなのが先にhtmlspecialchars()をすることかなと。
    もちろん”エスケープ+置換処理を行う関数”が最適ではありますが、質問者さんにとっては次の段階だと思ってます。

    キャンセル

  • 2018/06/28 11:32

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

    キャンセル

  • 2018/06/28 11:36

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

    キャンセル

  • 2018/06/28 11:39

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

    キャンセル

  • 2018/06/29 12:00

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

    キャンセル

  • 2018/06/29 12:19

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

    キャンセル

  • 2018/06/29 13:32 編集

    入力数チェックのあとに一度変更後文字列をエスケープし、それを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);
    ---
    ちょっと可読性が悪いとは思いますが…

    キャンセル

  • 2018/06/29 14:12

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

    キャンセル

  • 2018/06/29 14:18

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

    キャンセル

+1

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

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

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

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/06/28 10:21

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

    キャンセル

+1

$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 14:46

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

    キャンセル

  • 2018/06/28 17:22

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

    上記対応したコードを実際に動かしてみて下さい。
    動かして問題があればまた質問下さいね。

    キャンセル

  • 2018/06/29 12:01

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

    キャンセル

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

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

関連した質問

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

  • PHP

    20358questions

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