Sinatraのメモアプリの終了条件であるXSS対策について調べました。
結論
文字コード指定とエスケープ(サニタイジング)を行うとXSS対策できる
XSSとは
悪意あるクライアントサイドのコードをウェブサイトに挿入するセキュリティ攻撃です。
引用: Cross-site scripting (クロスサイトスクリプティング) - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN
XSSの簡単な例
入力フォームに直接JavaScriptでスクリプトを埋め込み意図しないアラートを表示させる
- 下記スクリプトを入力フォームに入力し送信
- アクセス時に
XSS!!
がアラートで表示される
<script>alert('XSS!!')</script>
XSSの原因
ユーザ入力が文字列ではなくHTMLタグやJavascriptとして認識されること
XSS対策
- 想定しない文字コードでの埋め込みを防止する: 文字コード指定
- ユーザ入力でのHTMLタグやJavascriptを文字列として認識させる: サニタイジング(エスケープ)
文字コード指定
Content-Typeフィールドで文字コードの指定を省略した場合、攻撃者が、この挙動を悪用して、故意に特定の文字コードをブラウザに選択させるような文字列を埋め込んだ上、その文字コードで解釈した場合にスクリプトのタグとなるような文字列を埋め込む可能性があります。
Content-Typeの出力時にcharsetを省略することなく、必ず指定することが有効です。ウェブアプリケーションがHTML出力時に想定している文字コードを、Content-Typeのcharsetに必ず指定してください。
引用: 安全なウェブサイトの作り方 - 1.5 クロスサイト・スクリプティング:IPA 独立行政法人 情報処理推進機構
Sinatraを使った今回の場合だと全ページ共通で表示に仕様しているlayout.erb
内のhead
タグ内で文字コードをUTF-8
で指定する
<!DOCTYPE html> <html lang="ja"> <head> <mata charset="UTF-8"> <!-- ここで文字コードを指定 --> <title>Memo App</title> <link rel="stylesheet" href="/normarize.css"> <link rel="stylesheet" href="/style.css"> </head> <body> </body> </html>
エスケープ(サニタイジング)
Rubyの標準ライブラリであるcgi
を使ってHTMLタグとJavaScriptを文字列に置換します
require 'cgi' => true string = ['"', "'", '&', '<', '>'] => ["\"", "'", "&", "<", ">"] string.each {|i| puts CGI.escapeHTML(i)} " ' & < > => ["\"", "'", "&", "<", ">"] html = '<p>テキスト</p>' CGI.escapeHTML(html) => "<p>テキスト</p>" script = '<script type="text/javascript">script</script>' CGI.escapeHTML(script) => "<script type="text/javascript">script</script>"
フォーム等の入力部ではなく、ユーザーが入力した文字列の出力部でエスケープすることがポイントです。
まとめ
これまでセキュリティはあまり意識して学習してこなかったが、ちょっとずつ対策を覚えていきたい。
参照
安全なウェブサイトの作り方 - 1.5 クロスサイト・スクリプティング:IPA 独立行政法人 情報処理推進機構