CyberX:エンジニアブログ -3ページ目

Webアプリケーションと 脆弱性対策 その1

CyberXのプログラマ M.I です。

今日のお題は「Webアプリケーションと脆弱性対策」についてです。

脆弱性への攻撃は
叫びクロスサイトスクリプティング
叫びHTTPヘッダインジェクション
叫びSQLインジェクション
叫びOSコマンドインジェクション
叫びメールヘッダインジェクション
叫びディレクトリトラバーサル
叫びクロスサイトリクエストフォージェリ
叫びセッションフィクセーション

などなど色々ありますね。
おぉ恐ろしや・・・ショック!

その中で今日取り上げるのは

「SQLインジェクション」

データベース操作を行うプログラムのパラメータに
SQL文の断片を与えて、情報の改ざんや不正に情報を入手する
恐ろしい攻撃ガーン

よくある攻撃例として

function get_user_info ($id)
{
$sql = " SELECT * FROM users WHERE id = '$id' ";
// 以下略
}

この引数 $id に下記の文字列が与えることにより

'; DELETE FROM users --

$sql は以下のようになり

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

DELETE文によってusersはまっさら空っぽに。。。爆弾

他に

function login ()
{
$id = $_POST['id'];
$pwd = $_POST['pwd'];

$sql = "SELECT * FROM users WHERE id = '$id' AND pwd = '$pwd'";
// 以下略
}

この場合$_POST['pwd']に

' or 'a' = 'a

というパラメータが渡ってきた場合に
ログインできてしまったりします。


これら脆弱性の原因は、開発者の意図しない形にSQL文が改ざんされてしまうことです。

SQL文で文字列はシングルクォートで囲みます。
もし Tom's のようにシングルクォートを含めたい場合は
シングルクォートを重ねて表現ます。

'Tom''s'

SQLインジェクションできてしまうプログラムは
このシングルクォートを重ねる処理が抜けています。
例えば

SELECT * FROM users WHERE name = '$name'
ダウン
SELECT * FROM users WHERE name = 'Tom's'

このようなSQLができあがります。

この場合は 'Tom's' の s' の部分がSQL構文エラーとなります。

では s' の部分がSQLとして意味のある文字列だったらどうでしょう。

SELECT * FROM users WHERE name = 'Tom'; DELETE FROM users --

DELETE FROM users が実行されてしまいます。

これがSQLインジェクション攻撃ですメラメラ

SELECT * FROM users WHERE id = $id
ダウン
SELECT * FROM users WHERE id = 1;DELETE FROM users --

もちろんシングルクォートで囲われない場合も
このような形で攻撃されてしまいます。


では対策です。

SQL文を組み立てる際に意図しない形にSQL文を変えられてしまうのを防ぎます。

方法として、プリペアードステートメント、プレースホルダを利用します。

$stmt = $db->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute(array($id));

プリペアドステートメントは一種のテンプレートのようなものです。
? の部分がプレースホルダで、変数など可変の部分に埋め込んでおくものです。

変数がユーザーの入力でも、自動的に引用符で括られるので
SQLインジェクション攻撃を防ぐことができますグッド!

動的にSQL文を組み立てる際はプリペアードステートメントを推奨します!チョキ


さて、タイトルに「その1」と書いたのですが
その2以降は きっと誰かが書いてくれるでしょうにひひ
こうご期待ニコニコ

ローカル開発でのメール送信の簡単なテクニック(Mac用)

エンジニア 喜納です。





このブログを見てくださっている方にはMacBookを使いカフェなどで開発をされている方もいると思いますが、





今回紹介するのは私が以前個人で仕事をしていた時に





ローカルでの開発時、メール送信する機能を実装した時に用いた方法になります。





最近のMacではPostfixがメールサーバーとしてインストールされています。





きちんとメールサーバーを立てることもできますが





そもそも開発用に使っているだけのローカル環境なので


マシンの中にメールサーバーを立てなくないなぁと思ったのでGmailSMTPサーバーを使用する方法にしました。





こちらを紹介したいと思います。








1.SASLパスワードファイルを作成





$sudo vi /etc/postfix/sasl_passwd





以下を追加します





smtp.gmail.com:587 [ユーザー名]@gmail.com:[パスワード]





上記ファイルを反映するために以下のコマンドを実行しておきます。





$sudo postmap /etc/postfix/sasl_passwd





上記コマンドを実行すると「/etc/postfix/sasl_passwd.db」ができます。





2.Postfixの設定ファイルを編集





$sudo vi /etc/postfix/main.cf





以下を追加しておきます(既に記載されているものは変更やそのままにしておく)





