けーたうぇぶ

ITエンジニアの技術ネタや日々の生活のことを書き連ねます。

Node.js/PostgreSQLでSQLインジェクション対策を行う

こんにちは。
IPAの安全なウェブサイトの作り方を参考にセキュリティ面のお勉強をしているので、Node.js/PostgreSQLSQLインジェクション対策の簡単な実装を残したいと思います。

安全なウェブサイトの作り方 - 1.1 SQLインジェクション:IPA 独立行政法人 情報処理推進機構

SQLインジェクションとはなにか

データベースと連携したウェブアプリケーションの多くは、利用者からの入力情報を基にSQL文(データベースへの命令文)を組み立てています。ここで、SQL文の組み立て方法に問題がある場合、攻撃によってデータベースの不正利用をまねく可能性があります。このような問題を「SQLインジェクション脆弱性」と呼び、問題を悪用した攻撃を、「SQLインジェクション攻撃」と呼びます。 安全なSQLの呼び出し方 - Qiita

アプリに脆弱性があると悪意のある第三者によって意図しないSQLを実行される可能性があるようです。

どのような対策が必要か

いくつか方法があるようですが、静的プレースホルダを用いることで原理的に脆弱性の発生をなくすことができるようです。
私の運用中のウェブアプリを覗いてみたところ、知らないうちに静的プレースホルダを利用できていました。
でも対策方法について知らなかったら、どこかで脆弱性ありありのコードを書いてしまっていたかもしれません。。

Node.js/PostgreSQLでの対策例

Node.jsで pg ライブラリを使った例を記載します。
リクエストの処理は Express です。

// 店舗情報を取得するAPIの処理
router.get('/get/store', function(req, res) {
  const connection = sqlConnect(DB_CONNECTION)

  // 取得したい店舗のID
  const storeId = req.query.storeId

  // データベースにクエリ実行
  connection.query('SELECT * FROM store WHERE $1', [storeId], function (error, row) {
    const rows = row['rows']
    const isRecordExist = rows.length > 0
    if (isRecordExist) {
      const rowData = rows[0]
      console.log(rowData)
      const resData = {
        name           : rowData.name,
        detail         : rowData.detail,
        longitude      : rowData.longitude,
        latitude       : rowData.latitude,
        address        : rowData.address,
        officialSite   : rowData.official_site,
        businessHours  : rowData.open_hours
      }
      res.send(resData)
    } else {
      const resData = { responseStatus: 'FAILED' }
      res.send(resData)
    }
  })
})

connection.query('SELECT * FROM store WHERE $1', [storeId], function (error, row) となっているところが静的プレースホルダになっていて、'SELECT * FROM store WHERE $1'[storeId] は別々にデータベースに送信されたあとに、リテラル値( [storeId] )を評価し、データベース側でSQLをパースした上で最終的にSQLが実行されることになります。
具体的な使用方法は pg ライブラリのドキュメントで説明されています。

Parameterized query - node-postgres

静的プレースホルダを使用すれば根本的な脆弱性の対策になるようなので、これからは静的プレースホルダを使っていきたいと思います。