変更要約: 初版
4.3アプリセキュリティ
認証情報を安全に扱うsecret管理(環境変数/シークレットストア・平文コミット禁止)と暗号化(保存時と転送時)、そしてファイアウォール・DNS・ロードバランサ・リバースプロキシの役割、さらにOWASPの代表的脅威(XSS・SQLi・CSRF)を、「この扱いは何を守り、どこが穴か」という診断として学びます。
アプリのセキュリティは「機能を追加する」より「穴を作らない」ことが本質です。API キーをソースに直書きして git に push すれば、コードを見た誰もが本番を触れてしまいます。暗号化も「掛ければ安全」ではなく、保存時と転送時のどちらを守っているのかを区別できないと守れません。この節では、secret の扱い・暗号化・境界のインフラ部品(ファイアウォール/DNS/LB/リバースプロキシ)・OWASP の代表脅威を、「この扱いは何を守り、どこが穴か」を診断する視点で学びます。
4.3.1secret管理とデータ暗号化
- secret(機密情報)=API キー・パスワード・トークン・秘密鍵など。ソースコードに直書きして版管理へコミットするのは禁忌(履歴に残り、公開/漏洩すると即悪用される)。正しくは環境変数や専用のシークレットストア/vaultから実行時に読み込み、リポジトリには置かない(
.gitignoreで.envを除外する)。 - 暗号化は守る対象で2種類に分ける:保存時の暗号化(at rest)はディスク/DB 上のデータを暗号化し、媒体の盗難や不正コピーから守る。転送時の暗号化(in transit)は TLS/HTTPS で通信経路を暗号化し、盗聴/改ざんから守る。両方が必要で、「HTTPS だから DB も安全」のように片方でもう片方を代替できない。
- データの取り扱いでは、必要以上に集めない/持たない(最小化)、扱う分類(個人情報/機密)に応じた保護、ログや通知にsecret や個人情報を漏らさない(トークンをそのままログ出力しない)といった原則を守る。漏洩の多くは高度な攻撃ではなく平文の置き忘れから起きる。
4.3.2境界のインフラ部品
- ファイアウォール=ポリシに基づき通信を許可/拒否する境界の関所。DNSは名前(
api.example.com)を IP に解決する仕組みで、これ自体は防御装置ではないが、名前解決が失敗すればアプリは相手に到達できない(接続性診断の要)。 - ロードバランサ(LB)=受けた要求を複数のバックエンドへ分散し、可用性とスケールを確保する(1台が落ちても残りで受ける)。リバースプロキシはクライアントとバックエンドの間に立ち、TLS 終端・キャッシュ・ルーティング・バックエンド隠蔽などを担う。LB とリバースプロキシは役割が重なることもあるが、「分散」が主眼か「仲介/終端」が主眼かで使い分けを判断する。
4.3.3OWASPの代表脅威
- XSS(クロスサイトスクリプティング)=攻撃者が仕込んだスクリプトが他ユーザのブラウザで実行される。原因はユーザ入力を無害化せず HTML に出力すること。対策は出力エスケープと入力検証(例:
<script>を無害化)。 - SQLi(SQLインジェクション)=ユーザ入力を文字列連結でクエリに埋め込むと、
' OR '1'='1のような入力で DB が乗っ取られる。対策はパラメータ化クエリ(プリペアドステートメント)で入力を値として扱い、SQL 構文として解釈させないこと。 - CSRF(クロスサイトリクエストフォージェリ)=ログイン中のユーザのブラウザに、本人の意図しない副作用のある要求(送金・設定変更等)を第三者サイト経由で送らせる。対策はCSRFトークン(正規フォーム由来の要求だけ受理)や SameSite Cookie。
「secretは環境変数/vaultで実行時読込・ソース直書きコミット禁止」「暗号化は保存時(at rest)と転送時(in transit=TLS/HTTPS)を区別・両方必要で片方が片方を代替しない」「LB=分散で可用性/スケール・リバースプロキシ=TLS終端/仲介/隠蔽」「XSS=出力エスケープ・SQLi=パラメータ化クエリ・CSRF=CSRFトークン」が頻出です。設問はこの扱い/コードのどこが穴かの診断として来ます。
あなたは新人が書いた Python の API クライアントをレビューしています。冒頭に API_KEY = "sk_live_9f2c...本物の本番キー" と直書きされ、そのままリポジトリへ push されていました。これは最も基本的で最も危険な穴です。git の履歴に本番キーが永久に残り、リポジトリを閲覧できる全員(外注/退職者/公開時は世界中)がそのキーで本番を操作できます。正しい修正は、キーをコードから外して環境変数(例:実行時に os.environ["API_KEY"] で読む)やシークレットストアから読み込み、.env を .gitignore に入れてリポジトリに含めないこと、そして既に push してしまったキーは無効化して再発行(ローテーション)することです(履歴から消すだけでは、既に漏れた可能性を潰せない)。続けてそのアプリのデータ保護方針を見ると、「通信は HTTPS だから DB の暗号化は不要」と書かれていました。これは保存時と転送時を混同した誤りです。転送時の暗号化(TLS/HTTPS)は経路上の盗聴を防ぎますが、サーバのディスクや DB バックアップが盗まれたときには無力で、そこは保存時の暗号化(at rest)が守ります。両者は守る対象が異なり、片方でもう片方を代替できません。さらに入力処理を見ると、ユーザ名をそのまま "SELECT * FROM users WHERE name = '" + name + "'" と文字列連結でクエリに埋めていました。これは典型的なSQLiの穴で、' OR '1'='1 のような入力で全件が漏れます。修正はパラメータ化クエリにして入力を値として扱わせること。ここで学ぶべきは、アプリセキュリティは高度な暗号理論より、「secret を平文でコミットしない」「暗号化は保存/転送のどちらを守るか」「入力を構文として解釈させない」といった基本の穴を、提示されたコードから見抜いて塞ぐ判断が問われる、という点です。
| 脅威 | 起きること | 主な原因 | 主な対策 |
|---|---|---|---|
| XSS | 他ユーザのブラウザで不正スクリプト実行 | 入力を無害化せず HTML 出力 | 出力エスケープ・入力検証 |
| SQLi | DB のデータ漏洩/改ざん/乗っ取り | 入力を文字列連結でクエリに埋込 | パラメータ化クエリ |
| CSRF | 本人の意図しない副作用要求を強制 | 要求の正当な出所を検証しない | CSRFトークン・SameSite Cookie |
ひっかけ: 「通信を HTTPS にしていれば、DB の保存データを暗号化しなくても安全」は誤りです——転送時の暗号化は経路の盗聴を防ぐだけで、ディスク/バックアップの盗難には保存時の暗号化が別途必要です。また「secret はソースに直書きでも、後で git 履歴から消せば大丈夫」も誤り=一度 push した鍵は漏れた前提で無効化・再発行(ローテーション)すべきで、履歴削除だけでは守れません。
4.3.4この節のまとめ
- secretは環境変数/vaultから実行時読込、ソース直書き&コミット禁止。漏れた鍵は無効化・再発行する
- 暗号化は保存時(at rest)と転送時(TLS/HTTPS)を区別し両方必要——片方が片方を代替しない
- OWASP:XSSは出力エスケープ、SQLiはパラメータ化クエリ、CSRFはCSRFトークンで塞ぐ。LB=分散、リバースプロキシ=TLS終端/仲介
進捗の記録にはログインが必要です。
理解度チェック
(軽い確認用)Q1. コードレビューで、Python スクリプトの冒頭に本番の API キーが `API_KEY = "sk_live_..."` と直書きされ、そのままリポジトリへ push されているのを見つけた。是正として最も適切なものはどれか。
Q2. あるチームが「通信を HTTPS 化したので、データベースに保存するデータは暗号化しなくてよい」と方針を出した。この判断の評価として最も適切なものはどれか。
Q3. あるエンドポイントが、ユーザ入力の name を `"SELECT * FROM users WHERE name = '" + name + "'"` のように文字列連結でクエリに埋め込んでいる。`' OR '1'='1` のような入力で全件が返ってしまう。根本対策として最も適切なものはどれか。

