search
LoginSignup
2

posted at

updated at

Laravelのクロスサイトスクリプト(XSS)対策

LaravelのXSS対策で意識することをまとめます。

要点

1、htmlのタグ内ではダブルクオテーションで囲う
<input value="{{ $text }}">

2、フロントに文字列を渡す時は、htmlspecialcharsでサニタイズする

htmlのタグ内ではダブルクオテーションで囲う

ダブルクオテーションで囲わないと予期せぬ属性が追加されてしまう。

実行例

TestController.php
class TestController extends Controller
{
    public function index()
    {
        $text = "test onclick=alert(1);";  
        return view('tests.test', compact('text'));
    }
}
test.blade.php
<input type="text" value="{{$text}}">  {{-- 正しい --}}
<br>
<br>
<input type="text" value={{$text}}> {{-- 誤り --}}

結果

クオテーションで囲まない方はonclick属性が追加できてしまった。
無題のプレゼンテーション.png

フロントの言語に変数を渡す時は、htmlspecialchars関数でサニタイズする

実行例

ボタンを押下したらlogが出力される機能を作成

{{-- ボタン(onclick属性) --}}
<button onclick="test({{$text}})">ボタン</button>

{{-- js --}}
<script>
 function test(text){
   console.log(text);
 }
</script>

渡すテキスト
$text = "test' onclick=alert(1);";
・シングルクオートあり
・()あり

出力されたログ

エラー
Uncaught SyntaxError: missing ) after argument list (at

修正例

{{-- シングルクオテーションで囲むことで()が文字列として扱われる --}}
{{-- さらにhtmlspecialchars関数でシングルクオテーションをサニタイズする --}}
<button onclick="test('{{htmlspecialchars($text,3)}}')">ボタン</button>

出力結果

test&#039; onclick=alert(1);

サニタイズする前の文字列を表示したい場合はjs側で処理する必要あり。
今回は範囲外とします。

追加

別パターン:json形式で渡す

blade.html
<button onclick="test2( {{ json_encode(['text' => $text], JSON_HEX_TAG | JSON_HEX_AMP) }} )">ボタン</button>
script.js
 function test2(text){
  console.log(text.text);
 }

出力結果

test' onclick=alert(1);
渡したテキストがそのまま取れました。これが一番良さそうです。
上司が教えてくれました。感謝。

他にもっと有効な方法があれば是非教えてください。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
2