みなさま、おはようございます、こんにちは、こんばんは。年の瀬ですね。近況“やばい”の一言ですが、Tekka Advent Calender 2018の17日目の記事を投稿します。(今日はきっと17日です。)
Tekkaや個人で何か作った訳ではないですが、ニッチなTipsをご紹介します。
adventar.org 余談ですが、今年を漢字で表すと「決」です。
●概要
Microsoftのパブリッククラウド AzureのApp Serviceで、IISの自作モジュール(Managed Module)を動かしてみよう!という趣旨の記事です。App ServiceのFreeプラン内でできることをご紹介します。Azureについて調査していくと、むしろ、無料プランでここまでできるのか……と驚きました。本番環境向きのプランではないにしても、自由度が高く素晴らしい。
簡単に補足すると、App ServiceはWindowsのWebサーバ「Internet Information Services」と呼ばれるもので動いており、激安レンタルサーバなどでよく聞くApache等とは違います。軽くWebサーバ機能として利用する分には、IISを深く意識する機会はないかと思いますが、ASP.NET絡みで開発する場合は、ASP.NETのライフサイクルの中身くらいは理解しておくと良さげです。IISの仕組みは奥が深く、魅力があります。ASP.NET/IISの仕組みを語りだすとコミケ用の薄い本が出来てしまうので、今回は割愛します。
動かすことが目的なので、詳細には取りまとめません。
- Microsoft/Azureアカウントの取得
- Azureサブスクリプション契約(無料枠, 無料プラン)
- App ServiceでWebアプリの作成
- Webアプリケーションのデプロイ(デフォルトドキュメントのままでも可)
ここまで終わっていることを想定しています。本稿の内容は下記の通りです。
- サンプルのIISマネージドモジュールのビルドする
- FTPSで特別なディレクトリへDLLを配置する
- web.configを作成し配置する
それでは簡単に、IISのマネージドモジュールの作り方、Azure App ServiceへFTPSでの接続方法、IISのモジュールをEnableする方法をご紹介します。
●サンプルのIISマネージドモジュールのビルド
ではさっそく、IISマネージドモジュールを作ってみよう
1. Visual Studioを立ち上げる(2015 or 2017を想定)
2. 空のプロジェクトを作成する
テンプレート→Visual C# >クラスライブラリ(.NET Framework)
名前→ここでは「CustomHeader」と命名しました。
ターゲットフレームワーク→.NET Framework 3.5 (4.xでも可) ※後方互換のため
3. 「System.Web」を参照に追加する
参照のコンテキストメニューから「参照の追加」をクリックします。
検索ボックスに「System.Web」と入力し、中央のリスト内の左のチェックボックスに該当の「System.Web」にチェックを入れてOKボタンを押下します。
4. サンプルコードの貼り付け
Class1.csに下記のコードをそのままぺた貼りします。
4. ソリューションのビルドをする
5. 出来上がったバイナリ(DLL)を取り出す
<プロジェクトディレクトリ>\<プロジェクト名>\bin\Debug にDLLがあるので、任意の場所にコピーするか、覚えておきます。(もしくは\Release)
・FTPSで特別なディレクトリへDLLを配置する
1. FTPSでAzure App ServiceのWebアプリのディレクトリにアクセスする(WinSCP)
AzureのPortalから、FTPSの資格情報を取得します。対象のWebアプリのデプロイセンターからFTP/FTPSと遷移すると良いでしょう。スクリーンショットでは、テスト用に「rein.azurewebsites.net」というアプリケーションを作成しました。今回はFTPクライアントとしてWinSCPを使用します。
資格情報をそのままコピペします。
転送プロトコル→FTP ※SFTPではありません!
暗号化→暗黙のTLS(Implicit) ※Explicitでもいけますが、Azureでは平文21/tcpを待ち受ける設定もできるので、Implicitが妥当でしょう
ホスト名およびユーザ名とパスワード→コピペしよう
無事FTPSでログインできると\wwwrootが見えます。これで下準備は完了です。
2. 特別なディレクトリ「\bin」の作成
wwwroot直下に「bin」というディレクトリを作成します。
3. 自作モジュール(DLL)のコピー
そのまま普通にコピーしてください。これで、自作モジュールの配置は終わりました。
・web.configを作成し配置する
1. 下記の内容のweb.configを作成します
2. wwwroot直下に「web.config」を配置する
最終的には上記の画面のようになっているでしょう。以上で、自作モジュールの導入は完了です。
●動作確認
wwwrootのデフォルトドキュメントにアクセスしてみましょう。普通に直下にアクセスするだけです。例えば、https://rein.azurewebsites.net/ です。
コケてなければ「Your App Service app is up and running」というメッセージのページが出てくると思います。見た目変わってないので、どこを確認するんだ、ということですが、HTTP Response Headerを確認します。Local Proxyを使って通信をInterceptしてみてください。Fiddler, Burp, ZAPなんでもいいです。(見るだけならFiddlerが楽です。)
Burpで見た場合のHTTPレスポンス例です。選択部分に注目してください。「X-Powered-By: CustomHeader/1.0.0.0」というヘッダが追加されていることが分かります。これでちゃんと動作しているか確認できました!
話が戻りますが、サンプルで作ったモジュールは一体何するものなのかというと、命名通り「X-Powered-By: CustomHeader/1.0.0.0」というヘッダを追加するだけのしろものです。
●後片付け
遊び終わったアプリケーションは停止して吉です。ちなみにデフォルトのままだと平文のFTPが空いてる状態なので、無効にしておきましょう。
●任意のDLLが動く、ということ
Azure App Serviceの無料プランでも、モジュールが組み込めるこの柔軟性はわくわくしますね。サンプルコードはヘッダ追加するだけですが、書きようによっては、遊び甲斐がありそうです。これは先出し調査結果情報ですが、Azureは基本的にオンプレミスのIIS(という言い回しは正しいか分かりませんが)と遜色なく使えそうで、VCでコンパイルしたDLLでも見事期待通りに動いてくれました。具体的には、自作・独自で実装ないしバイナリさえ用意すれば、Azure App Serviceが実装していない拡張機能を使うことが出来ました。
IISが標準提供されている機能をDevelopment用途として使っている理解ですが、中の人判断でまずかったらご一報ください。
azure.microsoft.comここを基準として読みました。
●構想、そして振り返り
雑談です。遡ること4-5年前、オープンソースでセキュリティ系のプロダクト作りたいなと、もやもやして、そういえばIISのApacheでいうmod_security的なのってあったけ、と思い立ち作り始めたのが「NachtWal」です。これがIISのモジュールを作ろうとしたきっかけになりました。
github.com 現在はXSS(Reflected)をなんちゃってブロックする程度で停滞していますが、作り上げたい思いは強くあります。構想や技術的な面はあるのに、リポジトリにコミットまで出来ていないことが多々あり、悔しく思います。例えば、ASP.NETライフサイクルにおいて、精度の課題は別にしてStored-XSSを検知・防御する実装は可能であることを個人で実験・検証済みですし、AzureのApp Serviceで動くことも確認していて、クラウド対応でDLLを放り込んでおけば、勝手に良きに計らってくれるぐらいには作りたいですね。ただ、マネージドモジュールにおいてのHTTPのIntercept行為には致命的な問題があり、ハンドラマッピングに基づき実行されたタイミングで、どうやらNamed pipeでごにょごにょやってるそうなんですが(確証はないです)、マネージドモジュールはBodyを横取りしてしまうIssueにぶちあたってます。この問題について、的確に言及しているブログ記事は1件見つけましたが、それ以上の情報はなく困ってます。
mvolo.com 解決策はあって、「ネイティブモジュール」であれば起こらないということは分かってます。ああ、VC++をやるべき時が来てしまったようだ。もっと早くVC++にステ振りしておけば良かった。次やる言語はVC++だ。
Microsoft界隈の方々と親睦を深めていきたいお気持ち高まってきた。詳しい人とお話したいし、機会に恵まれれば参画していきたい。お気軽にコンタクトくださいませ。来年のキーワードは、Azure, ASP.NET/IIS, Securityでやっていきたい。
Twitterで何度も投稿していますが、この本はちょーおすすめ。
それでは、良いお年を。