Facebook Twitter
お問い合わせ
TOPICS
更新情報
ホーム > ブログ > Oracle Cloud > 稼働しているWebサーバーにWAFを設定してみました!

稼働しているWebサーバーにWAFを設定してみました!

ブログ
Oracle Cloud
2021.09.01

本記事は、実際に稼働しているWEBサーバーにOracle CloudのWeb Application Firewall(以下「WAF」という)を設定した一連の手順について記載したものです。

  

こんにちは!k.takeiです

  

今回はすでに稼働しているWebサーバーに対してWAFを導入しました!
その際に悩んだところや工夫したところを中心にまとめています。
  
実現したかったのは、下記の2点です。
・稼働しているWebサーバーへのアクセスをWAF経由のみにしたい。
・アクセスさせるドメインは変更したくない。

  

  

WAFを経由してWebサーバーにアクセスさせる

WAFはWebアプリケーションを防御するためのものです。
例えば、SQLインジェクション、OSコマンドインジェクション、クロスサイトスクリプティングのような攻撃からWEBサーバーを守る用途で使用されます。

  

WAFポリシーの作成については「こちらの記事」で紹介してますのでご参照してください。

   

WAFポリシーの作成後、DNS管理から対象のWebサーバーで使用しているドメインを選択し、遷移後の画面でレコードを選択します。

    

今回はCNAMEではなく、ALIASというレコードを使用します。
理由は、Zone APEXだとCNAMEが設定できないからです。

  

今回稼働しているWebサーバーが使用しているドメインは、Zone APEX(wwwなどのサブドメインを含まないドメイン名)です。
そして、Zone APEXの場合はNSレコードの設定が必須となっています。
ただ、CNAMEは他のレコードと共存できないので、プロトコルエラーになってしまいます。
そのため、ALIASレコードを使用しています。
※OracleCloudのDNSレコードに関するドキュメントはこちらを参照して下さい。

    

今回設定する値を例に説明をします。
設定したいURLは「onigiri.fun」です。
「onigiri.fun」はZone APEXなので、NSレコードが必ず設定されています。

  

この状態でCNAMEを登録しようとすると、下記の画像の通りエラーが出てしまい設定することができません。

  

これを解決するためにALIASレコードを下記の手順で設定していきます。
ネットワーキング > DNS管理 > ゾーン > 対象のドメイン名を選択します。
レコードの追加をクリックすると項目の入力画面になります。

  

入力項目は下記の通りです。

・レコード型:レコードの型を選択する項目
 今回はALIASを指定します。

・名前:ドメインの前に設定する名前を入力する項目
 今回はそのまま使用したいので、空欄のままにします。
 ※赤枠の箇所にドメイン名が入っています。

・TTL:レコードのTTLを設定する項目
 今回はAレコードに合わせて300秒に設定しました。

・RDATA:入力方式を基本と拡張のどちらかから選択する項目
 今回は基本を選択します。

・DOMAIN:別名を入力する項目
 今回は作成したWAFのCNAMEターゲットをここに入力します。

  

送信が完了し、変更の公開を押すと反映されます。
AレコードのRDATA項目が下記のようになっていれば問題ないです。

  

これでWAFを経由させる作業は完了しました!
onigiri.funへのアクセスは、WAFを通してのみ行われるようになります。

  

WebサーバーへのアクセスをWAF経由のみに設定する

次はWebサーバーへのアクセスを制御します。
WAFを経由していないものに関しては、拒否するように設定していきます。

  

