https://aws.typepad.com/sajp/2016/05/aws-waf-dl.htmlAWS WAF, Amazon CloudFrontでリファラチェックして直リンクを弾く方法
何者かがあなたのウェブサイトのコンテンツを埋め込み、そのウェブサイトはコスト負担をすることなく、あなたが他人のサイトのための費用負担をすることになります。常にというわけではありませんが、そのhotlinking(直リンク、直リンとも)に対処しなければならないときがあります。
そんなとき、AWS WAFが直リン対応に使えます。AWS WAFは Amazon CloudFront(AWS のContent Delivery Network[CDN])に統合されたweb application firewallです。アプリケーションの可用性に影響を与える可能性がある一般的なWebの脆弱性を利用からWebアプリケーションを保護するためのセ キュリティを侵害し、過度のリソースを消費することができます。このブログ記事では、CloudFrontのようなCDNによって改善されたユーザーエク スペリエンスを利用しながら、AWS WAFのヘッダ検査を使用して、直リンを防ぐ方法を説明します。
Process overview
あ なたはいくつかの方法でホットリンクに対処することができます。たとえばRefererヘッダは、ブラウザから参照元ページを示すために送られます。例え ばApacheモジュールのmod_rewriteを使用して、Webサーバーで検証できます。問題を発見したならば、あなたのサイトのメインページへの リダイレクトや「403」エラーを返します。
CloudFront のようなCDNをコンテンツ配信速度の向上のために使っている場合、Webサーバでのリファラーヘッダの検証は現実的ではありません。CDNはコンテンツ をエッジネットワークのサーバにコピーして保存されているため、CDN自身で検証を行う必要があります。オリジンサーバで(リファラのように)ヘッダの検 証をするとしたら、追加でオリジンへのリクエストが生じてしまいます。
以下にプロセスを図示します。
エ ンドユーザクライアント(1)からのリクエストが、(2)のAmazon CloudFrontのエッジロケーションに届くと、エッジロケーションはキャッシュされているリクエストされたコンテンツのコピーオブジェクトを返しま す。このリクエストがキャッシュでまかなえるときは、cache hitとして扱われます。エッジにコンテンツが存在しないか、コンテンツ期限切れなどの理由で有効でないときは、リクエストは(3)のオリジン(ELBや S3を使っています)に送られ、オブジェクトの新たなコピーを取得します。cache hitの場合は、エッジはオリジンに問い合わせをしないので、オリジンは検証に関わることはできません。
それでは、AWS WAFがどのようにヘッダ検査し、ブロックまたは許可をするのか見ていきましょう。
Solution implementation—two approaches
用語
以下のリストは、この記事で使用する重要な用語が含まれています。
- web access control list (web ACL)から構成されるAWS WAFの設定。これはCloudFront distribution に関連づけらます。
- それぞれのweb ACLは1つ以上のルールから構成せれる。それぞれのルールは1つ以上の一致条件からなる。
- 一致条件は、1つ以上のフィルタからなり、ヘッダやURIといったリクエストを検査する。
AWS WAF setup
- 別々のサブドメイン – 画像やCSSといった静的ファイルをstatic.example.comといった別のサブドメインに分けて守る方法。このケースでは、リファラヘッダに特定のドメインがあるかをチェックします。
- 同じドメイン – 静的ファイルが同じドメイン上のフォルダに存在する場合。このケースでは、空のリファラヘッダをチェックするようにします。
この場合、1つのフィルタ、1つの一致条件、1つのフィルタを作ります。一致条件は、Refererヘッダに意図した値が含まれているかを確認します。ルールに一致すれば、トラフィックは許可されます。そうでない場合はトラフィックはブロックします。
次の手順では、AWS WAFコンソールを使って設定する方法を示しています。
Step 1: 守るべきものを決めます。
静 的ファイルは分離したサブドメイン(static.example.com)としていて、それらはexample.comからのみアクセスされるようにし ています。Refererがexample.comで終わっていないstatic.example.com以下へのリクエストは全てブロックします。
AWS WAFはAmazon CloudFrontにのみ適用可能であるため、トラフィックをCloudFrontを使うように設定していることを確認してください。この記事では、CloudFrontの設定自体はカバーしません。
Step 2: web ACLを作り、名前をつけます。
ここでは、web ACLを作るのが初めてのケースなので、次のスクリーンショットのようにAWS WAFコンソールを開き、Get Startedをクリックします。
web ACLを作ったことがあれば、Create web ACL をクリックします。
作ったweb ACLに名前をつけます。あわせて、自動的に有効にされ紐付かれるAmazon CloudWatch メトリック名もつけます。CloudWatchはサービスのモニタリングサービスで、多くのメトリクスを収集し、レポートします。このCloudWatchメトリックは、新しく作ったAWS WAF設定が使われているかレポートするために後に使うことになります。
web ACLに名前をいれたら、Nextをクリックします。
String match conditions セクションで, Create conditionを クリックします。幾つかの条件のタイプを使うことができますが、ここでは、Refererヘッダに含まれる文字列の評価をするために、スクリーンショット の通りstring matchコンディションを選びます。これにより、example.com宛のあらゆるWebリクエストのRefererヘッダが検査され、他サイトに埋 め込みされたコンテンツの扱いが私に委ねられることになります。このケースでは、ブランクリファラーを許可しません。このドメイン内での埋め込みのみを許 可します。
さ らにセキュリティを強化する必要がある場合には、Refererがhttp://やhttps://のように有効な値を一意に定義できるような文字から始 まるようにします。この例では、https://example.comとすることによって、stealfromexample.comを登録して直リン を作ったり、includingexample.comを持った誰かから使われることがないようにできます。
さらに、Transformationで、ヘッダをパースする前に小文字に変換するようにしています。これはモダンブラウザでは必須ではありません。HTTPヘッダはケースセンシティブです。
設定情報を入力したら、Add another filterをクリックします。そうでなければオリジナルのフィルタは読み込まれません。
String match conditionがよみこまれると、次のスクリーンショットのようにString match conditions セクションが表示され、ルール内で使えることがわかります。
Nextをクリックし、Create rulesページにすすみます。
Step 4: string match条件にをつかうルールを作成
今作ったstring match条件をつかうためのルールを作らなければなりません。
まず、Create ruleをクリックし、名前をつけたあと、スクリーンショットで見るようにリクエストと背後にあるフィルタの条件をルールに追加します。
条件を指定した後、Createをクリックすると、web ACLに自動でルールが追加されます。スクリーンショットの通り、新規でつくったルールをAllowに、デフォルトアクションをブロックにして、Nextをクリックします。
Step 5: CloudFront Distributionへの関連付けとcURLを使ったテスト
リソースのドロップダウンリストのAWSリソースのページから、静的サイトの配信に使っているCloudFront distributionを選択し、新たに作成されたAWS WAFのWeb ACLを関連付けることができます。
Review and createをクリックし、設定の詳細を確認します。
正しいことが確認できたら、Confirm and createをクリックします。多くの場合、10分から15分後にはweb ACLとCloudFrontのdistributionの関連付けがおわります。
The result
ホワイトリストされたリファラヘッダをつけずにリクエストするとCDNによってブロックされ、有効なリクエストは許可されています。
サードパーティがコンテンツを埋め込んで、CDNによってリクエストがブロックされている例
» curl –H "Referer: https://example.net/" -I https://static.example.com/favicon.ico
« HTTP/1.1 403 Forbidden
自サイトのため、リクエストが許可されている例
» curl –H "Referer: https://example.com/" -I https://static.example.com/favicon.ico
« HTTP/1.1 200 OK
アプローチ1では、Refererヘッダをつけなければ、全てのパスは遮断されます。
アプローチ2では、特定のURLパスであれば、Refererヘッダがブランクである場合も許可する方法を紹介します。
Approach 2: 全てのコンテンツが同一ドメイン下にあり、パスによってフィルタをする
2つ目のアプローチでは、AWS WAFのweb ACLに複数のルールと一致条件を追加したフィルタを作成します。最初のアプローチと同様に、Refererヘッダを使います。そこで2つの方法で有効性を確認します。
まず、規定したヘッダを含んでいるかどうかの確認です。そうでないときは次の方法に移ります。URLスタイルのRefererヘッダを含んでいるかどうかの確認です。
リクエストに含まれているパスの有効性(ここでは /wp-contentとしています)も確認し、AWS WAFは同一のドメインかつ個々フォルダを守ることになります。
Step 1: 守るべきものを決めます。
2 つ目のアプローチでは、1つ目のアプローチのようにそのドメイン下の全てを対象とはしません。ここでは、/wp-contentが対象となります。これ は、アップロードされたコンテンツを /wp-content に限定することで、サブドメインを分けることなく保護できるようにしています。
Step 2: web ACLを作り、名前をつけます。
1つ目のアプローチと同じく、新しいweb ACLを AWS WAF consoleから、Create web ACLをクリックして作成します。アプローチ1ですでにweb ACLを作っていると想定していますが、そうでないならば、アプローチ1のステップを参照してください。
1つ目のアプローチと同じく、作成したweb ACLに名前をつけて、Nextをクリックします。
Step 3: string matchをRefererに対して作成します。
アプローチ2では、全てが一つのドメイン下に存在していることを前提としています。example.com/ をつかうのではなく、よりセキュアにするために https://example.com/をStarting With(から始まる)値として選択しています。明確に一つのヘッダを明記しているため、次の2つの点に注意します。
- www.example.comとexample.comの切り替え
- https:// と http:// の切り替え
これらのスイッチのいずれかが発生した場合は、埋め込まれたファイルの代わりに403 Forbiddenを戻します。この例では、全てのコンテンツは、https://example.com/ から配信されます。
これらの一致条件を作るには、スクリーンショットのようにString match conditionの後にCreate conditionをクリックします。
次のスクリーンショットに示すように、新しい一致条件とフィルタを設定します。
Add another filterをCreateをクリックする前にクリックすることを忘れないで下さい。忘れるとフィルタ条件に追加されません。
ア プローチ2のために、この文字列の一致条件を作成した後、2つの文字列一致条件を作る必要があります。一つは /wp-content というURLパスのためので、もう一つはリファラが無いような標準に準拠していないアプリケーションや、例えば電子メールから直 接リンクされている場合です。
URL自体については、/wp-content 以下を保護したいので、そのケースを検証するために文字列一致をこれまでやってきたように行います。今回は、スクリーンショットのように、/wp-contentと一致するように、その部分だけ、変更しています。
ここでも、Add another filteのクリックをCreateをクリックするまえに行なうようにします。
3番目の文字列の一致条件
最初の2つの文字列の一致条件作成したら、Refererを使うのか使わないのかという最後の一致条件作成に向かいます。
ここでも、Create conditionを、これまでのcreate conditonsのように押します。今回はRefererヘッダに :// が存在するように作成します。
ここでも、Add another filterをCreateをクリックする前に押します。次のスクリーンショットに示すように、全部で3つの文字列一致条件を持つことになります。
Nextをクリックし、Create rulesページにいきます。
Step 4: ステップ3で作成した文字列一致条件を持つ、2つのルールを作成します。
アプローチ2ではアプローチ1の場合よりも複雑なルールをつくることになります。
まず2つのルールを作ります。1つ目は有効なRefererヘッダ検証で、2つ目はRefererヘッダが無いリクエストの検証用です。
Rule 1: Referer ヘッダの検証
こ の最初のルールは、Refererヘッダ(https://example.com/)とURL(/wp-content)が一致して存在することです。 次のスクリーンショットに示すように、Create ruleをクリックし、名前をつけたら、CloudWatch metric nameをひも付け、ロジックを設定します。
上記のようにできたら、Createをクリックすると、web ACLに追加されます。
Rule 2: Refererヘッダが無いものの検証
2つ目のルールは最初に似ています。Refererヘッダに :// が含まれています。この簡単な方法は、Refererヘッダはセットされているかどうかを調べ、それがあるときは、リクエストを全てブロックするように、作成し、web ACLに加えています。
繰りかえしますが、ルールが反映されたら、Createボタンを押すことで、web ACLに追記されます。
これらのルールを作成し、ルールがweb ACLに加えられたら、ルールが適用される順序を選ぶことになります。
- パスが /wp-content で、Refererが有効であれば、リクエストを許可
- /wp-contentからパスが始まっているが、Refererが無効であれば、リクエストをブロック。
- Defaultアクションとして、それ以外のリクエストは許可(パスは/wp-contentではない)
Step 5: CloudFront distributionにルールを関連付けして、テスト
Resourceのドロップダウンリストから、関係するCloudFront distributionを選択すれば、簡単に新しいAWS WAF web ACLとdistributionのひも付けができます。
Review and createをクリックし、アプローチ2で設定した詳細を表示させます。
問題なければ、Confirm and createをクリックします。ここでも、変更をプッシュするのに10-15分くらいかかります。
結果
アプローチ1と同様に、CDNでフィルタリングをします。今回は、フィルタリングはパスによって変化し、Refererヘッダなしの直リンは許可しています。
ここでは、新しいAWS WAF web ACLが正しくコンテンツを保護することの確認のためにcURLを使います。-H を使ってことなるRefererヘッダをCloudFront distributionに送っています。
第三者がコンテンツを埋め込んだとき
» curl –H "Referer: https://example.net/" -I https://example.com/wp-content/uploads/2013/03/shareable-image.jpg
« HTTP/1.1 403 Forbidden
自分でコンテンツを埋め込んだとき
» curl –H "Referer: https://example.com/" -I https://example.com/wp-content/uploads/2013/03/shareable-image.jpg
« HTTP/1.1 200 OK
このソリューションまたは実装について質問があるときは、必要に応じてAWS WAF forumに新スレッドをたててコメントしてください。
https://aws.typepad.com/sajp/2016/05/aws-waf-dl.htmlAWS WAF, Amazon CloudFrontでリファラチェックして直リンクを弾く方法
コメント