技術の犬小屋

Webプログラミングを餌に生きる犬のメモ帳

Posts in the Perl category

XSS脆弱性への対策方法について勉強した。サニタイズ言うなキャンペーンにも目を通した。Webアプリケーションのセキュリティに詳しい,高木浩光先生や徳丸浩先生の考え方を含めながら,まとめてみる。
 

XSSとは

ソフトウェアのセキュリティホールの一つで,Webサイトの訪問者の入力をそのまま画面に表示する掲示板などのプログラムが,悪意のあるコードを訪問者のブラウザに送ってしまう脆弱性のこと。
悪意を持ったユーザがフォームなどを通してJavaScriptなどのスクリプトコードを入力した時に,プログラム側に適切なチェック機構がないと,そのスクリプト内容がそのままHTMLに埋め込まれ,ページを閲覧したコンピュータでスクリプトが実行されてしまうことがある。
 

サニタイズとは

Webサイトの入力フォームへの入力データから,HTMLタグ,JavaScript,SQL文などを検出し,それらを他の文字列に置き換える操作のこと。「無害化」とも呼ばれ,サニタイジング操作により,入力データ中に含まれる悪意のあるHTMLタグ,JavaScript,SQL文などが解釈・実行されることを防ぐ。
 

サニタイズはするべきではない

ここまで見て,まず考えるのが「XSS対策としてサニタイズすれば良いのではないか」ということであるが,サニタイズはXSS対策の保険的なものであり,本来,サニタイズは推奨されない。
 
日本における「サニタイズ」という言葉の持つ意味やニュアンスを厳密に定義すると「入力処理で受け取ったデータに含まれる有害(別のリテラルで解釈可能)なメタ文字に対して,エスケープ処理を行うこと」となる。
ここで注意したいのは,「サニタイズ」は「バリデーション」とは全く異なるという点である。バリデーションを行うことは一般的なので,ここでは深く説明はしないが,「バリデーション」という言葉の定義は「入力処理で受け取ったデータに対して,データの妥当性をチェックすること」であり,サニタイズとは異なる。
 
では,何故サニタイズをしてはいけないのか,ということについての理由を説明する。まず,大前提として「サニタイズ」は間違った習慣が根付いてしまったものであり,本来は推奨されるべきではない,ということを念頭に置いてほしい。
 
サニタイズが推奨されないことには,以下の2つの理由がある。

  • プログラマの都合で,ユーザーが入力した内容を勝手に改変するべきではない
  • サニタイズが行われると,システムが汚染される

以下,それぞれの理由について説明する。
 

プログラマの都合で,ユーザーが入力した内容を勝手に改変するべきではない

いくらセキュリティ上の危険があるからといって,ユーザーが入力した内容を勝手に改変してよい理由はない。もし,メタ文字のエスケープが必要になる入力が行われたとしたら,それは本来はエラーにするべきである。
 

サニタイズが行われると,システムが汚染される

サニタイズは「スクリプトで受け取ったデータに含まれる,<>&"といったメタ文字を,JavaScriptのリテラルとして解釈できてしまう」という問題への付け焼刃的な対策方法である。だが,必ずしもXSSへの対策にサニタイズを行う必要はなく,出力処理で適切にエスケープ処理を行うことで,XSS脆弱性を回避することが可能である。
ここで大切なのは「サニタイズ」という言葉の定義を正しく理解することである。「サニタイズ」とは「入力処理で有害なメタ文字をエスケープ処理すること」である。「出力処理で有害なメタ文字をエスケープすること」を「サニタイズ」とは呼ばない。
 
ここで,どうして「入力処理」ではなく,「出力処理」でメタ文字をエスケープすることにこだわるのか,ということについて説明する。その理由は,メタ文字のエスケープ処理がシステムにもたらす「汚染」とも呼ぶべき影響範囲をなるべく小さくするためである。
 
ここでの「汚染」とは,入力データがエスケープ処理によって,本来のデータとは異なるデータに書き換えられることによって発生する,システムへの害のことを指す。
もし,入力処理でメタ文字のエスケープ処理を行った場合,エスケープ処理の影響は,システム内部やDBにまで波及する。つまり,システム内部やDBにて,エスケープ処理されたデータを,本来のデータに戻すための2次3次的な変更が発生することになる。
一方,出力処理でメタ文字のエスケープ処理を行った場合,エスケープ処理の影響はシステム内のどこにも波及することはない。
 
以上の理由から,XSS対策に,サニタイズ(入力処理でのメタ文字のエスケープ処理)は推奨されない。XSS対策には,出力処理でのメタ文字のエスケープ処理を行うべきである。
 

まとめ

  • サニタイズとは,「入力処理でメタ文字をエスケープすること」である
  • XSS脆弱性対策には,サニタイズは行わず,出力処理で適切にエスケープ処理を行う

 
 
