LoginSignup
10
7

More than 5 years have passed since last update.

「開け、ごま!」で使えるようになるWebサーバーを作りたい!

Last updated at Posted at 2018-08-18

やりたいこと

最初はどのページもアクセスできないけど、
秘密の順番でパスにアクセスしていくと、使えるようになる! 
ようなサーバーを作りたいです

一言でいえば、ポートノッキングのHTTP版みたいなものを作りたいです。

ポートノッキングで有名なツイートです。


ポートノッキングというのは、決められたポートを決められた順番で叩くことでファイアーウォールに穴を空けられるような仕組みのことです。
(引用:ポートノッキングで10秒間だけsshdを公開する設定 - hnwの日記

HTTP上でノッキングしたい理由

ポートノッキングだとHTTPSを使って暗号化していても、ポートの部分は暗号化されないはず1 なので、傍受しようと思えばできてしまうのかなと思いました。そこで、HTTPS上で、ノッキングすればHTTPヘッダもボディも暗号化されるため、ノッキングも暗号化できるのではと思い、セキュアになるかなと思ってやりたくなりました。また、HTTPを使うので、ブラウザからも簡単にノッキングできるので、ポートノッキングより容易にできるのではないかというのも一つ理由です。

設計の方針

  • なるべくあらゆるサイトに適用したいので、リバースプロキシとして作り、隠したいサーバーのURLを指定するようにする2
  • Dockerイメージを用意して、Docker Composeで簡単にノッキングサーバを適用できるようにする
  • オプションで自動でクローズしたりノッキングの間隔が空きすぎるとリセットするなどセキュアにする
  • HTTPSの対応はHTTPS-PORTALやHerokuなどのようにHTTPをHTTPS化してくれるようなシステムの利用を想定しています

http-knockingの使い方(npm)

以下のようにnpmで簡単にインストールができるようにしました。コマンドとして利用するので-gオプションでグローバルにインストールしてます。(Docker Composeでの使い方は次に書きます)

インストール
npm install -g http-knocking

以下が実行の方法です

実行方法
http-knocking --port=8282 --target-host=localhost --target-port=8181 --open-knocking="/hirake,/goma" --close-knocking="/tojiyo,/goma"

大雑把な構成は以下のようになります。
http-knocking.png
(PCの絵:パソコンのイラスト(無料イラスト)フリー素材

http://localhost:8282にアクセスすると最初は白紙のページです。以下の順番でアクセスすると、
1. http://localhost:8282/hirake
2. http://localhost:8282/goma
ノッキングが成功して、localhost:8282localhost:8181の内容にアクセスできるようになり、ちゃんと隠していたサーバーが使えるようになりました!
(閉じるときは/tojiyo -> /gomaの順番でアクセスすれば閉じます)

http-knockingの使い方(Docker Compose)

Docker Composeを使う方法だと、npmなしで利用することができます。
Alpineのおかげで、http-knockingのDockerイメージのサイズが87MBと割と小さくなりました。そのためそこまで負担なく導入しやすいのではないか思います。

隠したいWebサーバーとして、GhostのDockerイメージghostを使ってみました。
以下の起動方法は、以下の内容をdocker-compose.ymlとして保存して、docker-compose upで起動します。起動後はhttp://localhost:8282にノッキングサーバーが立ち上がります。

docker-compose.yml
version: '3.1'
services:
  http-knocking:
    image: nwtgck/http-knocking:v0.3.0
    ports:
      - '8282:8282'
    depends_on:
      - ghost
    restart: always
    command: --port=8282 --target-host=ghost --target-port=2368 --open-knocking="/alpha,/foxtrot,/lima"
  ghost:
    image: ghost
    restart: always
    expose:
      - "2368"

Docker Composeを使っているため、隠したいサーバー(今回のGhost)のポートにアクセスできないようにでき、よりわかりやすくてセキュアになっていると思います。あとは、これにHTTPS-PORTALを組み合わせてHTTPS化するというのを想定しています。

以下が、実際のノッキングの動作です。'/alpha' -> '/foxtrot' -> 'lima'の順番でアクセスすると、ちゃんと開くのが確認できます。(--close-knockingを指定していなので、逆順でノッキングすることで閉じます)
http-knocking animation

その他のオプション

セキュリティを高める目的などでいくつかオプションを用意しています。
バージョン0.3.0の時点で以下のオプションが利用可能です。

Options:
  --help                               Show help                       [boolean]
  --version                            Show version number             [boolean]
  --port                               Port of knocking server        [required]
  --target-host                        Target host to hide            [required]
  --target-port                        Target port to hide         [default: 80]
  --open-knocking                      Open-knocking sequence (e.g.
                                       "/alpha,/foxtrot,/lima")       [required]
  --close-knocking                     Close-knocking sequence (e.g.
                                       "/victor,/kilo")
  --enable-websocket                   Enable WebSocket proxy   [default: false]
  --auto-close-millis                  Time millis to close automatically
  --open-knocking-max-interval-millis  Time millis to reset open procedure

セキュリティを高めるには--auto-close-millis--open-knocking-max-interval-millisが便利だと思います。

--auto-close-millisは開いたあと何ミリ秒たったら、自動でクローズするかを指定します。デフォルトだと自動でクローズしません。

--open-knocking-max-interval-millisはパスを指定する時間間隔の最大ミリ秒を指定します。例えば、10000と指定すれば、10秒以内に次のパスにアクセスする必要があります。その次のパスにアクセスするときもまた10秒以内にその次の次のパスにアクセスする必要があります。デフォルトだと無制限です。

WebSocket対応

0.3.0からWebSocketもリバースプロキシ対応しました。
--enable-websocketオプションを指定することで、WebSocketの通信も通したり隠したりできるようになります。--enable-websocketオプションを指定しない場合は、WebSocketのリバースプロキシはされません。
(追記:2018/08/21)

GitHub

TypeScriptで実装しています。
https://github.com/nwtgck/http-knocking

以下のような方法で、install -gせずに使ってもいいと思います。

git clone https://github.com/nwtgck/http-knocking.git
cd http-knocking
npm install
npm start -- --port=8282 --target-url=<ターゲットURL> --open-knocking="/alpha,/foxtrot,/lima"

作ろうと思ったきっかけ

あんまり関係のない話ですが、最後に作ろうと思ったきっかけについてです。
curlコマンドとかでファイルを送信したり、受信したりするサーバーを作っていて、そのサーバーの利用を制限する方法がないかなと思ったのがきっかけでした。利用を制限すると、悪意もった人が巨大なファイルを送るのを防いだり、その他悪意のあるアクセスも少しは防げるのではないかと思ってます。

あと幸運なことに、通信が確立した後にノッキングサーバーをクローズしても、ファイルの送受信は進み続けるので、確立さえすればHTTPボディが巨大なリクエストやレスポンスもhttp-knockingでクローズ後もアクセス可能でした。クローズ後は新しい送受信の始まりが確立することはないので、目指していたよりセキュアな状態が可能になったのかなと思っています。


  1. ネットワーク周りは特に自身がないので間違っているかもしれません 

  2. ある特定のプログラミング言語のライブラリとかにすると、その言語で書かれているサーバーにしか適用できなさそうになるので、こういう方針にしました。 

10
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
7