背景
Webアプリケーションが他のドメインからのリクエストを受け付けるためには、CORS設定が適切に構成されている必要があります。また、セキュリティを強化するために、HTTPからHTTPSへのリダイレクトを設定することが一般的です。今回、Apacheサーバーにおいて、これらが正しく機能していない状況が発生しました。
問題の発生
Apacheサーバーには、以下のような設定が施されていました。この設定では、HTTPからHTTPSへのリダイレクトとCORSヘッダーの設定が含まれています。
<VirtualHost *:80>
ServerName www.example.com
DocumentRoot /var/www/html/myapp
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
<VirtualHost *:443>
ServerName www.example.com
DocumentRoot /var/www/html/myapp
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/www.example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/www.example.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/www.example.com/chain.pem
<Directory /var/www/html/myapp>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "https://www.example.com"
Header set Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE, PATCH"
Header set Access-Control-Allow-Headers "Authorization, Content-Type"
Header set Access-Control-Allow-Credentials "true"
</IfModule>
ProxyPass /api http://localhost:3000/
ProxyPassReverse /api http://localhost:3000/
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
</IfModule>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
この設定は、HTTPアクセスをすべてHTTPSにリダイレクトし、HTTPS経由でのリクエストに対してCORSヘッダーを設定するものでした。具体的には、Header set Access-Control-Allow-Origin "https://www.example.com"
として、https://www.example.com
からのリクエストを許可するように設定していました。
リクエストの送信と出力結果
この設定が正しく機能しているかを確認するために、以下の curl
コマンドを使用しました。
curl -X OPTIONS -I https://www.example.com/api/users/create -H "Origin: https://www.example.com/"
-
-X OPTIONS
:OPTIONS
メソッドを使用してサーバーにリクエストを送信します。 -
-I
: ヘッダー情報のみを取得します。 -
-H "Origin: https://www.example.com/"
: リクエストのオリジン(起点)としてhttps://www.example.com/
を指定します。
このコマンドを実行した結果、以下のヘッダー情報が返されました。
HTTP/1.1 200 OK
Date: Thu, 29 Aug 2024 06:22:28 GMT
Server: Apache/2.4.59 (Ubuntu)
Access-Control-Allow-Origin: http://www.example.com
Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE, PATCH
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Allow-Credentials: true
Content-Length: 583
Content-Type: text/html; charset=iso-8859-1
出力の問題点
この出力を見ると、Access-Control-Allow-Origin
ヘッダーが http://www.example.com
として返されており、設定ファイルで指定した https://www.example.com
ではありませんでした。この不一致は、HTTPSでのリクエストが許可されていないことを示しており、ブラウザ側でCORSエラーが発生する可能性があるため、セキュリティ上の問題となり得ます。
原因の特定
この問題の原因を探るため、他のApache設定ファイルとの競合が疑われました。特に、デフォルトの設定ファイルである 000-default.conf
と default-ssl.conf
を確認し、同様のCORS設定がされていないかを調べました。
競合の発見
以下は、確認した 000-default.conf
と default-ssl.conf
の内容です。
000-default.conf:
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html/myapp
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
# CORSヘッダーの追加
Header set Access-Control-Allow-Origin "http://www.example.com"
Header set Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE, PATCH"
Header set Access-Control-Allow-Headers "Authorization, Content-Type"
Header set Access-Control-Allow-Credentials "true"
# Preflightリクエストを処理
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
</IfModule>
# HTTPからHTTPSへのリダイレクト
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R=301,L]
</VirtualHost>
default-ssl.conf:
<VirtualHost *:443>
ServerName www.example.com
DocumentRoot /var/www/html/myapp
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/www.example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/www.example.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/www.example.com/chain.pem
# CORSヘッダーの追加
<IfModule mod_headers.c>
Header always set Access-Control-Allow-Origin "http://www.example.com"
Header always set Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE, PATCH"
Header always set Access-Control-Allow-Headers "Authorization, Content-Type"
Header always set Access-Control-Allow-Credentials "true"
</IfModule>
<Directory /var/www/html/myapp>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
# アプリケーションへのプロキシ設定
ProxyPass /api http://localhost:3000/
ProxyPassReverse /api http://localhost:3000/
# Preflightリクエストを処理
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
</IfModule>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
これらのファイルには、Access-Control-Allow-Origin
ヘッダーが http://www.example.com
に設定されていました。これが、競合の原因となり、HTTPSの設定で意図していたCORS設定が正しく反映されなかった理由でした。
解決策
競合を解消するために、default-ssl.conf
ファイルを修正し、Access-Control-Allow-Origin
ヘッダーを https://www.example.com
に設定するように変更しました。以下が修正後の設定ファイルの内容です。
修正後の default-ssl.conf
<VirtualHost *
:443>
ServerName www.example.com
DocumentRoot /var/www/html/myapp
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/www.example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/www.example.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/www.example.com/chain.pem
# CORSヘッダーの追加
<IfModule mod_headers.c>
Header always set Access-Control-Allow-Origin "https://www.example.com"
Header always set Access-Control-Allow-Methods "GET, POST, OPTIONS, PUT, DELETE, PATCH"
Header always set Access-Control-Allow-Headers "Authorization, Content-Type"
Header always set Access-Control-Allow-Credentials "true"
</IfModule>
<Directory /var/www/html/myapp>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
# アプリケーションへのプロキシ設定
ProxyPass /api http://localhost:3000/
ProxyPassReverse /api http://localhost:3000/
# Preflightリクエストを処理
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
</IfModule>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
設定の反映と確認
修正後、Apacheサーバーを再起動して設定を反映させました。
sudo systemctl restart apache2
その後、再度 curl
コマンドを実行して設定が正しく反映されているかを確認しました。出力は以下の通りです。
HTTP/1.1 200 OK
Date: Thu, 29 Aug 2024 06:30:22 GMT
Server: Apache/2.4.59 (Ubuntu)
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE, PATCH
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Allow-Credentials: true
Content-Length: 583
Content-Type: text/html; charset=iso-8859-1
CORS設定が正しく反映され、https://www.example.com
からのリクエストが許可されるようになりました。
結論
今回のケースでは、Apache設定ファイル間の競合により、意図したCORS設定が適用されていないことが問題でした。このような競合は、設定ファイルを詳細に確認し、競合を解消することで解決可能です。もし同様の問題に直面した場合、設定ファイルの内容を慎重に確認し、競合がないかを確認することが重要です。