HTMLの属性値はなんでダブルクォートで囲むことが推奨されているのか考えてみた
最近セキュリティの勉強をしています。
その中で一つ疑問に思って色々調べてみたけど、なかなか理由がわからないことがありました。
それは、HTMLの属性値を「"(ダブルクォート)」で囲むことを推奨していることです。
HTMLの属性値は、クライアントから受け取った値を使って動的に生成している場合、クロスサイトスクリプティングの脆弱性が発生してしまいます。そのため、HTMLエスケープする必要がありますが、「'(シングルクォート)」や「"(ダブルクォート)」の引用符で囲まなければ、たとえエスケープしていてもクロスサイトスクリプティングが可能です。
例えば以下のように、攻撃文字列の間にスペースを入れます。
<input type=text name=name value=<?php echo(htmlspecialchars($_GET())); ?>> ↓ <input type=text name=name value=hogehoge onmouseover=alert(1)>
このように、クロスサイトスクリプティングが成立してしまいます。ただ、なぜ「'(シングルクォート)」ではなく、「"(ダブルクォート)」で囲むことが推奨なのかがわかりませんでした。なぜ「'(シングルクォート)」じゃいけないのか・・・
「"(ダブルクォート)」の推奨に関しては、徳丸本とか、その他いろんなところで、そんな感じのことが書いてありました。
この件に関して、私の調査不足かもしれませんが、検索してもなかなかわからなかったので、以下のように推測してみました。
- 動的にHTMLの属性値を生成するとき、クロスサイトスクリプティング対策のため、属性値をHTMLエスケープし、且つ「'(シングルクォート)」か「"(ダブルクォート)」で囲む
- HTMLをデバッグするときにソースコードを見るが、不必要な文字列までエスケープされてしまうと、デバッグがしにくい
- 英語圏では、日常的に文章等に「'(シングルクォート)」が利用されるので、デフォルトでは「<」、「>」、「&」、「"」の必要最小限のみをエスケープするように関数を作成
- エスケープ用の関数を利用する際に、デフォルトでは「'(シングルクォート)」がエスケープされていないことを知らずそのまま使ってしまう。そして属性値を囲む引用符にポリシーがないまま開発してしまい、クロスサイトスクリプティングの脆弱性を作ってしまう
- そのため、HTMLの属性値は「"(ダブルクォート)」で囲むことを推奨している
と、こんな感じで考えてみました。
なので、「'(シングルクォート)」で囲ってはいけないわけではなく、デザイナーとか、低レベルのプログラマの人とかと連携して開発する場合は、とりあえずHTMLの属性値を「"(ダブルクォート)」で囲むことを徹底させておけば、脆弱性が作り込まれる可能性を少しでも低くできるんじゃないかということです。
XMMPボットサンプル
たいぶ古いけど、以下を参考にXMPPのボットのサンプルを試してみました。
http://d.hatena.ne.jp/Syo-Takasaki/20071121/1195644386
- 環境
- OpenFire version 3.8.1
- ruby 1.9.3
OpenFireに対してTLSで接続しようとすると、なんかうまくいかないようです。
Jabber::Client.new した後に、インスタンスの中のスコープで
@allow_tlsをfalseにするとうまくいきました。
require 'xmpp4r' user = "USER@DOMAIN" pass = "PASS" client = Jabber::Client.new(Jabber::JID.new("#{user}/bot")) client.instance_eval do @allow_tls = false end client.connect('HOST', PORT) client.auth(pass) client.send(Jabber::Presence.new.set_show(:chat)) puts "Connected ! send messages to #{user}." mainthread = Thread.current client.add_message_callback { |msg| if msg.body puts "from:#{msg.from} body:#{msg.body}" m2 = Jabber::Message.new(msg.from, "ECHO:#{msg.body}") m2.type = msg.type; client.send(m2) # Exit if msg.body == 'exit' m2 = Jabber::Message.new(msg.from, "Exiting ...") m2.type = msg.type; client.send(m2) mainthread.wakeup end end } Thread.stop; client.close; puts("Done.");
ubuntu12.04にmod_mrubyをインストールしたときの手順メモ
MacのVirtualBox上にubuntu12.04を入れて、そこにmod_mrubyをインストールしました。以下のURLを参考にさせて頂きました。
http://d.hatena.ne.jp/techmedia-think/20120618/1340021311
ubuntu上で以下のコマンドを実行していきます。最小構成でのインストール直後の状態です。
開発ツールインストール
# aptitude install build-essential # aptitude install libreadline-dev libssl-dev zlib1g-dev # aptitude install git-core curl
aprのインストール
# cd /var/tmp # mkdir work # cd work/ # wget http://ftp.jaist.ac.jp/pub/apache//apr/apr-1.4.6.tar.gz # wget http://ftp.jaist.ac.jp/pub/apache//apr/apr-util-1.4.1.tar.gz # tar zxf apr-1.4.6.tar.gz # cd apr-1.4.6/ # ./configure # make # make install # cd .. # tar zxf apr-util-1.4.1.tar.gz # cd apr-util-1.4.1/ # ./configure --with-apr=/usr/local/apr # make # make install # cd ..
pcreのインストール
# wget -O pcre-8.32.tar.gz "http://sourceforge.jp/frs/g_redir.php?m=jaist&f=%2Fpcre%2Fpcre%2F8.32%2Fpcre-8.32.tar.gz" # tar zxf pcre-8.32.tar.gz # cd pcre-8.32/ # ./configure # make # make install # cd ..
apacheのインストール
# wget http://ftp.kddilabs.jp/infosystems/apache//httpd/httpd-2.4.3.tar.gz # tar zxf httpd-2.4.3.tar.gz # cd httpd-2.4.3/ # ./configure --enable-mods-shared=all --with-apr=/usr/local/apr --with-apr-util=/usr/local/apr # make # make install # cd .. # /usr/local/apache2/bin/apachectl start usr/local/apache2/bin/httpd: error while loading shared libraries: libpcre.so.1: cannot open shared object file: No such file or directory # ln -s /usr/local/lib/libpcre.so.1 /lib/libpcre.so.1 # /usr/local/apache2/bin/apachectl start
Rubyインストール
# aptitude install ruby1.9.1 # gem install rake
mod_mrubyのインストール
# git clone https://github.com/matsumoto-r/mod_mruby.git # cd mod_mruby/ # git submodule init # git submodule update # cd mruby/ # rake CFLAGS="-O3 -fPIC" ・・・ rake aborted! Command failed with status (127): ["bison" -o "build/host/src/y.tab.c" "src/p...] tasks/mruby_build_commands.rake:29:in `_run' tasks/mruby_build_commands.rake:169:in `run' src/mruby_core.rake:14:in `block (2 levels) in <top (required)>' Tasks: TOP => default => all => bin/mruby => build/host/bin/mruby => build/host/lib/libmruby.a => build/host/src/y.tab.o => build/host/src/y.tab.c ・・・ # aptitude install bison # rake CFLAGS="-O3 -fPIC" # cd .. # vi Makefile.in //以下2行を修正 APXS=/usr/local/apache2/bin/apxs APACHECTL=/usr/local/apache2/bin/apachectl # ./configure # make # make install ※Warningは無視していいとのこと。 https://twitter.com/kyonfuee/statuses/282029734152507392 # /usr/local/apache2/bin/apachectl restart
mod_mrubyのサンプル作成
# cd /usr/local/apache2 # vi htdocs/test.mrb r = Apache::Request.new() r.content_type = "text/html" Apache.rputs("<h1>test</h1>") r.filename = "/usr/local/apache2/htdocs/index.html" Apache.return(Apache::OK) # vi conf/httpd.conf ・・・ AddHandler mruby-script .mrb //追記 ・・・ <IfModule mruby_module> //追記 mrubyTranslateNameFirst /usr/local/apache2/htdocs/test.mrb </IfModule> # bin/apachectl restart
適当なURLにアクセスして、
うまくでっかい文字でtestとIt works!が表示されればOKです。
Gehirn(ゲヒルン)のRS2登録と、baserCMSのインストール
Gehirn(ゲヒルン)のRS2がどんなものか試してみたくて登録してみました。デフォルトでPHPが使えますので、とりあえずbaserCMSをインストールしました。
特に難しい手順はなく、と言うかびっくりするぐらいにあっさりと完了し、しかも標準でWAF(Webアプリケーション・ファイアウォール)がついているので、アプリケーションのセキュリティも高く保てます。
以下、簡単ですが手順を書いておきます。
Gehirn(ゲヒルン)のRS2を登録
1. まずはGehirn(ゲヒルン)でアカウントを取得
https://cp.gehirn.jp/#!/register
2. コントロールパネルから請求先情報を登録する
https://cp.gehirn.jp/#!/ID/account
3. RS2を新規契約
https://cp.gehirn.jp/#!/RS2/signup
※詳細な手順は以下に記載されています。
http://support.gehirn.jp/manual/rs2/idcreate/
SSHでログイン
コントロールパネルのRS2の、契約一覧から、対象プランの「設定」ボタンをクリックします。
次に、SSHタブから、「公開鍵の管理」ボタンをクリックし、
そこから、「キーペアを生成する」ボタンをクリックしてPKCSの2048bitでキーペアを生成すると、ローカルPCに秘密鍵がダウンロードされます。
そしてダウンロードした秘密鍵の権限を変更し、その鍵を指定してGehirn RS2のサーバへSSHログインします。
$ chmod 600 xxxxx.key // ダウンロードされるファイル名は毎回異なります $ ssh -i xxxxx.key [SSHユーザ名]@[IPアドレス]
baserCMSインストール
ドキュメントルート以下に(コントロールパネルで設定可能)、baserCSMをダウンロードし、展開します。
$ cd /home/{ホスト名}/public_html $ wget http://basercms.net/packages/download/basercms/2.0.5.1 $ unzip 2.0.5.1
mysqlのデータベースを作成します。
コントロールパネルのRS2タブから、データベースタブをクリックし、「データベースを追加する」ボタンをクリックしてデータベースを作成します。
今回は手動で登録はありませんが、以下のようにデータベースへアクセスできます。
$ mysql -u {ユーザ名} -p // ※ユーザ名は、登録したデータベース名と同じ
そしていつも通り下記のURLへアクセスし、インストールを開始します。
http://{ホスト名}/basercms
rubyでdowncase VS 正規表現
ついでにupcaseも。
大文字と小文字を区別せずに大量のデータを比較する場合、downcaseが速いのか正規表現の方が速いのか、確認してみました。コードは以下です。(こんなんでいいかな・・・?)
require 'benchmark' a = "BaNaNa RiNgo BuDo IchiGO" b = "banana RINGO budo ICHIGO" n = ARGV[0].to_i puts Benchmark::CAPTION puts Benchmark.measure{ n.times { a.downcase == b.downcase } } puts Benchmark.measure{ n.times { a.upcase == b.upcase } } puts Benchmark.measure{ n.times { a =~ /^#{b}$/i } }
実行結果は以下です。1000回、10000回、100000回で実行しました。
$ ruby test.rb 1000 user system total real 0.000000 0.000000 0.000000 ( 0.000889) 0.000000 0.000000 0.000000 ( 0.000854) 0.000000 0.000000 0.000000 ( 0.004305) $ ruby test.rb 10000 user system total real 0.010000 0.000000 0.010000 ( 0.011290) 0.010000 0.000000 0.010000 ( 0.010139) 0.040000 0.000000 0.040000 ( 0.040895) $ ruby test.rb 100000 user system total real 0.100000 0.000000 0.100000 ( 0.095221) 0.090000 0.000000 0.090000 ( 0.094485) 0.370000 0.010000 0.380000 ( 0.382025)
断然downcase(upcase)の方が速かったです。
世の中の常識ですかね?
今まで調子に乗って正規表現でやってました。
反省します!
dotcloudでデプロイしようとしたらコマンドをアップロードしろって言われた
dotcloudでデプロイしようとしたらいきなりこんなこと言われたのでメモ。
$ dotcloud push --all [アプリ名] Warning: A new version of the DotCloud cli is available: 0.9.1 This new version is an important update and several changes have been made to improve developer workflow and usability. You can learn more about migrating here: http://docs.dotcloud.com/0.9/guides/migration/ When you're ready, you can run the following commands to upgrade to the latest version: $ sudo pip uninstall dotcloud dotcloud.cli $ sudo pip install --upgrade dotcloud
とりあえず以下でデプロイできました。
なんかコマンドのオプションが変わっていますね。また必要に応じて調べることにします。
$ sudo pip install --upgrade dotcloud $ dotcloud push -A [アプリ名]
PHP Matsuri 2012 参加してきました!
まず、参加してよかったこと。
それは、自分がどんだけしょぼいかってことを再確認できたことです・・・みなさんすごかった。レベルが高い。。まだまだ自分も頑張らなくては・・・(涙)
やってることのレベルも高いですし、なによりプレゼンがうまい人が多かった印象があります。みんな慣れてるって感じで、話もすごく面白くて爆笑の嵐でした。とは言っても、初心者やレベルの低い人たちにも優しくウェルカムな感じで、色々とサポートしてくれますし、誰でも安心して参加できるんじゃないかなーと思います。PHP知らなくてもきっと大丈夫です!!でもノートPCは必ず持って行きましょう。一応ハッカソンなので(笑)
それから、闇で行われた「アンリーダブルコード選手権」もめちゃくちゃ面白かったです(この時点で深夜0時)。異様な音楽とともにへんなグラサンをかけた関西弁の2人組があらわれ、続いて発表者が5人、顔がばれないように覆面で登場してきました。でも知ってる人には余裕でばればれ。全員の話が、もれなく面白かったです。ちょっと耳が痛いところもいくつかありましたが、さすがにこれはないわー(笑)っていうコードばかりでした。以下、セッションの一つ。スライドを上げてくれたようです。
https://speakerdeck.com/komagata/i-dont-like-such-a-php-project
そして深夜に行われたファミコン大会(このとき、1時か2時くらい)。一生懸命コード書いてる後ろでピコピコやってました。音が懐かしすぎて、気になって気になって仕方ありませんでした・・・
そして、あっというまに夜も明け、LT大会が始まりました。これも非常にレベルが高かった。やってる内容も、プレゼンも。ジャンルも幅広くて色々勉強になりました。
内容はこの辺にまとめられています。
http://togetter.com/li/400807
自分が今回やったことは、複数人でのWebアプリケーション開発です。PHPMatsuriなので、一応CakePHPを使いましたが、ほぼJavaScript(Pusher(Websocket)、JQuery含む)でした。セッションの合間と、一晩丸々使ってかなり進みましたが、思ったところまで進まず、LTは断念。。無念。。。次回は必ず・・・
それにしてもあの大トリをつとめた13歳のガ・・・子どもはなんだったんだろう・・・やけに場慣れしてる感じで、見た目は子ども、振る舞いは大人、コナン君かと・・・
まあなにはともあれ、楽しくてあっという間の2日間でした。とりあえず、ほとんど寝てないので寝ます!