現状はドメインを使用してアクセスされるもの(http://onigiri.funなど)は、先ほどの設定でWAFを経由するようになっていますが、IPを直接指定してアクセスされるもの(http://150.136.63.233など)はWAFを経由せずにアクセス出来てしまう状態です。

  

Webサーバーへのアクセスを指定したIPからの通信だけ許可する設定する方法ですが、今回はネットワーク・セキュリティ・グループ(以下「NSG」という)で行います。

  
ネットワーキング > 仮想クラウド・ネットワークから対象のVCNを選択し、左下のネットワーク・セキュリティ・グループを押下すると設定画面が出てきます。
その後に、ネットワーク・セキュリティ・グループの作成ボタンを押下します。

  

入力項目は下記の通りです。

・名前:NSGの名前を設定
 任意の名前を設定します。

・コンパートメントに作成:作成するコンパートメントを選択
 コンパートメントを選択します。

・セキュリティ・ルールの追加:セキュリティ・ルールを追加します。
 今回はこの画面では設定しません。
 ※理由は後述します。セキュリティ・ルールについては公式ドキュメントを参照してください。

  

NSGを作成し、セキュリティ・ルールにWAFのCIDERを追加していくのですが、合計で108個作成する必要があります。
※CIDER範囲が記載されているドキュメントはこちらを参照してください。

  

先ほどコンソール画面から設定しなかった理由は追加するルールの多さです。
手で設定するとなると、かなり大変な上にミスをしそうだったので、今回はCLIを使用してルールを追加していきます。
※CLIの始め方はこちらを参照してください。

  

・現在のNSGのルールを取得するコマンド

oci network nsg rules list --all --output table --nsg-id <NSGのOCID>

〈--output table〉をつけない場合、JSON形式でデータが取得できます。
ただ、上記のコマンドではカラムが多すぎるので、欲しいものだけに絞ります。

oci network nsg rules list --all --output table --query "data[*].{\"説明\":description,\"プロトコル\":protocol,\"IPアドレス\":source,\"ポート\":\"tcp-options\"}" --nsg-id <NSG_ID> > ./NSG_rule.txt

上記のコードでは、description、protocol、source、tcp-optionsの項目に絞ってデータを取得し、NSG_rule.txtというファイルに出力をしています。

  

NSGのルールを追加するコマンドは下記です。

oci network nsg rules add --from-json file://〈読み込むJSONファイルを指定〉

作成するJSONファイルの形式は下記のコマンドで取得できます。

oci network nsg rules add --generate-full-command-json-input

  

取得したJSON形式に説明のコメントを記載したものが下記です。
各項目の説明はこちらをご覧ください。

{
  "nsgId": "string", 
  "securityRules": [ 
    {
      "description": "string",
      "destination": "string",
      "destinationType": "string",
      "direction": "string",
      "icmpOptions": {
        "code": 0,
        "type": 0
      },
      "isStateless": true,
      "protocol": "string",
      "source": "string",
      "sourceType": "string",
      "tcpOptions": {
        "destinationPortRange": {
          "max": 0,
          "min": 0
        },
        "sourcePortRange": {
          "max": 0,
          "min": 0
        }
      },
      "udpOptions": {
        "destinationPortRange": {
          "max": 0,
          "min": 0
        },
        "sourcePortRange": {
          "max": 0,
          "min": 0
        }
      }
    },
    {
      "description": "string",
      "destination": "string",
      "destinationType": "string",
      "direction": "string",
      "icmpOptions": {
        "code": 0,
        "type": 0
      },
      "isStateless": true,
      "protocol": "string",
      "source": "string",
      "sourceType": "string",
      "tcpOptions": {
        "destinationPortRange": {
          "max": 0,
          "min": 0
        },
        "sourcePortRange": {
          "max": 0,
          "min": 0
        }
      },
      "udpOptions": {
        "destinationPortRange": {
          "max": 0,
          "min": 0
        },
        "sourcePortRange": {
          "max": 0,
          "min": 0
        }
      }
    }
  ]
}

  

今回追加するINGRESSルールに必要なもののみに絞ると下記の形になりました。

{
    "nsgId": "xxx",
    "securityRules": [
        {
            "description": "WAFのCIDR範囲",
            "direction": "INGRESS",
            "isStateless": "false",
            "protocol": "6",
            "source": "192.29.60.0/23",
            "tcpOptions": {
                "destinationPortRange": {
                    "max": "443",
                    "min": "443"
                }
            }
        }
    ]
}

   

セキュリティ・ルール追加のコマンドの読み込むファイルの部分に上記のJSONファイルが格納されているパスとファイル名を指定すると、OCIDが「xxx」のNSGに下記の画像のルールを追加していることになります。

  

あとは、追加したいルールをJSON形式で記述していくだけなのですが、いくつか注意する点がいくつかあります。

  1. CLIを使用してルールを追加する際は1度に25件が上限。
  2. コンソールでは宛先ポート範囲で80,443という記述をしてもよかったが、CLIでは出来ないので分けて作成する必要がある。(21‐22のような範囲指定は可能)
  3. セキュリティ・ルールは120個が上限。

WAFのCIDERが108個あるので、JSONファイルは5つに分ける必要があります。
また、ポート指定を80と443両方していすると上限を超えて登録できないため、どちらかに絞る必要がありました。
なので、WAFでHTTPからHTTPSへのリダイレクトを行い、WebサーバーのNSGは443のみを許可させることにしました。

下記はイメージです。※実際にはWebサーバーにssh接続する用のものも許可していますが省いています。

  

WAFのリダイレクト設定は、対象のWAF詳細画面の左下にある、設定から行えます。
編集ボタンを押下して、赤枠の項目を設定します。
※SSL証明書に関してはこちらを参照してください。

  

あとはWAFに必要な保護ルールを設定したら完了です。
※WAFの保護ルールについてはこちらを参照してください。

  

動作確認

設定が完了したので、動作確認をしていきます。
確認するのは下記の内容です。

・onigiri.funにアクセスした場合、WAFを経由すること。
http://onigiri.funにアクセスした場合、https://onigiri.funでWebサーバーにアクセスされること。
・WebサーバーのIPアドレスを指定してアクセスした場合、拒否されること。
  

まず、WAFを経由してアクセス出来ているかに関しては、下記の手順で確認できます。

  1. Webサーバーにアクセスする。
  2. 開発者ツールを開く。
  3. ページを更新し、Headerを確認する。

serverがZENEDGEとなっていればWAFを経由してアクセスしている証拠です。

  

  

次に、http://onigiri.funでアクセスしてみます。
するとhttps://としてアクセスされました。

  

最後にIPアドレスでWebサーバーにアクセスしてみます。
パブリックIPの150136.63.233を指定すると接続できません。

  

これでWAFを経由しないとWebサーバーへアクセス出来なくなっていることを確認できました!

  

まとめ

WAFの設定をしてみましたが、一番辛いのはWAFのCIDERをNSGのセキュリティ・ルールに追加する部分でした。

  

WAFを触ってみた個人的な感想ですが、
・Webアプリケーションの防御を開発者のスキルに依存することなく行える。
・セキュリティに割く開発コストや期間を短くできる。
・新たな脆弱性が出たときに、簡単に対応できる。
 ※これはプラットフォームにもよります。
・運用者のセキュリティの知識が浅くても設定自体は簡単に行える。
というのが、メリットだと感じました。

  

そして作っている最中に、CLIを使用しても手で書くと労力も精度もコンソール画面から登録するのと大差がないと気づいたので、JSONファイルを作ってくれるスクリプトを作成することにしました。。。

作成したはコードはGitHubで公開してあるので、興味のある方はこちらからご覧ください。
README.mdに使い方に関しての簡単な説明は記載しております。
※Pythonで作成しています(バージョンは3.8.10)。
  

少量であればJSONファイルをそのまま作成した方が早いのですが、今回みたいに大量に追加しなければいけない場合は、スクリプトを作成するのも1つの手段だと思いますので、興味がある方はチャレンジしてみてください!
  
この記事が少しでも皆様のお役に立てれば幸いです。
最後まで読んで頂きありがとうございました!


この記事が気に入ったら
「いいね!」

この記事を書いた人


関連コンテンツ

CONTACT お問い合わせ

Cloudiiのサービスやプロダクトについて
興味をお持ちの方は、
お気軽にお問い合わせください。