【入門編】コマンドインジェクションを防ぐためのOSコマンド実行の回避 – アプリケーションセキュリティ & 安全な開発防御ガイド

なぜ「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. ホワイトリストを活用する: 許可されたもの以外は、門前払いする。

セキュリティの達人は、決して複雑なコードを書く人ではありません。「シンプルで、隙のない仕組みを作れる人」のことです。

最初は難しく感じるかもしれませんが、一つひとつの入力箇所を「これは玄関かな?裏口かな?」と確認するクセをつけるだけで、あなたの書くコードは驚くほど安全になります。一緒に、強固で美しいアプリケーション作りを目指していきましょう!

何か分からないことがあれば、いつでも質問してくださいね。応援しています!

コメント

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