S3 の設定不備で起こる脆弱性を整理してみる
はじめに
当記事を読んでいただき、ありがとうございます。
私は普段、脆弱性診断やペネトレーションテストを中心に、セキュリティに関わる業務に携わっています。
ここ数年で、クラウド上に構築された Web アプリケーションを見る機会が増え、個人的にAWSの学習を進めてきました。ひとまず学習が一段落したため、脆弱性診断の観点からAWSで構築されたWebアプリで確認したいポイントを整理してみようと思います。
今回は S3 編です。LambdaやAPI Gatewayについては、気が向いたら続編として書くかもしれません。
S3を利用したWebサイト構成
本記事では、基本的なWebの脆弱性とAWSの主要サービスについて理解していることを前提とします。
S3をWebサイトのコンテンツ配信に利用する構成はいくつかあります。
そして、どの構成を採るかによって、発生しうる脆弱性や確認すべき観点は変わります。そのため、まずは前提知識として、S3を利用した代表的な配信構成を整理します。
1. S3
単純なストレージとしてS3を利用し、直接S3にアクセスさせることでコンテンツを配信する構成です。
特徴:
AWS の REST API エンドポイントを利用してアクセスします。インデックスドキュメント(index.htmlなど)やカスタムエラーページのような、一般的なWebサイト向けの機能は持たず、URLの扱いも通常のWebサーバーとは異なります。その特性から、主にHTMLなどのWebコンテンツの配布ではなく、PDFや画像などのオブジェクトを配布する目的で利用されます。
エンドポイント:
https://[bucket-name].s3.[region].amazonaws.com/...
セキュリティ:
HTTPS に対応しています。
一般的には Block Public Access(BPA)を有効にし、インターネットに非公開のまま利用する構成が基本です。
用途:
ダウンロード配布専用のファイル置き場、署名付きURLによるファイル配布など
2. S3 静的ウェブサイトホスティング
S3を簡易的なWebサーバーのように利用し、静的コンテンツを配信する構成です。
特徴:
S3が発行するWebサイトエンドポイントでアクセスします。
インデックスドキュメント(index.html)やエラードキュメントを設定できるため、S3単体よりWebサイトらしい動作になります。
デフォルトのエンドポイント:
http://[bucket-name].s3-website-[region].amazonaws.com/...
セキュリティ:
S3のWebサイトエンドポイントはHTTPSに対応しておらず、HTTPのみです。
また、この構成では通常、コンテンツを公開するために Block Public Access を無効化し、公開ポリシーを設定する必要があります。
そのため、インターネット公開時の構成としては慎重な取り扱いが必要です。
用途:
簡易的な社内向けツール、プロトタイプ、検証環境など
3. CloudFront + S3
CDNであるCloudFrontを前段に置き、S3をオリジンとして静的コンテンツを配信する構成です。
一般公開される静的サイトでは、現在もっとも標準的な構成の一つです。
特徴:
CloudFrontを使うことで、コンテンツを世界中のエッジロケーションにキャッシュできるため、表示速度や配信効率が向上します。
また、OAC (Origin Access Control) を利用すれば、S3バケットを非公開のままにしつつ、CloudFrontからのみアクセスさせる構成を取れます。AWS でもOACの利用が推奨されています。
デフォルトのエンドポイント:
https://[your-domain].cloudfront.net/
セキュリティ:
HTTPSの利用、AWS WAFとの連携、IP制限、地理的制限などのセキュリティ機能を組み合わせやすい構成です。
また、S3 を直接公開せず、CloudFront を唯一の公開経路にできる点が大きな利点です。
用途:
一般公開される企業サイト、LP、SPA(Single Page Application)、配布用静的コンテンツなど
4. CloudFront + Lambda@Edge + S3 / CloudFront Functions + S3
CloudFrontの配信処理の途中で、プログラムによる制御を挟む構成です。
CloudFront Functions および Lambda@Edgeは、どちらもCloudFrontの配信内容をカスタマイズするための仕組みです。本記事では脆弱性診断上の観点を中心に整理するため同一項目として扱いますが、実際は機能差があり実装可能な内容は完全には一致しない点に注意してください。
特徴:
エッジロケーション上で、リクエストやレスポンスに対して動的な処理を加えられます。
たとえば、ユーザー属性に応じた振り分けや、レスポンスヘッダーの付与、条件に応じたアクセス制御などが可能です。
デフォルトのエンドポイント:
https://[your-domain].cloudfront.net/
できること:
- 特定のヘッダーやCookieがないアクセスを遮断する
- User-AgentやAccept-Languageに応じて画像やパスを切り替える
- セキュリティヘッダー(HSTS、CSP など)を付与する
- A/Bテストや簡易的な振り分けを行う
セキュリティ:
基本的な公開構成は 3. CloudFront + S3 と同様です。
一方で、リクエストやレスポンスを動的に操作できるぶん、実装不備による認可ミス、ヘッダー設定ミス、キャッシュポイズニングなどの新たなリスクが生まれます。
用途:
A/Bテスト、認証付き静的コンテンツ配信、多言語対応サイト、エッジでの軽量な振り分け処理など
まとめ
ここまでの内容を整理すると、実運用の本番環境では 3. CloudFront + S3 や 4. CloudFront + Lambda@Edge + S3 の構成が多く見られます。
一方で、配布したいのが単純なオブジェクトだけであり、Webサイトとしての振る舞いを特に必要としないケースでは、 1. S3 が使われることもあります。2. S3 静的ウェブサイトホスティングは社内サイトや検証目的で利用されることが多く、実運用ではあまり見かけることがありません。(筆者はみたことがないです)
| 構成 | 1. S3 | 2. S3 静的ウェブサイトホスティング | 3. CloudFront + S3 | 4. CloudFront + Lambda@Edge + S3 |
|---|---|---|---|---|
| 主な用途 | 汎用ストレージ | 簡易Web公開 | 本番Web配信 | リクエスト・レスポンスのカスタマイズ |
| セキュリティ | HTTPS, BPA有効が基本 | HTTPのみ、公開設定(BPAオフ)が必須 | HTTPS, WAF連携, IP制限, 地理制限, OACによるS3の非公開化 | 3 に加えて動的処理由来の実装リスクに注意(XSSやキャッシュポイズニング等) |
| ロジック | 静的 | 静的 | 静的 | 動的 |
S3に関連したWebサイトの脆弱性
ここからが本番です。
S3が利用された構成において設定不備に起因して発生する脆弱性をまとめます。
CloudFrontのバイパス
CloudFrontを前段に置いた構成では、S3バケットを直接公開せず、CloudFrontからのみアクセスさせるのが基本的な考え方です。そのために利用されるのが OAC (Origin Access Control) です。しかし、OAC を利用しているつもりでも、実際には S3 側の設定が不適切だと、CloudFrontを経由せずにS3へ直接アクセスできる状態となることがあります。
脆弱性が存在する条件
この問題が成立するためには、主に以下の条件が揃っている必要があります。
1. S3 バケットが CloudFront 以外からもアクセス可能になっている
本来、OACを利用する場合は、S3バケットポリシーによりCloudFrontサービスプリンシパルと特定のDistribution ARNのみを許可し、それ以外からのアクセスを拒否する構成にする必要があります。
たとえば、以下のようなポリシーであれば、CloudFront経由のオブジェクト読み出しのみを受け付ける構成になります。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipalReadOnly",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::your-bucket-name/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/E123456789ABCD"
}
}
}
]
}
一方で、以下のように Principal でアクセス元を制限していない場合は、CloudFrontを経由しなくても誰でもS3バケットへ直接アクセスできる状態になります。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::your-bucket-name/*"
}
]
}
このような設定では、CloudFrontは単なる配信経路の一つに過ぎず、保護対象であるはずの S3 バケットが実質的にインターネットへ直接公開されている状態 といえます。
また、PrincipalはCloudFrontを指定していてもConditionが指定されていなければ、攻撃者が用意したCloudFrontディストリビューションを経由してS3バケットにアクセスすることが可能になる場合があります。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipalReadOnly",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::your-bucket-name/*",
}
]
}
2. Block Public Access (BPA) が無効化されている
S3ではバケットポリシーやACLの設定不備による意図しない公開を防ぐために、Block Public Access (BPA) という保護機能が用意されています。そのため、前述のような Principal: "*" を含む公開ポリシーを有効にするには、BPA が無効化されている必要があります。つまり、この脆弱性は単にOACが未設定であるというだけでなく、S3 側がパブリックアクセスを許容する設定になっていることによって成立します。

検証
この問題を確認するには、CloudFrontのURLではなく、S3バケットのREST APIエンドポイントに対して直接GETリクエストを送信します。適切に制限されていれば 403 Forbidden となるはずですが、S3が公開状態になっている場合は、オブジェクトの内容がそのまま取得できてしまいます。
# S3バケットの名前を指定して直接アクセスしてみる
curl -v -X GET https://[your-bucket-name].s3.[region].amazonaws.com/test.txt
# 成功すると 200 OK と共にファイルの内容が返却されます
< HTTP/1.1 200 OK
...
security_test
リスク
この問題の本質は、CloudFrontに集約したセキュリティ制御を回避されることにあります。一見すると単に S3 から直接読めるだけに見えるかもしれませんが、実際にはさまざまな保護機能が意味を失うため、影響は小さくありません。
1. CloudFront セキュリティ機能の無効化
CloudFrontには多くのセキュリティ機能が集約されていますが、これらはCloudFrontを通過することが前提です。バイパスされると、以下の機能がすべて意味をなしません。
- WAFの回避: CloudFrontに紐付けたWAFによる防御が一切効かなくなります。
- 地理制限の回避: 特定の国からのアクセスをCloudFrontで禁止していても、オリジンに直接アクセスされれば閲覧を許してしまいます。
- IP制限の回避: CloudFrontで特定のIPアドレスのみを許可していても、直接オリジンを叩くことでその制限をすり抜けられます。
2. Denial of Wallet
Denial of Wallet(DoW)とは、サーバレスや従量課金制のクラウドサービスを標的とし、不必要なリソースを大量消費させ、被害者に膨大な金銭的損害を与えるサイバー攻撃です。CloudFrontを回避して、S3へ直接アクセスされることにより以下のようなリスクが発生します。
- リクエスト課金の増大: S3ではAPI呼び出しの回数に応じて課金が発生します。CloudFrontのキャッシュが効いていれば、S3へのリクエスト料金は抑えられますが、バイパスして直接S3へ大量のリクエストを送られると、S3のリクエスト課金が跳ね上がり、高額な請求が発生します。
3. 認証・認可のロジックバイパス
CloudFrontでコンテンツの保護を行っている場合、その仕組み自体が回避され、認証・認可を受けていないユーザがリソースにアクセス可能になります。
- 署名付きURL / 署名付きCookieの無効化: CloudFrontの署名機能を使って特定のユーザのみに配信するといった制御をしている場合、オリジンへ直接アクセスできると、署名なしで誰でもコンテンツをダウンロードできてしまいます。
- プロトコルポリシーの無視: CloudFrontで「HTTPS強制」を設定していても、オリジンがHTTPを許可していれば、平文での通信を許してしまいます。
S3バケットへの書き込み権限の設定不備 (CloudFront経由)
本来は書き込みを許可すべきでない利用者やシステムに対して、S3バケット内のオブジェクトを追加・上書き・削除できる権限を与えてしまっている脆弱性です。S3バケットの権限設定不備が原因であるため、構成 1〜4 のいずれでも発生し得ますが、本節では特にCloudFront経由でS3のオブジェクト操作が可能になるケースを取り上げます。
CloudFront側で書き込み系メソッドが許可され、さらに S3 側でもCloudFrontに対して過剰な権限が付与されていると、閲覧者からのリクエストによってS3バケット内のオブジェクトが操作できてしまう場合があります。
脆弱性が成立するための条件
この問題が成立するためには、主に以下の2つの条件が揃っている必要があります。
1. CloudFront側で書き込み系メソッドが許可されている
S3バケット内のオブジェクトを追加・上書き・削除するには、主にPUT、POST、DELETEといったHTTPメソッドが使用されます。
CloudFrontのキャッシュビヘイビア設定でこれらのメソッドが許可されている場合、CloudFrontに到達した書き込み系リクエストがオリジンであるS3に転送される可能性があります。
言い換えると、CloudFront側でGETやHEAD、OPTIONSのみを許可している限り、この経路での書き込みは成立しません。

2. S3側でCloudFrontに対して書き込み権限が付与されている
CloudFrontが書き込み系メソッドを転送できても、S3側でそれを拒否していれば更新は成立しません。
そのため、もう一つの条件として、S3バケットポリシーでCloudFrontに対して書き込み権限が付与されている必要があります。
OAC(Origin Access Control)が正しく利用されている場合、PrincipalとConditionによって特定のCloudFrontディストリビューションからのアクセスのみを許可する構成になります。しかし、そのAction要素の中にs3:PutObjectやs3:DeleteObjectが含まれていると、CloudFront 経由でオブジェクトの追加・上書き・削除が可能になってしまいます。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCloudFrontOverPermission",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": [
"s3:GetObject",
"s3:PutObject", // ← 本来不要な書き込み権限
"s3:DeleteObject" // ← 本来不要な削除権限
],
"Resource": "arn:aws:s3:::example-bucket/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/ED123456789"
}
}
}
]
}
検証
上記2つの条件を満たす構成に対して、CloudFrontのURL宛てにPUTリクエストを送信します。
本来、閲覧者からの書き込みは想定されていないため、適切に制限されていれば 403 Forbidden となるはずです。しかし、CloudFront側で書き込み系メソッドが許可されており、S3側でも書き込み権限が付与されている場合は、オブジェクトのアップロードに成功し、200 OK が返る場合があります。
# 存在しないファイル test.txt を PUT してみる
curl -v -X PUT -d "security_test" https://[your-domain].cloudfront.net/test.txt
# 成功すると 200 OK が返却されます
* upload completely sent off: 13 bytes
< HTTP/1.1 200 OK
このように、CloudFrontのURLに対するPOST,PUT,DELETEリクエストによってS3バケット内のオブジェクトを操作できる場合、脆弱性となる可能性があります。
リスク
1. コンテンツの改ざんとフィッシング
静的ウェブサイトをホストしている場合、もっとも直接的な被害です。
-
サイトの乗っ取り: 攻撃者が
index.htmlなどの既存コンテンツを書き換え、悪意のある偽の画面(フィッシングサイト)を設置します。 - スクリプトの埋め込み: 既存のJavaScriptファイルを改ざんし、ユーザーのCookieやパスワードを外部へ送信するコードを注入されます。これにより、サイトを訪れた一般ユーザーが被害者となり、なりすましの被害にあいます。
2. マルウェア配布プラットフォームへの悪用
S3バケットが信頼されたドメインとして認識されていることを逆手に取った悪用です。
-
踏み台利用: 攻撃者が自分のウイルスやマルウェアをバケットにアップロードします。その後、
https://{your-domain}.s3.amazonaws.com/update.exeのような一見正規に見えるURLを使ってマルウェアを拡散させます。 - 社会的信用の失墜: あなたのドメインがセキュリティソフトによって危険なサイト(マルウェア配布元)としてブラックリストに登録され、ビジネスが停止する可能性があります。
3. データの破壊
S3のバージョニング機能を有効化しておらず、バックアップも取得していない場合、単純なデータの上書きや削除が脅威となります。
- データの暗号化・削除: 攻撃者がバケット内の全ファイルを削除するか、あるいは暗号化したファイルで上書きし、「元に戻してほしければ身代金を払え」と要求します。
- バックアップの無効化: もしそのバケットがバックアップ先だった場合、過去のデータもろとも消去され、事業継続が不可能になります。
4. Denial of Wallet
S3はリクエスト数やデータ転送量に対して課金されるため、DoWの標的となる可能性があります。
- ストレージコストの増大: 攻撃者が巨大なダミーデータを大量にアップロードすることで、翌月の請求額を意図的に跳ね上がらせます。
S3バケットへの書き込み権限の設定不備 (S3直接アクセス)
前節では、CloudFrontを経由してS3バケット内のオブジェクトを操作できてしまうケースを取り上げました。本節では、その別パターンとして、CloudFrontを経由せずにS3へ直接アクセスし、オブジェクトの追加・上書き・削除ができてしまうケースを扱います。
CloudFront側でPUT、POST、DELETEが拒否されている場合でも、それだけで安全とは限りません。S3自体が外部から直接アクセス可能な状態になっており、さらに書き込み権限まで付与されていると、CloudFrontをバイパスしてS3に対して直接オブジェクト操作が行える可能性があります。
また、CloudFrontを利用していない 1. S3 や 2. S3 静的ウェブサイトホスティングの構成では直接S3にアクセスすることを前提としているため、S3の設定不備だけで脆弱性が生じる可能性があります。
脆弱性が成立するための条件
この問題が成立するためには、主に以下の2つの条件が揃っている必要があります。
1. CloudFrontを回避してS3バケットにアクセスできる
「CloudFrontのバイパス」で説明した設定不備と同様です。
S3のアクセス制御に不備がある + Block Public Access (BPA) を無効化していることが条件になります。
2. S3バケットポリシーで書き込みが許可されている
S3へ直接アクセスした後、オブジェクトの追加・上書き・削除が可能となるためには、バケットポリシーのAction要素に書き込み系の権限が含まれている必要があります。たとえば、以下のように s3:PutObject や s3:DeleteObject が許可されている場合、外部の利用者がCloudFrontを経由せずにS3へ直接書き込みを行える状態になります。
なお、1. S3 や 2. S3 静的ウェブサイトホスティングの構成においては、CloudFrontのバイパスが必要ないため、S3のバケットポリシーで書き込みが許可されているだけで脆弱性となり得ます。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::your-bucket-name/*"
}
]
}
検証
この状態を確認するには、CloudFrontのURLではなく、S3バケットのREST API エンドポイントを直接指定して PUT リクエストを送信します。
適切に制限されていれば 403 Forbidden となるはずですが、S3側が公開書き込み可能な状態であれば、オブジェクトの作成に成功し 200 OK が返ることがあります。
# 存在しないファイル test.txt を PUT してみる
curl -v -X PUT -d "security_test" https://[your-bucket-name].s3.[region].amazonaws.com/test.txt
# 成功すると 200 OK が返却されます
* upload completely sent off: 13 bytes
< HTTP/1.1 200 OK
リスク
発生し得る影響自体は、前節で説明したCloudFront経由の書き込み権限不備と基本的に同様です。
ただし、このケースではCloudFrontを経由しないため、CloudFront側で行っている制御をすべて回避できるという点がより深刻です。
たとえば、CloudFront側でPUTやDELETEを禁止していても、S3が直接公開されていればその制限は意味を持ちません。また、CloudFrontにWAFやIP制限、地理制限を設定していたとしても、S3へ直接アクセスされることでそれらを回避される可能性があります。
S3 バケット内のオブジェクト一覧の露出
S3バケットに対してs3:ListBucket権限が付与されている場合、バケット内に存在するオブジェクトの一覧を取得できることがあります。
一般的なWebサーバーにおけるディレクトリリスティングと似た影響を持つため、脆弱性診断においては「ディレクトリリスティング」の脆弱性として扱われることもありますが、厳密にはS3のオブジェクト一覧APIが外部に露出していることが原因です。
脆弱性が存在する条件
この問題が成立するためには、主に以下の条件が揃っている必要があります。
1. S3 バケットに対して s3:ListBucket が許可されている
S3オブジェクトの一覧取得は、バケットに対するs3:ListBucket権限によって制御されます。たとえば、以下のようにPrincipal: "*"に対してs3:ListBucketが許可されている場合、外部からバケット内のオブジェクト一覧を取得できる可能性があります。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::your-bucket-name"
}
]
}
この問題は、S3バケットへの直接アクセス時だけでなく、構成や設定によってはCloudFront経由でも発生する可能性があります。なお、CloudFrontの Default root object を設定することでルートURLにおける意図しない露出を抑える助けにはなりますが、根本的な対策ではない点に注意してください。
検証
この問題を確認するには、S3バケットのルートに対して直接アクセスし、一覧取得が可能かどうかを確認します。
適切に制限されていれば 403 Forbidden となるはずですが、s3:ListBucket が公開されている場合は、XML形式でバケット内オブジェクトの一覧が返されることがあります。
# S3バケットのルートに直接アクセスしてみる
curl -v https://[your-bucket-name].s3.[region].amazonaws.com/
# CloudFront経由でURLのルートにアクセスしてみる
curl -v https://[your-domain].cloudfront.net/
成功した場合、レスポンスとして以下のようなXMLが返ってきます。
※ 以下は筆者が検証用に作成したサイトの情報です。

リスク
S3バケットの一覧が見える状態は、セキュリティ診断において情報の漏えいというカテゴリーで扱われます。
1. 偵察の効率化
攻撃者が最初に行うのはサイトの構造把握です。通常はツールを使って総当たりでファイルを探しますが、オブジェクトの一覧が確認できればその必要がありません。
- リスク: サイト全体のディレクトリ構造が把握され、攻撃の足がかりとなるポイント(管理画面、開発用ページなど)が特定されます。
2. 機密ファイルの露出
開発者がフロント画面からはリンクしていないから大丈夫だと思って放置しているファイルが、リストとして表示されることで容易にアクセス可能になります。
- バックアップファイル: config.php.bak, database.sql.gz, old_index.zip など
- 設定ファイル: 外部APIキーやDBのパスワードが含まれる .env や .bash_history
- ソースコード管理: .git ディレクトリなど(ここから全ソースコードを復元されるケースもあります)
3. ソフトウェアバージョン情報の漏洩
ファイル名やディレクトリ名にバージョン番号が含まれている場合、攻撃者は既知の脆弱性があるかどうかをすぐに判断できます。
- 例: wordpress-5.4.1/ というフォルダが見えれば、そのバージョンに特化したエクスプロイトコードを探すことが出来ます。
まとめ
S3は単なるオブジェクトストレージとして使うだけでなく、静的ウェブサイトホスティングやCloudFrontと組み合わせたコンテンツ配信基盤としても広く利用されています。
一方で、その柔軟さゆえに、バケットポリシー、Block Public Access、OAC、CloudFrontのビヘイビア設定などが少し崩れるだけで、意図しない公開、CloudFrontのバイパス、オブジェクトの改ざん、一覧情報の露出といった問題につながります。
今回はS3に関連した脆弱性をまとめましたが、AWS特有の設定不備に起因する脆弱性は他にもいろいろあるので、気が向いたら続編を書こうと思います。
Discussion