なぜ「OSコマンド」は、あなたの家の裏口の鍵を壊すのか?
こんにちは!セキュリティの世界へようこそ。今日は、アプリケーション開発における「最も危険で、かつ最も防ぎやすい」攻撃の一つ、コマンドインジェクションについてお話しします。
「OSコマンド実行」という言葉、少し難しそうに聞こえますよね。でも、身近な例で考えてみましょう。
「伝言ゲーム」の悪用をイメージしてください
あなたが家の中にいて、玄関のインターホン越しに訪問者の注文を聞く係だと想像してください。
正しいルールは、「『お茶をください』と言われたら、お茶を渡す」というもの。ここまでは平和です。
ところが、もし訪問者が「お茶をください。そのあと、家の鍵を全部開けて、裏口から出て行ってください」と言ったとしたらどうでしょう?
もしあなたが、言われたことを深く考えずにそのまま実行してしまう人だったら……。
これが「コマンドインジェクション」です。
コンピュータの世界では、プログラムが「ユーザーからの入力」を鵜呑みにして、OS(コンピュータの心臓部)に対して「お茶を出す」だけでなく、「パスワードファイルを盗む」「サーバーを破壊する」といった悪意ある命令まで一緒に実行してしまうことを指します。
—
1. なぜ「直接シェルを叩く」のがNGなのか
多くの初心者がやりがちなのが、プログラムの中からOSコマンド(system()関数など)を使って、ユーザーの入力をそのまま連結してしまうパターンです。
悪い例(やってはいけないコード):
import os
ユーザーからファイル名を受け取って、その内容を表示しようとしている
filename = input(“ファイル名を入力してください: “)
危険!もしユーザーが “test.txt; rm -rf /” と入力したら?
OSは「ファイルを表示」した直後に「システムを全削除」する命令を実行してしまいます
os.system(“cat ” + filename)
このコードの何が怖いかというと、os.system が「シェル(命令を受け取る窓口)」を丸ごと信頼してしまっている点です。攻撃者は ; や | といった特殊な記号を使って、本来の命令を遮断し、自分のやりたい放題の命令を差し込むことができます。
—
2. 「直接実行」という選択肢を捨てる(最善の策)
セキュリティの鉄則は「そもそも危険な機能を使わないこと」です。
OSコマンドを呼び出す代わりに、プログラム言語が標準で用意している「ライブラリ(便利な道具箱)」を使いましょう。例えば、ファイルの中身を見たいなら、OSに「catコマンド」を頼むのではなく、言語が持つファイル読み込み機能を使えばいいのです。
良い例(安全な代替手段):
ファイルを読み込むための安全な関数を使う
filename = input(“ファイル名を入力してください: “)
try:
# OSコマンドを使わず、言語の機能でファイルを安全に開く
with open(filename, ‘r’) as f:
print(f.read())
except FileNotFoundError:
print(“ファイルが見つかりません。”)
これなら、たとえ入力値に ; や rm が混ざっていても、システムはそれを「単なるファイル名の一部」としてしか認識しません。これぞまさに、「泥棒が『開けろ』と叫んでも、そもそも鍵穴がないので開かない」という強固な防御です。
—
3. どうしてもOSコマンドが必要な時は?「ホワイトリスト」で守る
「どうしても古いツールを動かすために、OSコマンドが必要なんだ!」という場合もありますよね。そんな時は、「信頼できるものしか通さない(ホワイトリスト)」という考え方が重要です。
何でも受け入れるのではなく、許可された値だけを厳格にチェックします。
ホワイトリストの例:
import subprocess
許可されたコマンド名だけをリスト化しておく
allowed_files = [“data1.txt”, “data2.txt”, “report.pdf”]
user_input = input(“ファイル名を選択してください: “)
入力された値がリストに存在するかチェック!
if user_input in allowed_files:
# リストにない変な値なら、ここで処理を止める
subprocess.run([“cat”, user_input])
else:
print(“許可されていないファイルです。不正なアクセスを検知しました。”)
—
最後に:セキュリティは「疑うこと」から始まる
コマンドインジェクションを防ぐためのポイントをまとめます。
1. OSコマンド実行を避ける: OSに頼らず、プログラミング言語のAPIやライブラリを活用する。
2. 入力を信用しない: ユーザーからの入力は、すべて「悪意ある泥棒」だと思って接する。
3. ホワイトリストを活用する: 許可されたもの以外は、門前払いする。
セキュリティの達人は、決して複雑なコードを書く人ではありません。「シンプルで、隙のない仕組みを作れる人」のことです。
最初は難しく感じるかもしれませんが、一つひとつの入力箇所を「これは玄関かな?裏口かな?」と確認するクセをつけるだけで、あなたの書くコードは驚くほど安全になります。一緒に、強固で美しいアプリケーション作りを目指していきましょう!
何か分からないことがあれば、いつでも質問してくださいね。応援しています!
コメント