Webアプリでデータベース(DB)などへの接続文字列をコード中に直接記述することは、割とありがちだ。でも危険なのでコードからは分離した方がよい。Azure Web Appsでの改善方法は?
対象サービス:Microsoft Azure、Web Apps
TIPS「AzureのTraffic ManagerでカスタムドメインやSSL証明書を割り当てる際の手順と注意」に記したように、弊社のマップサービスのバックエンドサーバにはTraffic Managerを利用している。その実装・構築の際、Webアプリのコード側でデータベースの接続文字列の取り扱いを改善する必要があった(もともとの実装が決してよくなかったのだが)。本稿では、その方法について説明したい。
Webアプリからデータベース(DB)にアクセスする場合、サーバ名やデータベース名、ID/パスワードなどを記述した「接続文字列」をAPIで指定することがよくある。この接続文字列はコードに直接埋め込むのが簡単で手軽なのだが、それには無視できない重要な問題点がある。
要するにセキュリティ面で脆弱(ぜいじゃく)であり、またコードの再利用もしにくいということだ。
前述のTraffic Managerの場合は、「正しい」データベースが選択されない、という問題が生じた。
筆者は東日本リージョンに構築してあったWeb AppsとAzure SQL Databaseのセットを、そっくり西日本リージョンに複製し、その後もコードやデータがリアルタイムで東日本から西日本へレプリケーションされるように設定した。それをTraffic Managerで束ねることで可用性を高めようとした。
ここで、西日本のWeb Appsが(想定していた)西日本のSQL Databaseではなく、東日本の方に接続してしまうことに気付いた。原因は、西日本にレプリケーションされたWebアプリのコード中にDB接続文字列が直接記述されていて、それが東日本のSQL Databaseを指していたからだ。
このままでは東日本のSQL Databaseがダウンすると、すぐに両リージョンのWeb Appsも応答不能になる。つまりTraffic Manager配下の全サイトがダウンするため、その可用性向上の効果も大幅に薄れてしまう。
この問題はWeb Appsに備わっている接続文字列の設定機能を利用して、コードから接続文字列を分離することであっさりと解決できた。それほど難しくはなかったものの、つまずいたところもあったので、その設定方法を具体的に説明しよう。例示しているのはPHPとAzure SQL Databaseだが、中核となるWeb Appsの仕組みは共通なので、他の言語やデータベースでも参考にはなるだろう。
まずはAzureポータルで対象のWeb Appsに接続文字列を設定する。
設定した接続文字列は、PHPやPython、Java、node.jsでは環境変数で参照できる。一方、.NETアプリケーションの場合は構成ファイルのconnectionStringsセクションに設定される。
環境変数の場合、その名称は前述のアプリケーション設定で指定した<名前>((6))とサービス/サーバの選択肢((8))によって、以下のように決まる。
サービス/サーバ | メニューの選択肢 | 環境変数名 |
---|---|---|
Azure SQL Database | SQL Database | SQLAZURECONNSTR_<名前> |
SQL Server | SQL Server | SQLCONNSTR_<名前> |
MySQL | MySQL | MYSQLCONNSTR_<名前> |
PostgreSQL | PostgreSQL | POSTGRESQLCONNSTR_<名前> |
Azure 通知ハブ | 通知ハブ | NOTIFICATIONHUBCONNSTR_<名前> |
Azure Service Bus | Service Bus | SERVICEBUSCONNSTR_<名前> |
Azure Event Hubs | イベント ハブ | EVENTHUBCONNSTR_<名前> |
Azure Cosmos DB(DocumentDB API) | ドキュメント DB | DOCDBCONNSTR_<名前> |
Azure Redis Cache | Redis Cache | REDISCACHECONNSTR_<名前> |
上記以外のサーバ/サービス | カスタム | CUSTOMCONNSTR_<名前> |
接続文字列の環境変数名の決まり方 前述のアプリケーション設定のうち、(6)の<名前>と、(8)のサービス/サーバの選択によって、Webアプリから参照すべき環境変数名が決まる。 |
接続文字列の内容は、Webアプリのコードや接続先のサーバ/サービスによって異なる。例として、PHPとAzure SQL Databaseの組み合わせに対して筆者が設定している接続文字列を挙げておく。
"sqlsrv:server=<SQL Databaseサーバ名>.database.windows.net;database=<データベース名>;<各種パラメータ>","<ログイン名>","<パスワード>"
上記の設定が済んだら、実際に設定された環境変数をWebアプリから確認してみよう。PHPであればphpinfo()の出力のうち、「Environment」セクションで環境変数の一覧を確認できる。
後はコードを修正して、決め打ちだった接続文字列を環境変数から取得するように変更する。参考までにPHPでの例を以下に記す。
$envPrefix = "SQLAZURECONNSTR_"; ……Azure Web Apps + Azure SQL Databaseでの環境変数名の接頭語
$envName = $envPrefix + "PDO3"; ……対象の環境変数名
$connStr = getenv($envName); ……環境変数から接続文字列を取得
if (empty($connStr)) {
error_log("環境変数 $envName が見つかりませんでした。");
return false;
}
$conn = explode(",", $connStr); ……配列に分割して保存
if (!$conn || count($conn) !== 3) {
error_log("環境変数 $envName に接続文字列が正しく設定されていませんでした。");
return false;
}
$dsn = trim($conn[0], '"'); ……ダブルクオートを削る
$login = trim($conn[1], '"');
$password = trim($conn[2], '"')
try {
$pdo = new PDO($dsn, $login, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); ……エラー時に例外を発生させる
} catch (PDOException $ex) {
$errMsg = "PDOException: DSN = " . $dsn . ", Line No = " . $ex->getLine() . ", Message = " . $ex->getMessage();
error_log($errMsg);
return false;
}
return $pdo;
接続文字列がコードからAzure Web Appsの設定項目に移ったので、以後はWeb Appsの設定項目から外部に漏れないよう、注意を払う必要がある。AzureポータルではIAM(Identify & Access Management)によってポータルを参照できるユーザーを細かく制限できるので、必要に応じて設定することが望ましい。
Copyright© Digital Advantage Corp. All Rights Reserved.