My Photo

« July 2013 | Main | September 2013 »

August 25, 2013

入力処理とセキュリティ

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

入力値の検証の目的はセキュリティ対策ではないが、以下のようにセキュリティのために役立つ場合もある。

  • SQLインジェクション対策が漏れていたが、英数字のみ許可していたので実害には至らない。
  • バイナリセーフではない関数を使っているが、入力段階で制御文字をチェックしているので実害には至らない。
  • 表示処理の関数で文字エンコーディングの指定を怠っているが、入力段階で不正な文字エンコーディングをチェックしているので実害には至らない。

バイナリセーフ

バイナリセーフとは入力値がどんなバイト列であっても正しく扱えることを意味する。典型的な例としてはヌルバイト(PHPでは\0と表記)が現れても正しく処理できることを指す。
ヌルバイトが特別な理由は、CおよびUNIX、WindowsのAPIでヌルバイトを文字列の終端とみなす取り決めがあるからである。このためPHPやその他の言語ではヌルバイトを正しく扱えない関数がある。このような関数をバイナリセーフではない関数と言う。

ヌルバイトを使った攻撃手法はヌルバイト攻撃と呼ばれる。ヌルバイト攻撃は他の脆弱性対策を回避するために使用される。
ヌルバイト攻撃との組み合わせが多い脆弱性はXSS脆弱性、ディレクトリトラバーサル脆弱性がある。

下記のPHPのコードはereg()を用いて変数$pが数字のみからなることを検証している。
ereg()はバイナリセーフではない。

<?php
$p = $_GET['p'];
if (ereg('^[0-9]+$', $p) === FALSE) {
	die('整数値を入力してください。');
}
echo $p;
?>

これに以下のURLでアクセスする。

http://example.jp/42/42-002.php?p=1%00<script>alert('XSS');</script>

結果はブラウザ上でjavascriptが実行されダイアログ上に「XSS」と表示される。これはヌルバイト攻撃+XSS脆弱性である。
URL中の「%00」はヌルバイトであり、ereg()はヌルバイトで文字列が終わっているとみなすためヌルバイトより後ろを無視し、検証が回避された。

ヌルバイト攻撃に対する根本対策はバイナリセーフの関数のみを用いてアプリケーションを開発することである。しかし、言語の関数リファレンスには関数がバイナリセーフかどうか記述がない場合が多く、現時的には困難である。
そのため、アプリケーションの入り口でバイナリセーフの関数を用いてヌルバイトをチェックするのが現実的な対応である。

入力値の検証基準はアプリケーション要件

入力値の検証の基準はアプリケーション要件である。
よって「すべての文字を許可する」という場合もある。しかし、そのような場合でも以下のチェックは行うべきである。

  • 制御文字のチェック
  • 文字数のチェック

PHPの正規表現ライブラリ

PHPの正規表現関数にはereg、preg、mb_eregの3系統がある。
eregは前述のとおりバイナリセーフではないので、開発ではpreg、mb_regを使用する。
pregはエンコードがUTF-8の場合のみ日本語を扱える。mb_eregは様々なエンコーディングが利用できる。

下記は英数字1~5文字チェックをpreg_match()で実装したコードである。
データの先頭と末尾はそれぞれ'\A'と'\z'で示す。代わりに'^'と'$'を使う場合もあるが'^'と'$'は行の先頭と末尾を表すので、'^'と'$'を使うと改行文字がチェックを通過してしまう。

<?php
$p = isset($_GET['p']) ? $_GET['p'] : '';
if (preg_match('/\A[a-z0-9]{1,5}\z/ui', $p) == 0) {
	die('1文字以上5文字以下の英数字を入力してください');
}
?>

文字種の制限がなし1~30文字の場合は、preg_match()の部分は以下のようになる。

preg_match('/\A[[:^cntrl:]]{1,30}\z/u', $p)

また、textarea要素からの入力値で改行、タブを許容し他の制御文字は禁止する場合は以下のようになる。

preg_match('/\A[\r\n\t[:^cntrl:]]{1,30}\z/u', $p)

「[:cntrl:]」は制御文字を表すPOSIX文字クラスで、「[:^cntrl:]」はその否定、つまり制御文字以外である。

参考文献:体系的に学ぶWebアプリケーションの作り方 4.2 入力処理とセキュリティ

体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践
徳丸 浩

ソフトバンククリエイティブ 2011-03-03
売り上げランキング : 4070

Amazonで詳しく見る
by G-Tools

参考ページ:
Ruby 1.9.3 リファレンスマニュアル 正規表現
正規表現の文字クラスまとめ - 名もないテクノ手

August 19, 2013

PostgreSQLでMySQLのgroup_concat関数のようなことをする

MySQLには group_concat という関数があってとても便利そう。
例えば1:nの親子関係のテーブルがあって連結して検索すると親の主キーに対して複数のレコードが検索される場合、親の主キーに対して1レコードとなる検索をしたい場合に使える。

