サーバアーキテクチャ

【図解】わかりやすい環境変数の仕組み~Windows/Linuxの実用例と確認コマンド~

環境変数とは

環境変数とは、OS が提供するデータ共有の仕組みであり、主にその OS 上で動作するプロセス (メモリ上のプログラム) がそのデータを参照し、振る舞いを変えるためにあります。

OS の機能ではありますが、各プロセスは『OS の環境変数のひな型』を参照するわけではありません。

プロセスは起動時に、必要に応じて『OS の環境変数のひな型』から環境変数を受け取ることができます。受け取った環境変数はそのプロセスが消滅するまで、個別に保持、管理、参照されます。

つまり、プロセス毎に持っている環境変数は異なるわけです。

Windows の環境変数

システム環境変数とは、ユーザー環境変数とは

Windows の「システム環境変数」と「ユーザー環境変数」は、ひな型に該当します。

「システムのプロパティ」⇒「詳細設定」⇒「環境変数(N)...」をクリックすると【ユーザー環境変数(U)】と【システム環境変数(S)】が表示されます。

「システム環境変数」は全ユーザー共通のひな形で「ユーザー環境変数」はログインしているユーザー個別のひな形です。

Windows の各プロセスの環境変数

Windows で環境変数を表示するコマンドとして set コマンドがあります。コマンドプロンプト上で実行すると、「コマンドプロンプト (cmd.exe)」というプロセスが持っている環境変数を表示します。

これは通常は上記システム環境変数とユーザー環境変数の集合になります。

ですが繰り返しますが上記はあくまで「コマンドプロンプト」というプロセスの環境変数です。

その他のプロセスの環境変数を見るのはひと手間必要です。例えば、MS 公式のツールである「Process Explorer」等で見ることができます。以下は、Process Explorer で表示された Chrome.exe のプロセスをダブルクリックし、「Environment」タブをクリックしたときの様子です。これが Chrome.exe のプロセスが持っている環境変数です。

Process Explorer は以下でダウンロードできます。

プロセス エクスプローラー - Sysinternals
開いているファイル、レジストリ キー、およびその他のオブジェクト プロセス、読み込まれた DLL などを確認します。

Linux の環境変数

Linux では同様に env コマンドというコマンドがあります。

[root@localhost ~]# env

ですがこれもやはりそのシェルプロセスが持っている環境変数にすぎません。

その他の各プロセス (アプリケーション) がどのような環境変数を持っているかを確認するには /proc/{pid}/environ の中身を覗きます。以下は systemd (pid=1) の環境変数を表示しています。

[root@localhost ~]# cat /proc/1/environ
TERM=linuxBOOT_IMAGE=(hd0,gpt2)/vmlinuz-5.14.0-70.22.1.el9_0.x86_64

全ユーザー共通のひな型 (Windows のシステム環境変数に相当) は例えば /etc/environment, /etc/profile および /etc/profile.d/ ディレクトリ内などがあります。正確に言うと、このファイルに環境変数の定義が記述されているわけではありません。これらは起動時などに読み込まれるスクリプトであり、そのスクリプト内で export コマンド (後述) を使って環境変数として読み込みます。

同様に、各ユーザー個別のひな型は例えば /home/[username]/.bashrc に含まれています。これらはユーザーログイン時などに読み込まれます。

上記はあくまで一例であり、これ以外にも各所で環境変数を取り入れる仕組みがあります。

環境変数の確認方法、設定コマンド

Windows の場合

前述の通り、Process Explorer 等のツールで確認することができます。

コマンドプロンプトの環境変数に限っては、set コマンドで確認できます。

C:\> set

コマンドプロンプトに環境変数 HOGE=fuga を設定する場合は以下の通りです。

C:\> set HOGE=fuga

ただし、これはコマンドを打ったコマンドプロンプトプロセスのみで有効ですが、そこから起動するプロセスには反映されません。各プロセスに引き継ぎたい場合は、setx を使ってユーザーのひな型のほうに設定を加えます。

C:\> setx hoge FUGA

(set と違い、= が不要であることに注意)

Linux の場合

確認コマンドは前述の通り、cat /proc/{pid}/environ で確認できます。{pid} は ps aux | grep [process 名] 等で調べます。

[root@localhost ~]# ps aux | grep -e PID -e bash
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
test 1243 0.0 0.1 5612 4336 pts/0 Ss 11:51 0:00 -bash
root 1264 0.0 0.1 5712 4300 pts/0 S 11:51 0:00 /bin/bash
root 1335 0.0 0.0 4456 2196 pts/0 S+ 12:02 0:00 grep --color=auto -e PID -e bash
[root@localhost ~]# cat /proc/1229/environ | sed -e 's/\x00/\n/g'
USER=test
LOGNAME=test
HOME=/home/test
PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin
SHELL=/bin/bash
TERM=xterm
SELINUX_ROLE_REQUESTED=
SELINUX_LEVEL_REQUESTED=
SELINUX_USE_CURRENT_RANGE=
MOTD_SHOWN=pam
XDG_SESSION_ID=1
XDG_RUNTIME_DIR=/run/user/1000
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
XDG_SESSION_TYPE=tty
XDG_SESSION_CLASS=user
SSH_CLIENT=192.168.1.2 53151 22
SSH_CONNECTION=192.168.1.2 53151 192.168.1.221 22
SSH_TTY=/dev/pts/0

cat /proc/{pid}/environ だけだと各変数の区切り文字が NULL (\x00) でコンソールでは表示されず境目が分からないため、sed で改行に変換しています。

現在のシェルの環境変数を確認する場合は env です。

