じぶん対策

日々学んだことをアウトプットして備忘録にしています。

XSSとSQLインジェクションについて

XSSとは

Webアプリケーションの脆弱性を利用して行われるサイバー攻撃の1つ。
入力フォームなどに悪質なサイトへ誘導するスクリプトを埋め込みます。
悪質なサイトに誘導されると、ユーザーのブラウザ上で不正なスクリプトが実行されます。
攻撃の種類はマルウェア感染や個人情報の漏えい、フィッシング詐欺などがあります。
もともとのサイトから悪質なサイトへ跨いでスクリプトが実行されるので「クロスサイト」スクリプティングと呼ばれます。

XSSへの対策

XSSは入力フォームなどに直接スクリプトを埋め込んで実行されます。
参考 : https://www.amiya.co.jp/column/cross_site_scripting_20210118.html
対策としては以下のような方法があります。

  • エスケープ処理を行う
  • バリデーション処理によって意図していない文字の入力を制限する
  • 文字数制限によって長いコードの入力を制限することも効果があります。
  • WAF(Web Applicaton FireWall)を設置することも効果的です。

XSSの種類

XSSには以下の3種類がある。
参考: https://www.ipa.go.jp/files/000024726.pdf

non-persistent/Reflected XSS(反射型XSS

Stored/Persistent XSS(格納型/蓄積型/持続型XSS

DOM Based XSS

  • DOMは、「Document Object Model」の略で、HTMLやXMLを取り扱うためのAPIやデータ構造を定義したもの
  • ウェブページに含まれる正規のスクリプトにより、動的にウェブページを操作した結果、意図しないスクリプトをウェブページに出力してしまうタイプのXSS
  • 対策のためには正規のスクリプトを修正する必要がある。

クロスサイトリクエストフォージェリ(CSRF)とは

  • XSSに似たものにクロスサイトリクエストフォージェリ(CRSF)がある。
  • XSSとは違いセッション管理における脆弱性を狙った攻撃。
  • 罠となるサイトにアクセスしてしまうと、ターゲットとなる他のサイトにログイン状態になっていると、ターゲットとなるサイトに偽のリクエストが送信、実行されてしまう。

SQLインジェクションとは

XSSと同じくWebアプリケーションの脆弱性を利用して行われるサイバー攻撃の1つ。 入力フォームからSQL文を生成しているような場合に不正なSQL文を埋め込まれ、データベース内のデータの消去や改ざんを行われる。

SQLインジェクションへの対策

SQLインジェクションも同様に入力フォームなどに不正なSQLを埋め込んで実行されます。
対策として以下のような方法があります。

  • SQL文をプログラム中で作成する際にで特別な意味を持つ記号を素通りしないようエスケープ処理を行う。
  • データベースエンジンによっては安全にSQL文を生成する「バインド機構」やエスケープ処理用にAPIが用意されていたりする。
    • PHPの場合はPDOを用いてDBを操作する手法が主流となっており、bindParambindValueといった関数が用意されています。
    • bindValue
    • bindParam

本当に十分な対策なのか

上記あたりがよくある対策というか、グーグル先生に聞くと真っ先に出てくる情報かなと思います。
もう少しちゃんと調べていくと、このような対策だけでは不十分なようです。
結論から言うと、IPAが以下のサイトで安全なSQLの呼び出し方という資料を配布しています。
かなり信頼が置けそうです。
https://www.ipa.go.jp/security/vuln/websecurity.html

さくっと内容をまとめますが、一度資料全体に目を通しておくとよさそうです。 https://www.ipa.go.jp/files/000017320.pdf

安全なSQLの呼び出し方

  • SQLインジェクションの根本的解決の基本はバインド機構だが、エスケープ処理による対策も根本的解決の一つになる。
  • ただ、SQLにとって特別な意味を持つ記号はデータベースエンジンによって異なる。
  • SQLインジェクションの原因はSQL文を実際の値に展開する際にリテラルとして正しく文を生成しないと、パラメータに与えられた値がリテラルの外にはみ出した状態になり、リテラルの後ろに続く文として解釈される
    $q = "SELECT * FROM atable WHERE id='$id'";
    $id = ';DELETE FROM atable--
    のような場合に展開すると
    SELECT * FROM atable WHERE id='';DELETE FROM atable--'
    となり、データベースの内容が全て削除される結果となる。
  • 具体的な対策は以下の二つ。
    • 文字列リテラルに対してはエスケープすべき文字をエスケープすること。
    • 数値リテラルに対しては数値以外の文字を混入させないこと
  • アプリケーションからSQLを呼び出す際の方法には以下の二つがある。
  • それぞれの説明については割愛するが資料にある。
  • データベースエンジンや言語ごとに対応方法が違うのでそれも資料を参照。
  • 特にMySQLPostgreSQLはシングルクォート以外の文字をエスケープしないといけない。
  • バックスラッシュがエスケープ処理に使用されるメタ文字として解釈されるため、バックスラッシュ自身のエスケープも必要となる。
  • 文字列リテラルエスケープ処理では、文字エンコーディングに配慮する必要がある。

まとめ

  • SQLインジェクションへの対策はバインド機構とエスケープ処理が基本
  • そもそもSQLインジェクションの原因を知らないと対策が十分かどうかすら判断できないので理解が必要
  • 使用する言語、データベースエンジンごとの対策を確認することが大事。

所感

軽く検索するとなんとなくの概要は掴めるけど、信頼のおける情報かどうか、必要十分な情報かどうか判断するにはちゃんと自分で考える必要があるなと感じました。
以下のサイトはその辺りの検証をしていて参考になるとともに、こういう視点を持って自分で検証できる、してみるというのはブログの読者側にもメリットが大きくてありがたいです。 https://ockeghem.hatenablog.jp/entry/20111109/p1
また、本質的な対策を書いてくださっている方もいます。 https://ajiyoshi.hatenadiary.org/entry/20100409/1270809525

  • 単にプリペアドステートメントを使え
  • 絶対に文字列結合でSQLを構築しようとしてはいけない
  • IPAの「安全なSQLの呼び出し方」を読むこと

この辺りのセキュリティ対策はWebエンジニアとしては必須の知識なのできちんと身につけていきたいです。

(何も知らない判断できない状態でのグーグル先生との付き合い方が最近むずかしくなってるけど丸呑みせずに自分で判断しないと。。。)