外部入力のフォーマット文字列への使用

外部入力のフォーマット文字列への使用

説明

ユーザー入力を util.format、console.log、sprintf などのフォーマット文字列に使うと、攻撃者が %s や %d などの指定子を入れ、後続の引数の解釈を変えることができます。セキュリティログや監査ログで、重要な値を隠したり歪めたりするために悪用される可能性があります。

想定される影響

  • 攻撃者がメッセージの構造を変え、監査証跡を歪めるおそれがあります。
  • 後続の引数が露出したり、意図しない意味で記録されたりする可能性があります。
  • セキュリティ監視が期待するログ形式を認識できなくなるおそれがあります。

対処方法

  • フォーマット文字列を定数にし、ユーザー入力は別の値引数として渡してください。
  • 入力をフォーマット文字列へ結合する必要がある場合は、そのAPIの書式規則に従って処理してください。可能なら結合自体を避けてください。
  • 構造化ログで、メッセージテンプレートとユーザー値を分離してください。

例

app、認証済みの req.user、%s 書式を扱える logger が用意されている前提の抜粋です。書式の固定は、秘密値のマスキングや改行などのログ内容の処理を代替しません。

変更前

javascript
const util = require("util");

app.get("/search", (req, res) => {
  logger.info(util.format(req.query.message, req.user.email));
  res.send("ok");
});

変更後

javascript
app.get("/search", (req, res) => {
  logger.info("search message=%s user=%s", req.query.message, req.user.email);
  res.send("ok");
});

解説:

  • 変更前: ユーザー入力がフォーマット文字列となり、後続の引数の解釈を変えられる可能性があります。
  • 変更後: 書式は固定され、ユーザー入力は値として渡されます。

参考資料