axiosのサプライチェーン攻撃とは
axiosのサプライチェーン攻撃とは、JavaScriptのHTTPクライアントライブラリ「axios」が配布経路(サプライチェーン)を通じて改ざんされ、悪意あるコードがユーザーに配布された事件のことを指します。
axiosをfetchに変更すれば完全に防げる
fetchとはJavaScript標準のHTTP通信APIで、サーバーと通信(GET / POST など)を行うための仕組みです。
npmのインストールやアップデートを行わないため、fetchならサプライチェーン攻撃のリスクがゼロになります。
axiosは便利ですが、単純にGETやPOSTなどでデータの取得や送信だけに使用しているケースでは、以下のようなコードを書けば、fetchで代替可能です。
const api = async (
method,
url,
{ params, body, headers, timeout = 30000 } = {}
) => {
const lowerMethod = method.toLowerCase()
const METHODS = [
'get',
'post',
'put',
'patch',
'delete',
'head',
'options'
]
if (!METHODS.includes(lowerMethod)) {
throw new Error(`Invalid method: ${method}`)
}
let fullUrl = url
if (params) {
const query = new URLSearchParams(params)
fullUrl += `?${query}`
}
const controller = new AbortController()
const timer = setTimeout(() => controller.abort(), timeout)
const config = {
method: lowerMethod.toUpperCase(),
signal: controller.signal,
headers: {
'Content-Type': 'application/json',
...(headers || {})
}
}
const hasBody = ['post', 'put', 'patch', 'delete'].includes(lowerMethod)
if (hasBody && body !== undefined) {
config.body = JSON.stringify(body)
}
try {
const response = await fetch(fullUrl, config)
if (!response.ok) {
const text = await response.text()
throw new Error(`HTTP ${response.status}: ${text}`)
}
if (lowerMethod === 'head') {
return {
ok: response.ok,
status: response.status,
headers: Object.fromEntries(response.headers.entries())
}
}
if (response.status === 204 || lowerMethod === 'options') {
return null
}
return await response.json()
} catch (error) {
if (error.name === 'AbortError') {
throw new Error(`Request timeout after ${timeout}ms`)
}
throw error
} finally {
clearTimeout(timer)
}
}
const result = await api('get', 'https://dummyjson.com/products/search', {
params: { q: 'phone', limit: 3 }
})
const phones = result.products.map((item) => item.title)
console.log(phones)
// [
// "Apple AirPods Max Silver",
// "Apple iPhone Charger",
// "Apple MagSafe Battery Pack"
// ]axiosに比べてコードは長く見えますが、API関数を別ファイルにexportし、importして使用すればコード量に大きな差はありません。
サンプルのコードはGETで書きましたが、POSTなども以下のように書けば使用できます。
import { api } from './api.ts'
// GET
await api('get', '/api/users', {
params: { page: 1 }
})
// POST
await api('post', '/api/users', {
body: { name: 'John' }
})
// PUT
await api('put', '/api/users/1', {
body: { name: 'Updated' }
})
// PATCH
await api('patch', '/api/users/1', {
body: { name: 'Partial Update' }
})
// DELETE
await api('delete', '/api/users/1')
// HEAD
const head = await api('head', '/api/users')
console.log(head.headers)
// OPTIONS
await api('options', '/api/users')ほとんどのプロジェクトではaxiosを使う必要がなく、fetchで十分なケースが多いため、セキュリティの向上のためにもaxiosを使用する必要性がなければ、fetchを使用することを推奨します。