#Minimum Postfix-specific configurations


mydomain_fallback = localhost


mail_owner = _postfix


setgid_group = _postdrop


relayhost = smtp.gmail.com:587





# Enable SASL authentication in the Postfix SMTP client.


smtp_sasl_auth_enable=yes


smtp_sasl_password_maps=hash:/etc/postfix/sasl_passwd


smtp_sasl_security_options=





# Enable Transport Layer Security (TLS), i.e. SSL.


smtp_use_tls=yes


smtp_tls_security_level=encrypt


tls_random_source=dev:/dev/urandom





3.Postfixの起動





$sudo postfix start





これで準備は完了です。





あとは開発中のプログラム内で


設定したgmailのメールアドレスにメールを送信してみましょう。無事に gmail側に受信できていたら成功です。


(ただし、スパムメールフォルダに受信しているかと思いますが。。)



[参考URL] http://www.riverturn.com/blog/?p=239






awkの小技紹介3つ

CyberX データマイニングチーム エンジニアの遠藤です。






CyberXではソーシャルアプリ開発を行っていますが、

アプリを運用していると、

日々いろいろな大量のログが掃き出されています。

(Webアクセスログ、SQLのログ、phpの処理ログなど…)




その大量のログから有用な情報を取り出し集計・分析することは、

データマイニングチームにとっての重要な仕事です。




それでは、どのように集計するのか?

ログをそのままRDBMSのレコードに追加して処理するのもいいですが、

ログから何か”手速く”有用な情報を得たい!

というときにawkコマンドが有効です。




awkコマンドはUNIX上で開発されたフィールド指向のテキスト処理スクリプト言語で、

迅速なテキスト処理を実現します。




そこで、本記事では、

弊社で行っている様々な集計で実際に使用している

awkコマンドの小技3つを紹介します。

(なお、ここで紹介しているawkの処理系は全てgawkです。)








-----------------------------------------------------


[1] 二次元配列の表記法






awkでは擬似的に二次元配列を作成して行います。


(変数名)[【数字】,【数字】]

で表現します。





$ awk '{ i=1; j=1; hoge[i,j]=1000; print hoge[1,1]; }' test.log
1

一方、添字名を表示する際は、

「,」は省略されてしまい表示されないので、

どうしても添字名で「,」を使用したい場合は、

いったん「文字列」として認識させるとよいでしょう。

(awkでの配列における添字は、数字・文字列両方に対応します。)



$ awk '{ hoge[2,3]=1; for(index_id in hoge){print index_id;} }' test.log
23
$ awk '{ index_string="2,3"; hoge[index_string]=1; for(index_id in hoge){print index_id;} }' test.log
2,3










[2] 文字列との一致判定処理

文字列との一致判定処理は2種類あります。


(A) 最初から文字列を指定して、指定文字列行のみに対して処理するパターン

awk '/【文字列】/{ 【処理】 }'

なお、「【文字列】」の部分は正規表現も可能です。


例 ログに「Cy」の文字列があったらその文字列のみを表示する
$ cat test.log
Cyberx
Cyberagent
Sumzap
Applibot
Grenge
Cygames
Quunapp
CABeat
$ awk '/Cy/{print;}' test.log
Cyberx
Cyberagent
Cygames



(B) 処理中にif文で限定するパターン


awk '{ if($0 ~ "【文字列】"){ 【処理】 } }'


なお、"【文字列】"はawk中の変数に置き換えても動作します。


例 ログに「Cy」の文字列があったらその文字列のみを表示する
$ cat test.log
Cyberx
Cyberagent
Sumzap
Applibot
Grenge
Cygames
Quunapp
CABeat
$ awk '{character="Cy"; if($0 ~ character){ print; } }' test.log
Cyberx
Cyberagent
Cygames



(A)は固定文字列と一致判定させるとき、(B)は文字列が固定しないときに一致判定させるときにそれぞれ用いると効果的です。








[3] 時刻計算のための経過秒⇔日付・時刻の相互変換


《日にち・時刻→経過秒に変換》


mktime("【西暦】 【月】 【日】 【時】 【分】 【秒】")




《経過秒→日にち・時刻に変換》


strftime("【dateコマンドのフォーマット指示子】",【時刻変換したい変数】)


例 2012年8月1日0時0分0秒を経過秒に変換して、変換したものを日付・時刻に戻す
$ awk '{second=mktime("2012 08 01 00 00 00"); print second; date=strftime("%Y/%m/%d %H:%M:%S",second); print date;}' test.log
1343779200
2012/08/01 00:00:00





------------------------------




というように、ログの海から有用な情報をすぐに取り出す際はawkで!!!!