以上
 
 
参考
クロスサイトスクリプティングとは 【 XSS 】 【 Cross Site Scripting 】 – 意味/解説/説明/定義 : IT用語辞典
サニタイジングとは 【 sanitizing 】 〔 サニタイズ 〕 – 意味/解説/説明/定義 : IT用語辞典
高木浩光@自宅の日記 – WASF Times版「サニタイズ言うな!」
XSS再入門
XSS: 今こそXSS対策についてまとめよう – 徳丸浩の日記(2008-08-22)

SQLインジェクションについて,改めて勉強したので忘れないようにメモしておく。
 

SQLインジェクションとは

データベースと連動したWebサイトで,データベースへの問い合わせや操作を行うプログラムにパラメータとしてSQL文の断片を与えることにより,データベースを改ざんしたり不正に情報を入手する攻撃。また,そのような攻撃を許してしまうプログラムの脆弱性のこと。
 

具体例

例えば,ユーザによって入力されたユーザID,パスワードをそれぞれ {$userId} , {$passwd} に代入し,上記SQLにてその存在が確認できればログインできるWEBページがあるとする。
 
そのWEBページで使われているSQLは以下のようになっている。
 

SELECT * FROM ユーザマスタ WHERE ユーザID = '{$userId}' AND パスワード = '{$passwd}'

 
悪意のあるユーザがユーザID「dog」としてパスワードを入力せずにログインを試みるようなパラメータを入力した際には,以下のようなSQLとなる。
 

SELECT * FROM ユーザマスタ WHERE ユーザID = 'dog' AND パスワード = '' OR 'A' = 'A'

 
$passwd に対して ‘ OR ‘A’ = ‘A’ というパラメータを渡している。このように OR で A は A である,というような条件式を追加することで不正にログインすることが出来てしまう。
 

SQLインジェクション脆弱性への対策方法

SQLインジェクション脆弱性への対策としては,プレースホルダを使用する。ここで,パラメータ部分を示す記号「?」のことをプレースホルダと呼び,そこへ実際の値を割り当てることを「バインドする」と呼ぶ。
 
プレースホルダには,以下の2つがある。

  • 静的プレースホルダ
  • 動的プレースホルダ

 
以下,これらについて説明する。
 

静的プレースホルダ

静的プレースホルダは,JIS/ISO の規格では「準備された文(Prepared Statement)」と規定されている。これは,プレースホルダのままのSQL文をデータベースエンジン側にあらかじめ送信して,実行前に,SQL文の構文解析などの準備をしておく方式である。SQL実行の段階で,実際のパラメータの値をデータベースエンジン側に送信し,データベースエンジン側がバインド処理を行う。つまり,SQL文の構文がバインド前に確定する。このことから,セキュリティの観点で,静的プレースホルダは最も安全である。静的プレースホルダでは,SQLを準備する段階で SQL文の構文が確定し,後からSQL構文が変化することがないため,パラメータの値がリテラルの外にはみ出す現象は起きない。その結果として,SQLインジェクションの脆弱性が生じることはない。
 

動的プレースホルダ

動的プレースホルダとは,プレースホルダを利用するものの,パラメータのバインド処理をデータベースエンジン側で行うのではなく,アプリケーション側のライブラリ内で実行する方式である。動的プレースホルダは静的プレースホルダとは異なり,バインド処理を実現するライブラリによっては,SQL構文を変化させるようなSQLインジェクションを許してしまう,脆弱な実装のものが存在する可能性を否定できない。
よって,SQLインジェクション脆弱性対策には,なるべく静的プレースホルダを使用することを推奨する。
 

プログラミング言語とデータベースの組み合わせによって使用されるプレースホルダの種類が分かれる

プログラミング言語とデータベースの組み合わせで,デフォルトで使用されるプレースホルダが,静的プレースホルダか,動的プレースホルダか,に分かれる。
 
以下にプログラミング言語とデータベースの組み合わせでどちらのプレースホルダが使われるかを示す。
 

Java + Oracle

項目 内容
プレースホルダの実装 静的のみ
デフォルトで使用されるプレースホルダ 静的

 

Java + MySQL

項目 内容
※静的プレースホルダを使用するには,DB接続時にuseServerPrepStmts=trueというパラメータを指定する必要がある。
プレースホルダの実装 静的または動的
デフォルトで使用されるプレースホルダ 動的

 

PHP + MySQL

項目 内容
※静的プレースホルダを使用するには,DB接続時にPDO::setAttribute(ATTR_EMULATE_PREPARES, false)というパラメータを指定する必要がある。
プレースホルダの実装 静的または動的
デフォルトで使用されるプレースホルダ 動的

 

PHP + PostgreSQL

項目 内容
プレースホルダの実装 静的のみ
デフォルトで使用されるプレースホルダ 静的

 

Perl + MySQL