[root@localhost ~]# env

現在のシェルに環境変数 HOGE=fuga を設定する場合は export HOGE=fuga です。

[root@localhost ~]# export HOGE=fuga

Linux の場合は、このシェルから作り出した子プロセスにこの環境変数含めて引き継がせることができます。

Windows/Linux の共通した有名な環境変数 PATH

例えば有名な環境変数の 1 つとしては PATH があります。これは Windows でも Linux でも使われますが、シェルからコマンドを打つときに、コマンドの場所の探し場所を指定した環境変数です。

つまり、主にシェル系のプロセス (アプリケーション) で使われる環境変数です。

例えば Windows のコマンドプロンプトで "ping 1.1.1.1" を実行するケースを考えます。

もし環境変数 PATH が何も設定されていない場合、現在のディレクトリ (C:\Users\test>) 上に ping.exe コマンドファイルが無いと実行できません。もしくは、C:\Windows\System32\ping 1.1.1.1 とフルパスで指定する必要があります。以下は where コマンドで ping のフルパスを探し、フルパスで ping コマンドを指定し実行しています。(where コマンドも PATH 内にあるためそのまま使えています。)

c:\> where ping
C:\Windows\System32\PING.EXE

c:\> C:\Windows\System32\PING 1.1.1.1

1.1.1.1 に ping を送信しています 32 バイトのデータ:
1.1.1.1 からの応答: バイト数 =32 時間 =20ms TTL=55
1.1.1.1 からの応答: バイト数 =32 時間 =39ms TTL=55

ですが環境変数 PATH に C:\Windows\System32 が含まれているため、ping 1.1.1.1 と入力するだけで、C:\Windows\System32\ping 1.1.1.1 が実行できるわけです。(Windows の場合、実行ファイルは .exe を省略できます。)

このようにフルパスを指定せずに実行できる状態を一般に「PATH が通っている」と言います。

Linux でも同様です。which コマンドで ping のコマンドフルパスを確認すると /sbin/ping となっており、本来は以下のようにフルパスで ping コマンドを指定し実行しますが、

[root@localhost ~]# which ping
/sbin/ping
[root@localhost ~]# /sbin/ping 1.1.1.1
PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
64 バイト応答 送信元 1.1.1.1: icmp_seq=1 ttl=55 時間=30.5ミリ秒
64 バイト応答 送信元 1.1.1.1: icmp_seq=2 ttl=55 時間=22.7ミリ

環境変数 PATH に /sbin が含まれているため、ping 1.1.1.1 だけで実行が可能なわけです。

環境変数 SSLKEYLOGFILE

環境変数 SSLKEYLOGFILE はブラウザ等から参照される環境変数であり、ブラウザはこの環境変数が設定されている場合はその変数に格納された値が示す場所 (ファイル) に TLS セッションキーを書き込みます。

これは、ブラウザ開発者が意図して「環境変数 SSLKEYLOGFILE が設定されていればその値を読み込み、TLS セッションキー情報を書き込む」というプログラミングをした結果です。

ブラウザは Windows でも Linux でも動作することが期待され、どちらの OS 環境であっても環境変数 SSLKEYLOGFILE を設定すれば上記の動作になります。

参考

【解析/Wireshark】https(SSL/TLS)を復号化する方法(SSLKEYLOGFILE),ブラウザで見る方法
Wireshark で https を復号するには Wireshark は N...

ハードコーディングを防ぐための環境変数

環境変数は自分で作成するプログラムやスクリプトでも利用することができます。

例えば Python で API キーを扱うときは、セキュリティの観点からハードコーディングはしてはなりません。ファイル上=ディスク上に平文でキー等の機密情報を書き込むと流出リスクが高まるためです。

環境変数として扱えばメモリ上で扱えることができます。

以下 URL の例では "export apikey=" コマンドにより API キーを環境変数 apikey としてメモリ上に読み込んだ上で Python コードを実行しています。Python コード内に API キーを書き込んでいないため、このようにブログでサンプルコードをそのまま公開しても問題ありません。

VirusTotal+PythonでURL/IPリストから危険なものを検出する
やりたいこと Google が運営する「VirusTotal」の無償公開 AP...

状態を表す環境変数

前述の SSLKEYLOGFILE や apikey はどのアプリケーションがどのように利用するか、ある程度想定されたものでしたが、汎用的な目的で保存される環境変数もあります。 例えば Linux へログインした場合、env コマンドで見てみると環境変数として例えば以下のような変数が割り当てられていることが分かります。

LANG=ja_JP.UTF-8
HOSTNAME=rocky1
USER=test
PWD=/home/test
HOME=/home/test
MAIL=/var/spool/mail/test
SHELL=/bin/bash
SHLVL=1

なのでシェルから起動したアプリケーションはこれらの情報を引き継ぎ、言語を日本語 UTF-8 だと認識して表示を合わせたり、ホスト名やユーザー名を認識して表示をフィードバックしたり、カレントディレクトリを認識したりすることができます。

SSH 接続した場合はさらにいくつか加わります。(例えば以下)

SSH_CONNECTION=192.168.1.2 58772 192.168.1.211 22
SSH_TTY=/dev/pts/0

このように、アプリケーションはどのような状態で SSH 接続しているかを知ることができます。

これらの環境変数は汎用的であり、利用用途は多岐にわたります。

まとめ

以上から分かる通り、環境変数は「各プロセスが保持し、参照し、その変数の中身によってふるまいを変える」ためのものであり、「各プロセスが個別に管理する変数」です。

コメント

タイトルとURLをコピーしました