はじめに
IPA(独立行政法人情報処理推進機構)から第7版として(2015年3月に)公開されてる
の「第1章 ウェブアプリケーションのセキュリティ実装」の要点まとめです。
(要点といいつつ結局書き写しみたいになってしまった感が強いが..)
詳しくは、ドキュメントを見てください。
Webアプリケーションエンジニアであれば、Webアプリにおける「セキュアコーディングのプラクティス」として知っておくべき内容かと思います。
その他にも、以下のようなセキュアコーディングに関する文書があるのでこれらも参考になりそうです。
#JVN 脆弱性レポート一覧を見てもらえれば分かりますが、国内においてもこれだけ多くの脆弱性がある状況です。
#問題にならないようきちんと対策しておきたいものです。
脆弱性一覧
- 1)SQLインジェクション
- 2)OSコマンドインジェクション
- 3)ディレクトリトラバーサル
- 4)セッション・ハイジャック
- 5)XSS(クロスサイト・スクリプティング)
- 6)CSRF(クロスサイト・リクエスト・フォージェリ)
- 7)HTTP ヘッダ・インジェクション
- 8)メール ヘッダ・インジェクション
- 9)クリックジャッキング
- 10)バッファオーバーフロー
- 11)アクセス制御や認可制御の欠落
1)SQLインジェクション
SQL文を含んだ悪意のあるリクエストによりDBが不正利用される脆弱性。
対策
- SQL文の組み立てはプレースホルダで行う
- SQL文の組み立てを文字列連結で行う場合は、文字列としてエスケープする
- Webアプリに渡されるパラメータにSQL文を直接指定しない
SQL文組み立てのプレースホルダと文字列連結に関して少し補足。
【静的プレースホルダ】
データベースエンジン側でプレースホルダ("?"の記述)のままSQL文をプリコンパイルし、後からパラメータをバインドする方式。
Prepared Statementのこと。
あとで構文が変化することがないため脆弱性の心配はなく、最も安全で効率のよい方式。
ただ、DBエンジンによっては非サポート。
【動的プレースホルダ】
アプリ側のデータベース接続ライブラリで、パラメータをエスケープしてプレースホルダにはめ込む方式。
静的プレースホルダと異なりバインド処理を実現するライブラリ次第で脆弱性もあり。
なので、きちんと確認する必要あり。
【文字列連結】
SQL文を文字列連結により生成する方式。
エスケープ漏れしないように実装する必要あり。
ただ、DBの種類や設定によりエスケープ処理が異なるため注意が必要。
2)OSコマンドインジェクション
悪意のあるリクエストにより、サーバ上でOSコマンドを実行される脆弱性。
対策
-
Webアプリ内でシェルを起動しない
例えば、Perlの場合ファイルオープン処理ではopen()ではなくsysopen()を使用するなど。 -
シェルを起動する必要がある場合は、パラメータチェックを徹底する
許可する文字の組み合わせ以外は許可しない「ホワイトリスト方式」で制御する。
「ブラックリスト方式」もあるが悪用される記号文字(「|」「<」「>」等)に漏れる場合が出てくるのでおすすめできない。
3)ディレクトリ・トラバーサル
リクエストのパスに不正な内容を指定することで公開していないディレクトリにアクセスされてしまう脆弱性。
別名「パス・トラバーサル」ともいわれたり「../ (ドットドットスラッシュ)攻撃」ともいわれる。
対策
- 外部からのパラメータにファイル名を直接指定する必要があるか仕様を見直す
- ディレクトリ固定とする
外部からのパラメータをチェックし、ディレクトリ名を取り除く。
4)セッション・ハイジャック
セッション ID(利用者を識別するための情報)を発行し、セッション管理を行うWebアプリにおいて、ログイン中の利用者のセッションIDを不正に取得され、その利用者になりすまされる脆弱性。
攻撃の種類として、セッションIDの「推測」「盗用」「固定化」の3つがある。
対策
- セッションIDを複雑にする
セッションIDの推測攻撃に有効になる。
セッションIDは、生成アルゴリズムに暗号論的擬似乱数生成器を用いるなどして、予測困難なものにする。
セッション管理機能を提供するWebサーバを利用する場合は自前でセッションIDを生成する必要はない。 - セッションIDをURLパラメータにセットしない
セッションIDは、Cookieに格納するか、
POSTメソッドのhiddenパラメータに格納して受け渡しするようにする。 - HTTPS通信でのCookieはsecure属性で。
- HTTP通信でのCookieは、HTTPSで発行するCookieとは別にする。
- ログイン成功後に新しくセッションを開始する
- ログイン成功後に既存のセッションIDとは別に秘密情報を発行してページ遷移の妥当性チェックを行う
- ログイン成功時にセッションIDとは別に秘密情報を作成してCookieにセットし、この秘密情報とCookie の値が一致することを全てのページで確認する
5)XSS(クロスサイト・スクリプティング)
攻撃者の流し込んだスクリプトに利用者が意図せずアクセスすることで被害を及ぼす脆弱性。
対策
- 特殊文字をサニタイジングする
記号文字(「<」「>」「&」「"」「’」等)を、HTMLエンティティ(「<」「>」「&」「"」「'」等)に置換する。
JSのdocument.writeやinnerHTMLにて動的読み込みする場合も同様に。 - URL出力は「http://」や「https://」形式のみ許可
- script要素の内容を動的に生成しない
- スタイルシートを任意のサイトから取り込めるようにしない
スタイルシートには、expression()等を利用してスクリプトを記述することができるため危険。
6)CSRF(クロスサイト・リクエスト・フォージェリ)
利用者が、攻撃者の流し込んだリンクやスクリプトにアクセスすることで意図せず別のWebサイト上で何らかの操作を行わせる攻撃。
対策
- 前ページのセッションIDの整合性チェック
セッションIDとログイン時に生成するセッションIDが正しいかチェックする。
IDはhiddenパラメータに含める。
そのためPOSTリクエストする(GETだとRefererにhidden漏れちゃうから) - 前ページからページ遷移時にパスワードを求める
上記対応ができないのであれば、くらいで。
画面遷移を考慮するので設計が必要。 - Refererで元リンクをチェック
意図した画面遷移かどうか判断する。
しかし、ブラウザやファイアーウォール設定でReferer未設定にされてると意味がない。
7)HTTP ヘッダ・インジェクション
悪意を持って細工された情報をHTTPヘッダに埋め込まれ(インジェクション)、埋め込まれた情報を基にした偽ページを表示させられてしまうもの。
クロスサイト・スクリプティングとは細工される場所が異なるが同様の脅威がある。
対策
- ヘッダ出力を直接行わず、Webアプリの実行環境や言語で用意されているヘッダ出力用APIを使う
- 改行コードを適切に処理するヘッダ出力用APIを利用できない場合は、改行を許可しない
- 外部からの入力全てにおいて改行コードを削除するのもあり
8)メール ヘッダ・インジェクション
商品申し込みやアンケート等の本来固定のメールアドレスへの送信が、自由なメールアドレスへ送信できてしまう脆弱性。
対策
- メールヘッダを固定値にして、外部からの入力はすべてメール本文に出力する
- メールヘッダを固定値にできない場合、ウェブアプリケーションの実行環境や言語に用意されているメール送信用APIを使用する
- HTMLで宛先を指定しない
- 外部からの入力の全てについて、改行コードを削除するのもあり
9)クリックジャッキング
Webサイトの見えているボタンをクリックしたつもりが、実際は隠れているページのボタンをクリックしてしまう脆弱性。
iframeで罠のページを重ね合わせ透明にすることで罠のページのリンクをクリックさせる。
CSRFとは似て非となり、クリックジャッキングはマウス操作のみで発生しうる脅威に絞られるのが特徴。
対策
-
HTTPレスポンスヘッダに、X-Frame-Optionsヘッダフィールドを出力する
X-Frame-Optionsを使用することで他ドメインのサイトからのframe要素やiframe要素による読み込みを制限する。
IE7ではX-Frame-Optionsに対応してないので効かない。 -
直前のページで再度パスワードの入力を求め、実行ページではそのパスワードが正しいかチェックする
この対処の場合は画面遷移が変わるので再設計が必要になる。
10)バッファオーバーフロー
実行中のプログラムが確保したメモリ領域(バッファ)を超えてデータが上書きされ、悪意のあるコードが実行される脆弱性。
対策
- 直接メモリにアクセスできない言語で開発する
C、C++、アセンブラなどの直接メモリを操作できる言語など。 - 直接メモリにアクセスできる言語で記述する部分を最小限にする
- 脆弱性が修正されたバージョンのライブラリを使用する
11)アクセス制御や認可制御の欠落
セキュリティに対する認識のなさから、不適切な設計で作成/運用されるWebサイトの「アクセス制御」や「認可制御」等の機能欠落に伴う脆弱性。
対策
- 認証機能を設ける(パスワード等の秘密情報の入力要求)
・サイト上で非公開とされるべき情報や、利用者本人にのみデータの変更や編集を許可する場合等には、アクセス制御が必要
・メールアドレスだけではなくパスワード等の入力を必要とする設計/実装を行う - ログイン中の利用者が他人になりすましてアクセスできないようにする
・どの利用者にどの操作を許可するかなどの認可制御が必要
・セッションIDを用いてセッション管理をする
・利用者IDが、ログイン中の利用者ID と一致しているかを常に確認する
・利用者IDを、外部から与えられるパラメータから取得しないで、セッション変数から取得するようにする。