データを安全に扱う
プログラムは、入力を受け取るだけでなく、データベース・ファイル・外部サービスなどと連携することがあります。データの種類や利用先に応じた安全対策が必要です。
文字列連結で命令文を作らない
データベースへ問い合わせるとき、入力値を文字列連結してSQL文を作る設計は避けます。入力値が命令文の一部として解釈される危険があるためです。
データベースを使う場合は、利用するライブラリが提供するパラメーター化クエリを使い、命令文と値を分離します。パラメーター化は、入力値をSQLの構文として扱わせないための基本的な対策です。
同じ考え方は、シェルコマンドやテンプレートなど、文字列が命令として解釈される仕組みにも当てはまります。外部入力をそのまま命令文へ埋め込まないでください。
ファイルパスを検証する
利用者が指定したファイル名を扱う場合、入力されたパスをそのまま読み書きに使ってはいけません。
- アプリケーションが許可した保存先の範囲に限定する。
- 絶対パスや親ディレクトリへの移動を意図した指定を拒否する。
- ファイル名の長さや形式を検証する。
- 読み書きの権限を必要最小限にする。
- エラー時に、内部のファイル構成や機密情報を表示しない。
文字列としてパスを確認するだけでは、シンボリックリンクなどによって想定外の場所を参照する可能性があります。実際のファイル操作では、実行環境の機能も使って保存先を制限してください。
秘密情報をソースコードへ書かない
パスワード、APIキー、アクセストークン、秘密鍵などをソースコードや教材、公開リポジトリへ直接書いてはいけません。
- 環境変数や専用のシークレット管理機能を利用する。
- 開発用と本番用の認証情報を分ける。
- 必要な権限だけを持つ認証情報を使う。
- 不要になった認証情報は失効させる。
- ログやエラーメッセージに秘密情報を含めない。
環境変数はソースコードへの直書きを避ける手段のひとつですが、誰でも読める場所へ表示したり、ログへ出したりしてよいわけではありません。実行環境のアクセス制御も必要です。
外部ライブラリを安全に使う
外部ライブラリは便利ですが、追加する前に必要性と信頼性を確認します。
- 目的に合ったライブラリか確認する。
- 正規の配布元・公式パッケージ名を確認する。
- 更新状況や既知の脆弱性情報を確認する。
- 利用するバージョンを管理し、変更内容を確認して更新する。
- 不要になった依存関係を削除する。
名前が似ているだけの偽パッケージを導入しないよう、パッケージ名と配布元を確認してください。
出力先に合わせてエンコードする
入力値をHTMLやWebページへ表示する場合、表示先の文脈に合ったエンコードを行います。HTML本文・属性値・JavaScript・URLでは必要な処理が異なります。
単純な文字列置換で安全性を確保しようとせず、利用するWebフレームワークやテンプレートエンジンが提供する安全な出力機能を使います。HTMLとして表示する必要のない入力は、HTMLとして解釈させないことが基本です。
安全なプログラムを確認するチェックリスト
- 外部入力を用途に応じて検証している。
- 入力値を命令文へ直接連結していない。
- ファイル操作の対象範囲を制限している。
- 秘密情報をソースコードやログへ含めていない。
- 実行権限を必要最小限にしている。
- 外部ライブラリの配布元と更新状況を確認している。
- エラー時に内部情報を利用者へ過剰に公開していない。
セキュリティ対策は一つだけで完結しません。入力検証、権限管理、安全なAPIの利用、依存関係の管理を組み合わせて、問題が起きにくく、起きても影響を抑えられる設計にします。