項目 内容
※静的プレースホルダを使用するには,DB接続時にmysql_server_prepare=1というパラメータを指定する必要がある。
プレースホルダの実装 静的または動的
デフォルトで使用されるプレースホルダ 動的

 

ASP.NET + SQL Server

項目 内容
プレースホルダの実装 静的のみ
デフォルトで使用されるプレースホルダ 静的

 

まとめ

  • SQLインジェクション脆弱性への対策にはプレースホルダを使う
  • 動的プレースホルダよりも,なるべく静的プレースホルダを使うことが望ましい

 
 
以上
 
 
参考
SQLインジェクション
安全なSQLの呼び出し方
PDOでATTR_EMULATE_PREPARESを適切に設定してないとSQLインジェクションの原因になるかも(MySQL編)
プリペアド・ステートメント(プレースホルダ)入門
PDOにおける一応の安全宣言と残る問題点 | 徳丸浩の日記
SQLインジェクションのまとめ – No Programming, No Life

第4回となったPerlの備忘録です。リアルではPerlのプログラミング業務が終了しました。
 

invocantとblessについて

invocant(インボカント)とはパッケージ外からメソッドが呼び出された時に暗黙的にメソッドの第一引数として渡されるパッケージのリファレンスである。
 
リファレンスとはCでいうところのポインタと同じ、メモリのアドレス情報(参照)とかなり似た性質を持つものである。厳密に言うと全く同一ではないが、似ているものだと認識して差支えない。
 
bless(ブレス)は、invocantで取得したパッケージのリファレンスとパッケージ内で宣言した変数などを関連付ける時に使用する。
 
以下のコードでは、mainパッケージからStoneパッケージを呼び出す際にblessしている。コードの挙動としてはmainパッケージの4行目でStoneパッケージのインスタンスを生成し、Stoneパッケージの2行目でinvocantを受け取っている。Stoneパッケージの7行目でblessする。そして、mainパッケージの8行目で実際に使用している。
 

呼び出し元

#!/usr/bin/perl
package main;
use Stone;
$obj = Stone->new("SmokyDog","28");
print ref $obj;    #"Stone"を出力
print "n";
print $obj;         #"HASH(0x10b1350)"を出力
print $obj->{'name'};     #"SmokyDog"を出力

 

呼び出されるパッケージ

package Stone;
my $pkg = shift;    #invocant(Stoneパッケージの参照)を受け取る
my $hash= {
  name   => shift,    #SmokyDogを受け取る
  weight => shift     #28を受け取る
};
bless $hash,$pkg;

 
上記で示したコードだとblessがそれほど重要だという印象を受けないかもしれないが、blessを使用することでソースを短く、簡潔に記述することができるので、可読性が高いソースコードを書く上では重要である。私が携わったPerlのプロジェクトでも、データベースに接続してSQLの発行を担う基底クラスに組み込んで使用した。
 
 
以上
 
 
参考
Perlオブジェクト指向プログラミング

第3回となったPerlの備忘録です。リアルではプログラミング業務を開始したので、余裕があるときに備忘録としてまとめていきたいと思います。
 

メソッド/サブルーチン

メソッド/サブルーチンの呼び出し

&MethodName($param1, $param2, $param3);

 
関数名呼び出しには頭に「&」を記述する。引数は他の言語と同じくカンマ(,)区切りで記述する。
 

メソッド/サブルーチンの引数受け取り

sub MethodName{
    my ($param1, $param2, $param3) = @_;
}

 
メソッド/サブルーチン宣言の頭にはsubを書く。呼び出し元から渡された引数は@_から受け取ることができる。@_で複数の引数を受け取る時はmy ($param1, $param2, $param3)というようにリストでまとめて受け取ることができる。
 
@_以外にもshiftと書くと引数を一つずつ受け取ることができる。

sub MethodName{
    my $param1 = shift; //第一引数受け取り
    my $param2 = shift; //第二引数受け取り
    my $param3 = shift; //第三引数受け取り
}

 

invocantについて

invocant(インボカント)はパッケージスコープ外のメソッドを呼び出した時に自動的にメソッドの引数に渡されるパッケージの参照情報である。パッケージスコープ外のメソッドを呼び出すと、必ず引数の1番目に入ってくる。
 
invocantについて、詳しくは次回の記事でまとめる。
 
 
以上
 
 
参考
$foo = shift;ってなんだろうか? – marsonicの日記
引数を任意の変数に格納 – サブルーチン – Perl入門

今回は変数・スコープ周りについて説明する。
 

変数のスコープを理解する

Perl言語の変数のスコープには,myとourとlocalの3つがある。基本的に変数のスコープにはmyを使用する。
 

myの使い方

myはレキシカルスコープと呼ばれるスコープを持つ。単語からでは、どういうスコープを持つのか想像しにくいのが厄介だが,他のサイトでは以下のように説明されていた。

