16:39表題の通り、cron等で適当にアクティブチェックのプログラムを書き捨てるならMojo::UserAgentが便利ですよというお話。MojoliciousはPerl標準モジュール以外に依存していないので、サクッとインストールして実行環境を用意することができる(まあディストロのパッケージマネージャでインストールすればたいていのものはストレスなくインストールできますが)サンプルコード以下コードは監視対象HTTPサーバへアクセスした後、ステータスコードが200,301以外を返された場合にSlackへ通知する例。このコードを10分間隔で実行した場合、監視対象の障害が継続していれば10分間隔でSlack通知が来てしまう。満たした場合だけSlack通知するように書けば良い。SQLiteの簡単なCRUD操作を提供してくれるMojo::SQLiteというラッパーモジュールがあるので使うとよい。01:43安全なウェブサイトを作るためにネット上の情報を漁っていると、「入力バリデーション」と「パスワード」についてクリティカルなものがあったりする。今回はこのあたりについて自分の考えをまとめておく。入力バリデーション入力のバリデーションはSQLインジェクションの根本的な対策にはならない。SQLインジェクションへの根本的な対策は、プリペアードステートメントを利用すること。クライアントサイドの入力バリデーションは、ウェブサイトの利用者へ「入力値の条件が満たされていない理由」を親切丁寧に伝えるために過ぎない。攻撃者はその気になればHTTPリクエストのすべての内容を生成することができるということを理解しておかなければならない。「if,caseで型を含めて等しいかを判定して分岐」するか、または、「あらかじめ用意した連想配列(辞書)のキーとして存在するかをチェック」するという方法が最強と思われる。現実的な方法お使いのフレームワークが用意しているバリデーション機構を利用してください。その正規表現、大丈夫?一つの正規表現で無理やり入力値のバリデーションを実現することは避けた方が良い。ReDoS対策の観点から、できるだけシンプルな造りになるように処理をステップごとに分割し、一つ一つのコードを単純化することを検討しよう。メールアドレスのバリデーションを自前の一行正規表現で済ませてしまうのはやめよう。まって、その正規表現、本当に本当に大丈夫?入力文字列の長さを調べたいのならば、例えばPHPであればstrlenで判定できる。以下の処理をシーケンシャルに実行して、条件に反していたらその時点でリジェクトすればオッケーだと思うよ。「クラックされやすいパスワードリストに載っていないかを判定」しつこくてごめんね。その正規表現、本当にほんと~~に大丈夫?正規言語の限界、イプシロン遷移、バックトラック、DFAとNFAについて考えたことがない、「そんな単語聞いたことも無い」という状態であれば、頑張って複雑な一行の正規表現で済ませてしまうのは絶対にやめよう。「0回以上繰り返し」の量指定子は地雷です。*と{0,N}が該当しますね。https://twitter.com/adokoy0001/status/824580874704293889バックトラックが何なのか分かっていないのであれば、「極力正規表現を使わない方法」を模索しましょう。判定、などなど、有限オートマトンであるところの正規表現ではスタックがないので不可能です。いうのはプッシュダウンオートマトンであるところの文脈自由言語とかならできます。正規表現を積極的に使うべきシーンは、文字列の置換やパターンマッチした部分を抽出する処理などでしょう。それでも正規表現を使いたい場合どうしても入力バリデーションを正規表現一発でやりたいのであれば、以下のURLにある正規表現のやばい挙動を完全に理解した上でやりましょう。https://regex101.com/r/GM8BLm/2/debugger最後の量指定子{1,3}を、{1,50}にしてみよう。https://regex101.com/r/GM8BLm/3/debuggerおわかりいただけただろうか。50から70とかに増やすとタイムアウトになったりする。ここで重要なのは以下である。数字を増やすと指数関数的にステップ数が増える短い入力でもバックトラック地獄は起こりうる短くシンプルな正規表現でも危ないものは危ない量指定子*を使わなくても、イプシロン遷移があれば危ないこの投稿が何かのお役に立てれば幸いである。15:24ウェブアプリのセキュリティ対策について無責任なことをネットで書くことはご法度であり、また、セキュリティ対策を講じる担当者もネット上の情報を安易に受け止めてはいけない。このドキュメントも例外ではない。JPAが公開している安全なウェブサイトの作り方、脆弱性情報データベースの情報をこまめにチェックすること。ネットワーク構成とファイアウォールアプリケーションとストレージは分離し、HTTPを受け付けるサーバーとそのportのみをpublicに晒す。ロードバランサを利用するのであれば、LBの80,443番ポートのみpublicに晒し、APPとDBはローカルネットワーク内部のみのトラフィックを受け付ける。各サーバにアクセスするために、マネジメント用のサーバMGMTを設けると良い。その場合の構成は、LB(80,443ポートを晒す),MGMT(カスタマイズされたsshポートを晒す),APP(ローカルのみ),DB(ローカルのみ)中間者攻撃クラウドサーバへの初回SSHアクセス時は、予めクラウド基盤で提供されている該当サーバのフィンガープリントを照合する。運用チームだけが用いるウェブコンソールであっても、クラウド上など社内ネットワークの外に置かれている以上は必ず中間者攻撃を想定した構成にしなければならない。Encryptを入れて中間者攻撃を確実に防ぐ」こと。サーバー本体のアップデートHTTPサーバーおよびリバースプロキシのセキュリティパッチは必ず適用する。無停止で手軽にメンテナンスできるような構成が望ましいため、グローバルIPをサーバにほぼゼロダウンタイムでアタッチできるサービスを利用すると良い。key認証とパスワード認証を併用することが望ましい。アプリへのログインに用いられるパスワードは必ずsaltを付けてハッシュ化する。saltは共通のものだけを使うのではなく、レコード毎に生成しなければならない。システム運用チームは、特権的なウェブコンソールでアカウントを共有してはならない。運用チームのメンバーが退職した際にはそのアカウントをログイン不能な状態にするか、可能であれば削除すること。外部システムとの連携に用いられる認証情報は、アプリへのログインに用いる情報とは完全に分離し、APIアクセスキーやToken等として簡単に失効させることができるようにすること。S3の認証情報をHTTPサーバの環境変数にセットした状態で、phpinfo()が呼ばれるページをプロダクションに放置してしまうなど)ソースコード中に外部システムのクレデンシャルを直接書き込まないこと。認証情報をhiddenパラメタに含めてはいけない。適切なHTMLエスケープ機構を利用せずにユーザーからの入力値やDBから読みだした値を出力することはXSSに繋がる。副作用のある操作は全てCSRF対策が必要。顧客自身がページをWYSIWYGエディタ等でカスタマイズできる機能がある場合、それ自体がXSS脆弱性となっており、さらにページ編集機能にCSRF対策が施されていない場合はフィッシングサイトへの誘導に利用される危険性がある。決済機能クレジットカード番号などは間違ってもサーバに保存してはならない。デバッグ目的でカード番号をログに保存してはいけない。決済時のみ決済サービスへjumpする機能を利用することができるのであれば、利用する。何らかの攻撃が成功し決済サービスへのjump先がフィッシングサイトへ書き換えられてしまう事態を想定し、システムの外から定期的に(数分間隔)決済ページへのリダイレクト先を監視するサーバを立てること(具体的には、決済ページに遷移するまでのアクセスを順次実行するUserAgentを作ってcronで定期的に実行して監視。)SQLインジェクション何らかの値をリテラル・変数問わず入力する場合、必ずプリペアードステートメントを利用する。プリペアードステートメントのエミュレーションはやはりエミュレーションに過ぎないので安全ではない。table_a」等、「かならずこのSQLにしかならない」ということが確定している定型文などに限ると考える。原則として、「本物の(エミュレーションではない)プリペアードステートメントを利用すること以外にSQLインジェクションの有効な対策は存在しない」と考えるべきである。二段階(二要素)認証とアクティビティ通知アプリケーションの利用者が必ずしも高いリテラシーを持っているとは限らない。パスワードは辞書攻撃等で突破される前提で考えておき、二段階(二要素)認証を必ず導入しておくこと。異常な回数のログイン試行やログインの成功などを、事前に登録されたアカウント本人のメールアドレス等にそのアクティビティを送る。builderのselect系についてのみ、実用的な例を示しておく。insert,update,delete系はORMを使ったほうが効果的な場合もあるだろうが、FuelPHPのModel自動生成機能はリレーションをまともに読んでくれない(リレーションを手作業で張る必要あり・・・)ので、DBの仕様を頻繁に変えるような開発初期段階ではかなり大変で、Modelの更新も慎重にやらなきゃなので、アンチパターンに入りがちかもしれない。PerlのDBIx::Classとスキーマローダーに慣れている身としては結構厳しい。Builderがコスパ的にかなり良いと思っています。TABLES");この例は「かなり強いLOCKを割と長い時間維持する」書き方なので、マネをするとしたら非機能要件に合っているかどうかを吟味してください。17:56PHP歴がそろそろ半年になろうとしているので、私的なエチュードであるところの「ある言語で複雑なデータ構造を再帰的に全てスキャンするプログラム」を書いてみた。動作は表題の通りです。部分で連想配列か配列かを判定している。16:35以前お話したPHPのデプロイについて、Deployerというツールを使ってDSLを書いてみたところいい感じだった。会社のプロダクトではFuelPHPというWAFを使っているが、レシピはcommonなもので十分だった。https://deployer.org/インストールは公式に書いてある通りでOK。/usr/local/bin/dep前提条件としては、デプロイスクリプトを実行するマシンは、アプリサーバーに公開鍵認証でsshログインできることと、sudoコマンドでパスワードを聞かれないこと、apacheの設定でユーザーディレクトリの設定を済ませていることぐらい(必要なコマンドだけnopassにしてください)。デプロイ対象サーバーの設定として、以下のような形式で設定を書き込む。アプリサーバーのアプリ展開path等に使う。リモートホストの指定。リモートホストのユーザー名。'success']);アプリケーションはリモートの/home/app_user/appに展開され、/home/app_user/app/currentのシンボリックリンクが指し示すディレクトリが最新のものになる。16:07元PostgreSQLユーザー故、MySQLのトランザクションとテーブルロック獲得処理を逆に取り違えて致命的なミスをしてしまうところだった。以下のようなPostgreSQLの(他セッションからの読み取りを含む)排他ロックが要求されるトランザクション処理があると仮定する。EXCLUSIVE)獲得」->「アトミックかつ不可視にしたい処理」->「トランザクションをコミット」->「ロックを自動的に開放」という流れになる。ロックモードの指定は「ロックを獲得する対象テーブル(レコード)の状態をどのように変更するか」という観点での名前になっている。それに対してMySQLでは、「autocommitを0に設定」->「排他ロックを獲得」->「暗黙的にトランザクションが開始される」->「アトミックかつ不可視にしたい処理」->「トランザクションを明示的にコミット」->「明示的にロックを開放」という流れ。ロックモードの指定はREADとWRITEがあり、これは「ロックを獲得しようとしているセッションがこれから実行する処理は、読み込みだけなのか、それとも書き込みが含まれるのか」という観点での名前になっている。複数テーブルに及ぶ更新系処理では、それら全てのテーブルに対して排他ロックを「一文で」獲得する必要がある。複数ステートメントでロックを獲得しようとしても、その前のロックは勝手にアンロックされる(というか、ロック獲得と同時に暗黙のトランザクションが開始される)。そのほかにもいろいろある。https://dev.mysql.com/doc/refman/5.6/ja/internal-locking.html・・・と、PostgreSQL使いからするとかなり神経を使う激ヤバ仕様。16:37社会復帰してまだ半年にもならないですが、1年半以上パソコンを触っていないという浦島太郎状態から徐々にキャッチアップできるようになってきたような気がする(錯覚)最近AWSで本番環境の構築作業をしていたので、メモ代わりに気付いたことを記しておく。Altus、IBMクラウドでWebサーバを構築したことはあります。AWSは個人アカウントの無料枠で試しただけ)VPCのアドレス空間まず初めに、展開するサービスの要件に合わせたアドレス空間でバーチャルプライベートネットワークを構築する。確保しておけば大丈夫だろう。AWSで複数のサービスを展開することや、不要になったサービスを事業譲渡などで他社に引き渡すことを考えると、プライベートネットワークをサービス単位で構築しておいた方が良い(サービス間連携はプライベートネットワーク内の通信以外の手段で実現する)。む既存のネットワークと重ならないアドレス空間が好ましい。VPCには一つ以上のサブネットが必要。VPCで確保したアドレス空間と同じものを割り当ててよい。インターネットゲートウェイを作成VPCとインターネットを相互接続するためにはインターネットゲートウェイが必要。1つ作成し、割り当てる。Egress-OnlyではインターネットからVPCに対するアクティブな接続はできないので注意(SSHなど)。ここまで設定すればうまく動きそうに思えるが、後述するデフォルトゲートウェイの設定を書いてやらなければまだ動かない。作成したVPCのルートテーブルに、0.0.0.0/0の通信先をインターネットゲートウェイに向けるように設定し、作成したサブネットにも関連付けを施す。これでやっとうまく動く。15:33Perlのゼロダウンタイムでグレイスフルなホットデプロイに慣れていたせいで、phpのプロジェクトをデプロイ(本番環境で新しいプログラムに入れ替える)する際のアトミシティを考えていなかった。今時自前で作るのはばかばかしいが実際に作るとしたら、ブルーグリーンデプロイメントのように、HTTPサーバで設定しているドキュメントルートの指し示すディレクトリをシンボリックリンクにして、それをアトミックに張り替えるスクリプトを組めば良いらしい。https://qiita.com/dalance/items/d2d2feb720172036fd22ちなみに普段使いのFuelPHPではDeployerというのが良く使われている模様。ゼロダウンタイムと銘打っているので、これも恐らく同様にシンボリックリンクを使ってやってくれているものだと思われる。(DBへのコネクションをpersistentに張っている場合はどうなるんだろう?)アプリケーションを実行しているプロセスのグレイスフルなリスタートをするようなものがphpに無いか探したが、見つけられなかった。11:02表題の通り。Index作成時にHASHを指定できるが、実際に作成されるのはBTREEインデックスになるとのこと。ややこしいのがInnoDBは適応的ハッシュインデックスという機能を持っており、稼働状況から自動的に必要なハッシュインデックスが構築され、それが利用されるとのことでした。YokodaTweet。