脆弱性という「時限爆弾」をCI/CDで無力化する:現場視点のSAST活用術
現場でコードを書いていると、どうしても「動くもの」を優先したくなる気持ちは痛いほどわかる。だが、君たちが書いているその数行のクエリが、明日、会社のデータベースを全公開する「入り口」になる可能性を想像したことはあるか?
インジェクション攻撃は、Webセキュリティの歴史の中で最も古く、そして今なお最も破壊的な攻撃だ。今回は、教科書的な説明は抜きにして、なぜSAST(静的解析)が「最後の砦」ではなく「開発の生命線」なのか、そしてどう実装すべきかを語ろう。
—
1. なぜ「心のガード」だけではインジェクションを防げないのか
SQLインジェクション(SQLi)の恐ろしさは、入力値がそのままコマンドとして解釈される点にある。例えば、ログイン機能でこんなコードを書いていないか?
// 最悪な実装例:絶対に行うな
$username = $_POST[‘user’];
$sql = “SELECT FROM users WHERE username = ‘” . $username . “‘”;
$result = $db->query($sql);
攻撃者はここに ' OR '1'='1 を投げ込む。結果、SQLは SELECT FROM users WHERE username = '' OR '1'='1' となり、パスワードなしで全ユーザー情報が抜かれる。これは攻撃者にとって「挨拶」レベルの初歩だ。
ここでの教訓は、「人間はミスをする」ということだ。どれほど熟練のエンジニアでも、深夜のデプロイや納期直前の焦りの中で、エスケープ漏れやバリデーション忘れは起こる。だからこそ、機械(SAST)に監視させる必要があるんだ。
—
2. CI/CDパイプラインへの「SAST」組み込み:実戦的アプローチ
SASTツールを「警告が出るだけの邪魔なもの」と考えるのは古い。重要なのは、「ビルドを止める」ことだ。
GitHub Actionsでの自動スキャン例 (Semgrepを使用)
Semgrepは軽量で高速、かつルールセットが充実しているため、今の現場の主流だ。以下の設定を .github/workflows/security.yml に置く。
name: Security Scan
on: [push, pull_request]
jobs:
sast:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Semgrep Scan
run: |
# 脆弱性が見つかったら終了コード1を返し、CIを強制停止させる
semgrep –config auto –error .
もし脆弱性のあるコードをプッシュすれば、GitHub上のPRで即座に指摘が入り、マージボタンはブロックされる。「後で直す」という甘えを許さない環境を作ることが、セキュリティの第一歩だ。
—
3. 「コピペで動く」セキュアな実装:プリペアドステートメントの鉄則
インジェクション対策の正解は、「クエリとデータを分離すること」に尽きる。言語ごとのベストプラクティスを叩き込んでおけ。
Python (SQLAlchemy/psycopg2) の場合
文字列連結は厳禁だ。プレースホルダー(%s)を使用せよ。
安全な実装例
def get_user(username):
# クエリの構造をDBエンジン側に先に教える
query = “SELECT FROM users WHERE username = %s”
# データは後から安全にバインドする
cursor.execute(query, (username,))
return cursor.fetchone()
JavaScript (Node.js/pg) の場合
// 安全な実装例
const query = ‘SELECT FROM users WHERE username = $1’;
const values = [req.body.username];
// ライブラリ側が適切にエスケープ処理を行う
const res = await client.query(query, values);
—
4. 現場のシニアが教える「盲点」:WAFは万能薬ではない
よくある勘違いが、「WAF(Web Application Firewall)があるからコードは適当でもいいだろう」という考え方だ。
WAFはあくまで「外壁」に過ぎない。暗号化された通信や、複雑なエンコーディングを駆使したペイロードはすり抜けることがある。また、内部ネットワークからのアクセスや、アプリケーション内部のロジックに起因する脆弱性は防げない。
セキュリティは多層防御だ。
1. SAST: コードの欠陥を開発段階で潰す。
2. プリペアドステートメント: アプリ層でインジェクションを物理的に不可能にする。
3. WAF: 既知のシグネチャによる攻撃を水際でブロックする。
—
最後に:エンジニアとしての矜持
SASTを導入すると、最初は大量の警告が出るかもしれない。無視したくなるだろう。だが、その警告を一つずつ精査して潰していくプロセスこそが、君を「単なるコード書き」から「信頼されるエンジニア」へと引き上げる。
コードは嘘をつかない。君が書いたコードが、誰かの個人情報を守る盾にもなれば、攻撃者の道具にもなる。その責任を、ツールと技術でしっかりとコントロールしてほしい。
今日のコードを見返してくれ。文字列連結でSQLを作っている場所はないか? 明日のデプロイ前に、一度Semgrepを回してみることを強く勧める。健闘を祈る。
コメント