myは、レキシカルスコープで、他言語で言えば、ブロック内のローカル変数のように振舞います。構文上、ブロックを抜けると、宣言した変数のスコープが終了します。宣言後、スコープから抜けるまで、他の関数やブロックから、その変数は見えません。

 
以下にmyの使い方をコードで示す。
 

use strict;
use warnings;
package AAA;

    my $hoge = 'サブルーチンの外'; #変数をmyで宣言
    print $hoge; #「サブルーチンの外」が出力される

    &example; #exampleサブルーチン呼び出し
    sub example {
        my $fuga = 'サブルーチンの中; #変数をmyで宣言
        print $hoge; #「サブルーチンの外」が出力される
        print $fuga;  #「サブルーチンの中」が出力される
    }

    print $hoge; #「サブルーチンの外」が出力される
    print $fuga;  #←ここで変数を参照するとエラー

package BBB;

    print $hoge; #「サブルーチンの外」が出力される

 
一般的なプログラマからすると,myのスコープは馴染み深いはずだ。myは,最近のプログラミング言語(C,Java,PHPなど)で実装されている変数のスコープとほとんど同じである。しかし,上記の通り,同一のファイルに複数のパッケージが記載されている場合は,myはパッケージスコープを超えてしまう。これを防ぐには,以下のようにパッケージに{}ブロックを付けて記述する。このようにすることでmyのスコープをパッケージ内に限定することができる。
 

use strict;
use warnings;
package AAA;
{
    my $hoge = 'サブルーチンの外'; #変数をmyで宣言
    print $hoge; #「サブルーチンの外」が出力される
}
package BBB;
{
    print $hoge; #←ここで変数を参照するとエラー
}

 

ourの使い方

ourはレキシカルスコープを持つ。myとの大きな違いとして,以下の2つがある。

  1. スコープを抜けて、もう一度同じスコープに入ってきたときに、前の値を保持している
  2. パッケージ名前空間を利用できる

 
以下にourの使い方をコードで示す。
 

use strict;
use warnings;
package foo;

    my $hoge = 'サブルーチンの外';
    print $hoge; #「サブルーチンの外」が出力される

    &example; #1度目のサブルーチン実行 #print文で「サブルーチンの中」が出力される
    sub example{
        our $hoge;
        BEGIN {    #BEGINは一度目の呼び出しに限り実行される
            $hoge = 'サブルーチンの中';
        }
        print $hoge;
    }

    print $hoge; #「サブルーチンの外」が出力される

    $hoge = 'サブルーチンの外';
    &example; #2度目のサブルーチン実行 #print文で「サブルーチンの中」が出力される

 
上記では,一度サブルーチンのスコープを抜けて,もう一度同じサブルーチンのスコープに入ってきたときに前の値を保持している。ourはこのような特徴を持つ。
 

package foo;
{
    our $hoge = 'foo';
}

package bar;
{
    print $foo::hoge; #パッケージ名前空間を利用して参照することができる
}

 
ourでは,$foo::hogeのようにパッケージ名前空間を利用して変数を参照することができる。
 

localの使い方

localは,ダイナミックスコープを持つ。ダイナミックスコープとは,文字通り動的なスコープのことで,変数のスコープがその宣言を含むブロックに限定されないことを指す。localは,サブルーチンのスコープ内でのみ有効な値を定義することができ,localを宣言したサブルーチンから呼び出したサブルーチンでも同じ値が共有される。
 
以下にlocalの使い方をコードで示す。
 

use strict;
use warnings;

$var1 = 'サブルーチンの外';
print $var1; #「サブルーチンの外」が出力される

&example1; #サブルーチン実行
sub example1 {
    local $var1 = 'サブルーチンの中'; #localはサブルーチン内でのみ有効
    print $var1; #「サブルーチンの中」が出力される
    &example2; #サブルーチン実行
}

print $var1; #「サブルーチンの外」が出力される

sub example2 {
    print $var1; #「サブルーチンの中」が出力される
}

 
上記のように,localはサブルーチンを跨いだ呼び出しを行った場合,値が共有される。また,localを使用することでグローバル変数とローカル変数を視覚的に区別することが容易になり,クラス内の見通しが良くなるという恩恵も得られる。
 

まとめ

変数宣言には,基本的にmyを使用し,グローバル変数的に使用したい変数にはourを使用する。localはサブルーチンの中でのみ使用することができるが,myでも代替することは可能である。
ourやlocalを使用することに抵抗がある場合は,無理して使わなくてもよい。Perlのスローガンに「やり方はひとつじゃない」とある通り,ユーザはPerlに用意された様々な方法の中から,自分に合った方法を選べばよいのだ。
 
 
以上
 
 
参考
my と local どう違う? – futomi’s CGI Cafe
Perlのour – Perlのourについて。