Axios 1.8 から導入された allowAbsoluteUrls の使い所と注意点

こんにちは、ARCH チームの立川です。

最近、Axios のリリースノートをチェックしていて 1.8.0 で Breaking Changes が入っていたので(ただし、メジャーバージョンが上がっているわけではない)、今回はその内容について書こうと思います。具体的には、 allowAbsoluteUrls というオプションが追加されたのでそちらに関する説明となります。allowAbsoluteUrls について触れている記事が見当たらなかったので、この記事が皆様のバージョンアップ対応の一助となれば幸いです。

github.com

allowAbsoluteUrls オプションの設定は、baseURL オプションを利用したリクエスト URL 指定について影響を及ぼします。まずは、1.7.9 での baseURL オプションを使用した例について見ていきます。

Axios は baseURL オプションを利用することによって、URL ドメインを共通で利用することができます。

import axios from "axios";

const client = axios.create({
  baseURL: "https://jsonplaceholder.typicode.com",
});
client
  .get("/posts/1")
  .then((response) => {
    console.log(response.data);
  })
  .catch((error) => {
    console.error(error);
  });

スタンダードな書き方なのでご存じの方が多いと思いますが、上記のコードを実行すると baseURL とリクエスト URL が結合して https://jsonplaceholder.typicode.com/posts/1 にアクセスされ、 response.data が出力されます。

では以下のように、 get で指定するリクエスト URL を絶対パスにするとどうなるでしょうか?

const client = axios.create({
  baseURL: "https://jsonplaceholder.typicode.com",
});
client
  .get("https://jsonplaceholder.typicode.com/posts/1") 
  .then((response) => {
    console.log(response.data);
  })
  .catch((error) => {
    console.error(error);
  });

一見、 https://jsonplaceholder.typicode.com/https://jsonplaceholder.typicode.com/posts/1 にアクセスされると思われがちですが、実際に実行してみると先ほどの例と同じ挙動となります。つまり、リクエスト URL に絶対パスを指定すると、 baseURL を指定していようが上書きされる ということです。リクエスト URL に https://example.com/ のようなドメインが異なる URL を指定した場合も、その URL で上書きされます。

先述した通り 1.8.0 以降、 allowAbsoluteUrls オプションが追加されました。
1.8.0 からパッチリリースでいくつか修正が入っているため、1.8 系の最新である 1.8.4 を使用して説明します。

allowAbsoluteUrls はデフォルトで true が設定されており、true の場合は 1.7.9 で見た例と同じ挙動になります。問題は false にしたときの場合でこちらについて詳しく見ていきましょう。

const client = axios.create({
  baseURL: "https://jsonplaceholder.typicode.com",
  allowAbsoluteUrls: false,
});
client
  .get("/posts/1")
  .then((response) => {
    console.log(response.data);
  })
  .catch((error) => {
    console.error(error);
  });

まず、上記の相対パスを指定した例では、 https://jsonplaceholder.typicode.com/posts/1 にアクセスされます。次に、リクエスト URL に絶対パスを指定した例です。

const client = axios.create({
  baseURL: "https://jsonplaceholder.typicode.com",
  allowAbsoluteUrls: false,
});
client
  .get("https://jsonplaceholder.typicode.com/posts/1") 
  .then((response) => {
    console.log(response.data);
  })
  .catch((error) => {
    console.error(error);
  });

こちらを実行すると、 エラーが発生します。内容としては https://jsonplaceholder.typicode.com/https://jsonplaceholder.typicode.com/posts/1 にアクセスされてしまい、404 エラーとなって返却されます。つまり、 allowAbsoluteUrlsfalse を指定することにより、 baseURL が指定したリクエスト URL で上書きされない仕様となりました

実例で見てきたように、従来の Axios (1.8.0 未満)では、 リクエスト URL に絶対パスが指定された場合は baseURL を無視して、そのリクエスト URL にアクセスする仕様でした。この仕様には問題があり、例えば、次の簡易な Webhooks を処理する場合を考えてみましょう。

import axios from "axios";
import express from "express";

const router = express.Router();


const axiosInstance = axios.create({
  baseURL: "http://internal-api.local/",
});


router.post("/webhook/handler", async (req, res) => {
  const data = req.body;
  const callbackUrl = data.callbackUrl;

  if (callbackUrl) {
    try {
      
      await axiosInstance.post(callbackUrl, { status: "success" });
      res.status(200).send("OK");
    } catch (error) {
      res.status(500).send("Internal Server Error");
    }
  }
});

この例では、リクエストで指定された callbackUrlhttp://internal-api.local/ ドメインのパスであることを前提としているように見えますが、 callbackUrl に絶対パスを指定された場合は baseURL が無視されます。これにより、悪意のあるユーザーがリクエストの callbackUrl に任意の URL を含めることでサーバーに対して様々な攻撃が可能となります。例えば、http://localhost/admin/delete_db のような URL を指定してサーバーの内部のリソースを不正に操作できてしまう可能性があります。

実装者が Axios に関して詳しければこのような問題は起きませんが、このような意図しない実装を防ぐために 1.8.0 以降では allowAbsoluteUrls オプションに false を指定することにより、このような攻撃を防ぐことができるようになりました。つまり、 想定外の SSRF (Server Side Request Forgery)攻撃を防ぐために取り入れられたものがこのオプション ということになります。

また、一方で Axios をクライアントサイドで利用する(フロントエンド開発で利用する)場合は、このオプションによるセキュリティ的恩恵はありません。しかし、 false 設定することにより、リクエスト URL は相対パス指定でなければならないという意図を開発組織のメンバーに明確に伝えることができます。

想定外の SSRF 攻撃対策として 1.8.0 から allowAbsoluteUrls オプションが導入されました。できれば、allowAbsoluteUrls オプションは今後 false にしておいた方が安全性は高くなるでしょう。

  • allowAbsoluteUrls が true の場合
    • allowAbsoluteUrls はデフォルトで true です
    • この場合、従来(1.8.0 未満)と baseURL オプション指定の挙動は変わりません
    • リクエスト URL が絶対パスの場合は baseURL は無視されるので注意しましょう
  • allowAbsoluteUrls が false の場合
    • リクエスト URL が相対パスの場合は従来(1.8.0 未満)と挙動は変わりません
    • リクエスト URL が絶対パスの場合でも相対パス扱いとなり、baseURL と結合されるので注意しましょう

先述した通り、1.8.0 からパッチバージョンで修正が入り、1.8 系の最新は現時点で 1.8.4 で、アップデートする場合はこのバージョンのインストールを推奨します。また、最近は Axios のマイナーバージョンアップの頻度が高く、現在は 1.11.0 が最新です(1.8.4 は今年の 5 月リリースしたばかりなのに…)。1.11 系まで上げられるのであればこの機会に上げてしまった方が良いと思います。




Source link

関連記事

コメント

この記事へのコメントはありません。