PostgreSQLでは9.0で string_agg という MySQLのgroup_concatに相当する関数が追加された。
PostgreSQL 9.1 集約関数

9.0以前では配列を使って同じような結果を得ることができる。

customers と customerTagRelation というテーブルを例にして考える。
データは以下のようになっている。

customers
customerID customerName
1Suzuki
2Tanaka
3Yamashita
customerTagRelation
customerID tagID
11
12
32

下記はcustomerTagRelation に対して自己相関サブクエリ?で customerID毎にカンマ区切りのtagIDを取得するSQLの例。customerID毎にするためにDISTINCTを付けている。customerTagRelation だけを検索しているので、クエリの結果に customerTagRelation にない customerID = 2 のレコードはない。

--SQLその1
SELECT DISTINCT a.customerID,
                ARRAY_TO_STRING(
                  ARRAY(SELECT b.tagID
                        FROM customerTagRelation b
                        WHERE b.customerID = a.customerID ), ',')
FROM customerTagRelation a
ORDER BY a.customerID;

実行結果は以下。

 customerid | array_to_string
------------+-----------------
          1 | 1,2
          3 | 2
(2 行)

次いで、customers を検索して customerID,customerName毎にカンマ区切りのtagIDを取得するSQL。SELECT句で相関サブクエリを使用する。

--SQLその2
SELECT t1.customerID, t1.customerName,
       (SELECT ARRAY_TO_STRING(
           ARRAY(SELECT t2.tagID FROM customerTagRelation t2
                 WHERE t2.customerID = t1.customerID ), ',')) AS text_csv
FROM customers t1
ORDER BY t1.customerID;

実行結果は以下。

 customerid | customername | text_csv
------------+--------------+----------
          1 | Suzuki       | 1,2
          2 | Tanaka       |
          3 | Yamashita    | 2
(3 行)

上記の配列を使う方法の他には ARRAY_AGG 関数を使う方法がある(8.4以降)。
ARRAY_AGG 関数は集約関数で、値をカンマで連結して波括弧で括ったvarchar型の値を返す。集約関数なので GROUP BY句を使う。
ARRAY_AGG は配列を返すので ARRAY_TO_STRING 関数で文字列にしている。前記の ARRAY と ARRAY_TO_STRING を使う方法よりわかりやすいように思う。8.4以降ならば ARRAY_AGG を使った方がいいだろう。

SQLその1とほぼ同じ検索をするARRAY_AGGを使ったSQL。
ARRAY_AGG は出力形式の変更はできないようだ。

SELECT customerID, ARRAY_TO_STRING(ARRAY_AGG(tagID), ',') AS tag
FROM customerTagRelation
GROUP BY customerID;

実行結果は以下。

 customerid | tag
------------+-----
          1 | 1,2
          3 | 2
(2 行)

SQLその2とほぼ同じ検索をする ARRAY_AGG 関数を使ったSQL。配列を使用した場合よりわかりやすい。デメリットは ARRAY_AGG を使っているので出力形式が固定になること。"{NULL}" はなんかあまり美しくない感じがする。

SELECT t1.customerID
     , MAX(t1.customerName) AS name
     , ARRAY_TO_STRING(ARRAY_AGG(t2.tagID), ',') AS tag
FROM customers t1
LEFT OUTER JOIN customerTagRelation t2
ON t1.customerID = t2.customerID
GROUP BY t1.customerID;

実行結果は以下。

 customerid |   name    | tag
------------+-----------+-----
          1 | Suzuki    | 1,2
          2 | Tanaka    |
          3 | Yamashita | 2
(3 行)

参考ページ:
GROUP_CONCAT関数の便利さは異常 - 開発の風景 ~KKZのSE日記~
複数行返ってくるサブクエリを文字列に連結して取得するSQLまとめ - hikky nikky
複数行の結果を単一列に連結 - PostgreSQL - 教えて!goo
PostgreSQL 9.0 のその他の新機能 — Let's Postgres
集約関数

August 11, 2013

Webアプリケーションの機能と脆弱性の対応

脆弱性は

  • 出力に起因するもの…インジェクション系脆弱性
  • 処理に起因するもの

に分けられる。

出力に起因する脆弱性

ここでの「出力」とはHTTPレスポンスだけではなくDBアクセスなど外部システムとのやり取りも含む。

クロスサイトスクリプティング(HTMLインジェクション、JavaScriptインジェクション)
出力:HTMLの出力
HTTPヘッダインジェクション
出力:HTTPヘッダの出力
SQLインジェクション
出力:SQLの発行
OSコマンドインジェクション
出力:シェルコマンドの呼び出し
メールヘッダインジェクション
出力:メールヘッダおよび本文の出力
ディレクトリトラバーサル
出力:ファイルへのアクセス

処理に起因する脆弱性

クロスサイトリクエストフォージェリ(CSRF)
セッションフィクセーション認証不備
認可不備

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

Webアプリケーションではテキスト形式のインタフェースが多用される。
これらのテキスト形式の多くは引用符(シングルクウォートやダブルクウォートなど)やデリミタによってデータを識別する。
多くのWebアプリではテキストの構造はあらかじめ決まっていて、データのみをテキスト中の特定の場所に流し込む。

インジェクション系脆弱性の原理は、本来データが入る部分に引用符やデリミタを混入させ、文字列の構造を変化させることである。

例として以下のSQL(Aと呼ぶ)があるとする

SELECT * FROM users WHERE id='$id'

$idの部分以外はあらかじめ決められているが、アプリケーションにSQLインジェクションの脆弱性があるとこの構文を変化させることができる。
例えば、$idの部分に以下の文字列(Bと呼ぶ)が入ったする。

';DELETE FROM users --

すると、AにBを流し込んだ結果はいかになる。

SELECT * FROM users WHERE id='';DELETE FROM users --'

結果、SELECT文1個だったものにDELETE文が追加される。

脆弱性 インタフェース 手口 データの終端
クロスサイト
スクリプティング
HTML JavaScriptなどの注入 >"など
HTTPヘッダ
インジェクション
HTTP HTTPレスポンスヘッダの注入 改行
SQLインジェクション SQL SLQ命令の注入 'など
OSコマンド
インジェクション
シェルスクリプト OSコマンドの注入 ;|など
メールヘッダ
インジェクション
senmailコマンド メールヘッダ、本文の注入・改変 改行

参考文献:体系的に学ぶWEBアプリケーションの作り方 4.1 Webアプリケーションの機能と脆弱性の対応

体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践
徳丸 浩

ソフトバンククリエイティブ 2011-03-03
売り上げランキング : 4070

Amazonで詳しく見る
by G-Tools

August 06, 2013

PostgreSQLで時間の差を求める

PostgreSQLで時間の差を求めるにはage()を使用する。

-- date1とdate2の差を算出
SELECT id, age(date1, date2) AS diff FROM tbl;

-- date1とdate2の差が1日以内のレコードを抽出
SELECT id, date1, date2, age(date1, date2) AS diff
FROM tbl
WHERE age(date1, date2) BETWEEN interval '-1 days' AND '+1 days';

August 04, 2013

クロスドメインアクセス

前の記事:同一生成元ポリシー

前の記事にあるように、javascriptは同一生成元ポリシーによりクロスドメインのアクセスが厳しく制限されている。
この記事ではブラウザでクロスドメインアクセスが許可されているものについて説明する。

frame要素,iframe要素

farme、iframe要素はクロスドメインのアクセスができる。
X-Frame-OptionsヘッダというHTTPレスポンスヘッダがあり、値としてDENYとSAMEORIGINがある。
DENYの場合、ページ内のフレームは表示されない。
SAMEORIGINの場合、フレーム内が外側のページと同一生成元であればフレームが表示される。
フレームを使用しない場合はDENYを、単一ホストでフレームを使用している場合はSAMEORIGINを指定することにより、クリックジャック攻撃を防ぎ安全性を高めることできる。

img要素

img属性はクロスドメインの指定が可能。
意図しないサイトに画像を張られるのを防ぐには、画像に対するRefererヘッダをチェックするという方法がある。

script要素

src属性を指定することで他のサイトのjavascriptを読み込むことができる。
サイトAのドキュメントがサイトBのjavascriptを読み込んだ場合、読み込まれたjavascriptはサイトAのドメインで動作する。
サイトBのjavascriptを読み込むときにサイトBに対するクッキーが送られるので、利用者の状態にサイトBが影響を受けてjavascriptが変化する場合がある。これによってJSONP(JSON with padding)を利用している場合に情報漏えいする可能性がある。よってJSONPで公開情報のみを提供するべきである。

CSS

過去に Internet Explorer はCSSXSSという脆弱性があった。

form要素

action属性でクロスドメインの指定が可能。
この仕様を悪用した攻撃がクロスサイト・リクエストフォージェリ(CSRF)攻撃である。ユーザの意図しないformを送信させられる。

参考文献:体系的に学ぶWEBアプリケーションの作り方 3.2 受動的攻撃と同一生成元ポリシー

体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践
徳丸 浩

ソフトバンククリエイティブ 2011-03-03
売り上げランキング : 4070

Amazonで詳しく見る
by G-Tools

« July 2013 | Main | September 2013 »

May 2017
Sun Mon Tue Wed Thu Fri Sat
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      
無料ブログはココログ

日本blog村

  • にほんブログ村 IT技術ブログへ
  • にほんブログ村 アニメブログへ
  • にほんブログ村 サッカーブログ アルビレックス新潟へ

好きな音楽家

メモ

XI-Prof