Skip to main content

Node.jsのセキュリティスキャンAPIを構築し、Platformatic Cloudにデプロイする

著者
Headshot of Matteo Collina

Matteo Collina

feature platformic security

2024年1月5日

0 分で読めます

このガイドでは、PlatformaticとFastifyを組み合わせ、堅牢性とセキュリティを重視しながらバックエンドを迅速に開発する方法を紹介します。

Node.jsの経験豊富な開発者にも、これから始める方にも、この記事はPlatformaticなどのNode.js PaaS環境への理解を深めるのに役立ちます。Snykをワークフローにシームレスに統合して、コードに脆弱性やシークレットの漏えいがない状態を保つ方法と、Snyk APIを使ってセキュリティアプリケーションを構築する方法を解説します。

Platformaticとは何ですか?

Platformaticは、Node.jsでのAPIやバックエンドの構築・管理を効率化するクラウドホスティングプラットフォームです。Platformaticを使えば、ルーティング、データベース連携、認証などのタスクを簡素化するさまざまなツールや機能を活用して、開発者はスケーラブルで効率的なAPIを簡単に作成できます。Fastifyとの連携により、パフォーマンスと開発者エクスペリエンスがさらに向上します。

Fastifyとは?

Fastifyは、高いパフォーマンスと低いオーバーヘッドで知られる、Node.js向けのモダンなオープンソースWebフレームワークです。Expressを使った経験がある方なら、Fastifyに組み込まれた開発者体験や、軽量でありながら高機能な点に魅力を感じるでしょう。速度と効率を重視したFastifyは、シンプルで直感的なAPI、簡単なリクエストとレスポンスの処理に加え、スキーマベースのバリデーションとシリアライズを標準でサポートしています。

Platformaticは、包括的なツール一式を統合されたパッケージとして提供することで、Node.js開発者がバックエンドインフラストラクチャの細部に煩わされることなく、アプリケーションの中核機能の開発に集中できるようにします。

Platformatic serviceでNode.jsアプリケーションのひな形を作成する

まず、Node.jsアプリケーションを配置する新しいディレクトリを作成します。

mkdir pkg-probe

次に、以下のnpmコマンドを実行してPlatformaticプロジェクトジェネレーターをインストールします。

npm create platformatic@latest

このコマンドを実行すると、最新バージョンのplatformatic npmパッケージをダウンロードするか確認されます。

Need to install the following packages:
create-platformatic@1.11.0
Ok to proceed? (y) y

続いて、以下のプロンプトに回答し、新しいNode.js APIサービスのひな形を作成します。

 Hello Liran Tal, welcome to Platformatic 1.11.0!
 Let's start by creating a new project.
? Which kind of project do you want to create? Service
? Where would you like to create your project? platformatic-service
? Do you want to run npm install? yes
? Do you want to use TypeScript? no
? What port do you want to use? 3042
? Do you want to create the github action to deploy this application to Platformatic Cloud? yes
? Do you want to enable PR Previews in your application? yes
? Do you want to init the git repository? no

これで、platformatic-serviceディレクトリにPlatformatic serviceプロジェクトが作成されます。プレーンなJavaScriptを使用し、GitHub Actionsとの統合に加えて、各PRでサービスの不変のスナップショットを提供するPlatformaticの連携型PRレビュー機能も備えています。

ディレクトリとファイルの構成は、次のようになります。

.
└── platformatic-service
    ├── README.md
    ├── global.d.ts
    ├── node_modules
    ├── package-lock.json
    ├── package.json
    ├── platformatic.service.json
    ├── plugins
    ├── routes
    └── test

5 directories, 5 files

Node.js Platformatic serviceを起動する

生成されたPlatformatic serviceは、起動できる状態になっています。アプリを起動しましょう。まず、ディレクトリを変更します。

cd platformatic-service

次に、以下を実行します。

npm run start

lirantal  …/repos/pkg-probe/platformatic-service   v20.8.0 
♥ npm run start

> start
> platformatic start

[12:56:12.555] INFO (main/75676): Server listening at http://127.0.0.1:3042

生成されたNode.jsアプリケーションが起動し、ポート3042でHTTPリクエストを受け付けるようになりました。デフォルトのGET /エンドポイントでは、次の入門ガイドが表示されます。

ドキュメント、OpenAPIドキュメント、GraphiQLへのリンクが表示されたPlatformatic Serviceのウェルカムページ。

このインデックスページは、Platformatic CLIによって提供されるもので、ローカル開発専用です。Node.jsアプリケーションサービスとともにデプロイされる、クライアント側のブラウザーコードには含まれません。

Platformatic serviceを詳しく見る

このNode.jsアプリケーションの仕組みをさらに理解するため、Platformaticの設定とディレクトリ構成を詳しく見ていきましょう。

platformatic.service.jsonでは、HTTPリクエストを待ち受けるポートや、読み込むプラグイン、ルート(これもプラグインとして定義)など、デプロイするPlatformatic service全体の設定を定義します。生成されたサービス設定ファイルは次のとおりです。

{
  "$schema": "https://platformatic.dev/schemas/v1.11.0/service",
  "service": {
    "openapi": true
  },
  "watch": true,
  "plugins": {
    "paths": [
      {
        "path": "./plugins",
        "encapsulate": false
      },
      "./routes"
    ]
  },
  "server": {
    "hostname": "{PLT_SERVER_HOSTNAME}",
    "port": "{PORT}",
    "logger": {
      "level": "{PLT_SERVER_LOGGER_LEVEL}"
    }
  }
}

上記の設定では、pluginsに./routesが含まれており、APIルートを読み込むディレクトリを指定しています。

HTTPルートはroutes/root.jsファイルで定義されています。標準で用意されているサンプルでは、パスパラメーター/exampleに次のGETエンドポイントが設定されています。

/// <reference path="../global.d.ts" />
'use strict'

/** @param {import('fastify').FastifyInstance} fastify */
module.exports = async function (fastify, opts) {
  fastify.get('/example', async (request, reply) => {
    return { hello: fastify.example }
  })
}

次のHTTPリクエストをGET /exampleに送信して、動作を確認しましょう。

 curl http://localhost:3042/example -vvv  
*   Trying 127.0.0.1:3042...
* Connected to localhost (127.0.0.1) port 3042 (#0)
> GET /example HTTP/1.1
> Host: localhost:3042
> User-Agent: curl/8.1.2
> Accept: */*
> 

< HTTP/1.1 200 OK
< content-type: application/json; charset=utf-8
< content-length: 18
< Date: Thu, 16 Nov 2023 11:24:41 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
< 
* Connection #0 to host localhost left intact
{"hello":"foobar"}%   

npmパッケージのセキュリティ脆弱性をテストする新しいルートを追加する

次に、ユーザーがパッケージ名とバージョンを入力すると、既知のセキュリティ脆弱性がないか検査できる機能を、Node.js APIに追加しましょう。

このチュートリアルのセクションで行う作業は次のとおりです。

  • Snyk CLIをインストールしてセットアップする

  • Snyk APIトークンを取得する

  • APIトークンを使ってSnyk APIにHTTPリクエストを送信する

  • Node.js Platformatic serviceに新しいPOST /test/vulnerabilities APIエンドポイントを定義する

Snyk CLIをインストールしてセットアップし、APIトークンを取得する

Snyk CLIの利用は、npmパッケージをインストールするだけですぐに始められます。

npm install -g snyk

Snykをnpmのグローバルパッケージとしてインストールすると、開発中のJavaScriptプロジェクトのコードやセキュリティに関するさまざまな項目をテストできるので便利です。さらに、SnykはPython、Java、Ruby、PHPなどの言語のコードや依存関係もテストできます。

次に、パッケージの脆弱性をAPIで照会できるよう、無料のSnykユーザーを作成します。次のコマンドを実行してください。

snyk auth

CLIの手順に従ってください。完了したら、snyk configコマンドを実行してAPIトークンを取得できます。このコマンドはAPI設定キーを返します。

snyk config

api: <YOUR_API_TOKEN_HERE>

APIトークンは、すぐ使えるよう手元に保存しておきましょう(誤ってインターネット上に漏えいしないよう十分注意してください)。

これで、コードと依存関係のセキュリティ脆弱性をテストする準備ができました。この機会に、Node.js Platformatic Serviceアプリケーションもテストしてみましょう。

lirantal  …/pkg-probe/platformatic-service   main !   v20.8.0 
♥  snyk test   

Testing ~/repos/pkg-probe/platformatic-service...

Organization:      snyk-demo-567
Package manager:   npm
Target file:       package-lock.json
Project name:      package.json
Open source:       no
Project path:      ~/repos/pkg-probe/platformatic-service
Licenses:          enabled

✔ Tested 500 dependencies for known issues, no vulnerable paths found.

Next steps:
- Run `snyk monitor` to be notified about new related vulnerabilities.
- Run `snyk test` as part of your CI/test.

脆弱性ゼロのプロジェクトツールをリリースしたPlatformaticチームに拍手を送りましょう。

Snyk CLIの使用方法について詳しくは、Snyk User Docsと、便利なSnyk CLI Cheat Sheetをご覧ください。

POST /test/vulnerabilities Node.js APIエンドポイントを定義する

routes/root.jsファイルを開き、既存のfastify.get()コードの直後に、新しいFastify APIルートの宣言を追加します。

  fastify.post("/test/vulnerabilities", async (request, reply) => {
    const packageName = request.query.packageName;
    const packageVersion = request.query.packageVersion;

    const snykApiToken = "12345”
    const url = `https://snyk.io/api/v1/test/npm/${packageName}/${packageVersion}`;

    const response = await fetch(url, {
      headers: {
        Authorization: `token ${snykApiToken}`,
      },
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const data = await response.json();
    return { vulnerabilities: data.issues?.vulnerabilities };
  });

このコードでは、Snyk v1 APIエンドポイントを使用してnpmパッケージの脆弱性をチェックするAPIエンドポイントを設定します。各部分を順に見ていきましょう。

まず、Fastifyのルート作成です。

fastify.post("/test/vulnerabilities", async (request, reply) => {...});

この行は、/test/vulnerabilitiesに新しいPOSTエンドポイントを作成します。ここでは、高速かつ軽量なNode.js向けWebフレームワークであるFastifyを使用しています。asyncキーワードは、この関数が非同期処理を実行できることを示します。

次に、HTTPリクエストからクエリパラメーターを取り出します。

const packageName = request.query.packageName;
const packageVersion = request.query.packageVersion;

これらのパラメーターで、ユーザーが脆弱性をチェックしたいnpmパッケージとそのバージョンを指定します。

次の部分でSnyk APIと連携します。

const snykApiToken = "12345";
const url = `https://snyk.io/api/v1/test/npm/${packageName}/${packageVersion}`;
const response = await fetch(url, { headers: { Authorization: `token ${snykApiToken}` } });

パッケージ名と明示的なバージョン番号を使って、Snyk APIエンドポイントのURLを組み立てます(タグは使用できないため、「latest」はサポートされません)。次に、リクエストヘッダーに認証トークンを指定し、Snyk APIに非同期でfetchリクエストを送信します。これはsnyk configコマンドで取得したAPIトークンです。

最後に、指定したnpmパッケージで見つかった脆弱性をエンドポイントから返します。レスポンスに問題が含まれないケースに対応するため、オプショナルチェーン演算子(?.)を使用しています。

return { vulnerabilities: data.issues?.vulnerabilities };

最後に、リクエストとレスポンスのスキーマを定義すれば、POST /test/vulnerabilitiesエンドポイントのFastifyルート定義をさらに改善できます。入力検証を追加できるほか、OpenAPIのAPIルートドキュメントにも自動的に反映されます。Platformatic DBでREST APIを構築する方法については、Platformatic movie app tutorialとSimon Plenderleith blog postを参考にしてください。

APIキーなどの機密情報を漏えいさせないよう注意してください。


APIトークンをコードに直接書き込んでいたことに気付きましたか?これは絶対に避けるべきことです。

もちろん見落としてはいません。VS Code IDEにSnyk拡張機能をインストールしているので、シークレット検出が自動的に有効になり、自分のコードにセキュリティ脆弱性を招く可能性のある問題があれば警告してくれます。

ハードコードされたSnyk APIトークンが強調表示された、Node.jsのルートを示すコードエディター。

VS Code IDEからSnyk拡張機能を直接インストールするか、詳しくはVS Code MarketplaceのSnyk extensionsをご覧ください。

では、シークレット検出のアラートを受けて、認証情報の漏えいを修正しましょう。まず、.envに新しい環境変数を定義し、「1234」を自分のSnyk APIトークンに置き換えます。

PLT_SNYK_API_TOKEN=1234

次に、platformatic.service.json設定ファイルで、配列内にある既存の./routes文字列キーを、optionsキーを受け取るオブジェクトに変更して追加します。

{
  …
  "plugins": {
    "paths": [
      {
        "path": "./plugins",
        "encapsulate": false
      },
     {
        "path": "./routes",
        "options": {
           "snykApiToken": "{PLT_SNYK_API_TOKEN}"
       }
     }
    ]
  },
  …
}
module.exports = async function (fastify, opts) {

    const snykApiToken = opts.snykApiToken;
    const url = `https://snyk.io/api/v1/test/npm/${packageName}/${packageVersion}`;

npm run startを使ってNode.js Platformatic Serviceを実行している場合、このコマンドを再実行する必要はありません。自動再読み込みに対応しているため、ルートやプラグインファイルを保存するたびにサーバーコードが更新されます。

新しいNode.js API serviceを使ってnpmパッケージのセキュリティ脆弱性をテストする

SnykとNode.js Platformatic API Serviceの連携ができたので、すべてが正しく動作することを確認しましょう。

信頼できないコードを実行する際にセキュリティサンドボックスとして使う開発者もいるvm2 npmパッケージの最新版が安全かどうかをテストしてみましょう。

次のHTTPリクエストでは、パッケージ名とnpmjsレジストリに登録されている最新バージョンを指定し、結果をjqツールに渡して整形済みのJSONレスポンスを表示します。

curl -X POST "http://localhost:3042/test/vulnerabilities?packageName=vm2&packageVersion=3.9.19" | jq 

{
  "vulnerabilities": [
    {
      "id": "SNYK-JS-VM2-5772823",
      "url": "https://snyk.io/vuln/SNYK-JS-VM2-5772823",
      "title": "Remote Code Execution (RCE)",
      "type": "vuln",
      "description": "## Overview\n[vm2](https://github.com/patriksimek/vm2#readme) is a sandbox that can run untrusted code with whitelisted Node's built-in modules.\n\nAffected versions of this package are vulnerable to Remote Code Execution (RCE) due to insufficient checks which allow an attacker to escape the sandbox.\r\n\r\n**Note:**\r\n\r\nAccording to the maintainer, the security issue cannot be properly addressed and the library will be discontinued.\n## Remediation\nThere is no fixed version for `vm2`.\n## References\n- [GitHub Issue](https://github.com/patriksimek/vm2/issues/533)\n",
      "from": [
        "vm2@3.9.19"
      ],
      "package": "vm2",
      "version": "3.9.19",
      "severity": "critical",
      "exploitMaturity": "proof-of-concept",
      "language": "js",
      "packageManager": "npm",
      "semver": {
        "vulnerable": [
          "*"
        ]
      },
      "publicationTime": "2023-07-12T14:50:43.988574Z",
      "disclosureTime": "2023-07-12T14:10:56Z",
      "isUpgradable": false,
      "isPatchable": false,
      "isPinnable": false,
      "identifiers": {
        "CVE": [
          "CVE-2023-37903"
        ],

動作しましたね。SnykとPlatformaticを使って初めてのセキュリティツールを構築できました。おめでとうございます。

引き続き、このWebアプリケーションのフロントエンドを構築し、Node.js APIをPlatformatic Cloudにデプロイしましょう。

セキュリティ脆弱性をスキャンするVueフロントエンドアプリケーション

このセクションでは、Platformatic serviceで構築したNode.jsバックエンドAPIと通信するフロントエンドWebアプリケーションの基本要素を確認します。

npmパッケージのセキュリティスキャナー。vm2のバージョン3.9.19と、2件のリモートコード実行の脆弱性レポートを表示

フロントエンドWebアプリケーションは、次の要素で構成されています。

  • Vue.js 3 + Viteのクライアントサイドフロントエンド

  • Tailwind CSS

フロントエンドは、パッケージ名とバージョンを入力するテキストフィールドを備えたシンプルなフォームで、入力内容はNode.js Platformatic APIに送信されます。

以下は、ローカルで実行中のlocalhost:3042のNode.js serviceと通信する、シンプルなVue.jsフォームです。

<script setup>
import { ref } from "vue";

const processing = ref(false);
const packageName = ref("vm2");
const packageVersion = ref("3.9.19");
const vulnerabilities = ref([]);

async function scanPackage() {
  processing.value = true;

  const BASE_URL = "http://localhost:3042";
  const httpResponseRaw = await fetch(
    `${BASE_URL}/test/vulnerabilities?packageName=${packageName.value}&packageVersion=${packageVersion.value}`,
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({}),
    }
  );

  const httpResponse = await httpResponseRaw.json();
  vulnerabilities.value = httpResponse.vulnerabilities;

  processing.value = false;
}
</script>

フロントエンドWebアプリケーションのコード全文は、こちらのGitHubリポジトリをご覧ください。https://github.com/lirantal/pkg-probe

Node.jsバックエンドAPIをPlatformatic Cloudにデプロイする

Platformatic Cloudは、Node.jsアプリケーションのホスティングに最適な、特化型のPaaS(Platform as a Service)です。Platformaticの優れたツールに加えて、同社のクラウド環境を使ってセキュリティスキャンWebアプリケーションをホストし、インターネットからアクセスできるようになりました。

ランディングページでConnect with GitHubボタンを使ってサインインし、GitHubアプリの連携を承認して、利用規約とプライバシーポリシーに同意します。これで、ダッシュボードのCreate an appをクリックする準備ができました。

組織とリポジトリのドロップダウン、[次へ]ボタンが表示された、GitHubリポジトリのステップのPlatformaticインポート画面

このデフォルトのワークフローでは、新しいPlatformaticサンプルアプリケーションが作成されます。しかし、すでにアプリケーションがあるので、ここに表示される手順画面の下部にあるDo it manuallyリンクをクリックしてください。

次に、アプリケーション名とワークスペース名を設定します。現時点ではCLIからNode.jsアプリケーションをデプロイするために自動PRレビューは必要ないので、Dynamic Workspaceはオフのままにしてください。

次のようなPlatformaticの概要画面が表示されます。

「pkg-probe」が正常に作成されたことを示すワークスペース設定画面。ワークスペースIDとAPIキーの欄はマスクされています。

ワークスペースIDとAPIキーが取得できたので、それらを使ってNode.jsバックエンドアプリケーションをPlatformatic Cloudのホスティング環境にデプロイできます。

ワークスペースIDとAPIキーを用意したら、プロジェクトのplatformatic-serviceディレクトリに移動して、Node.js APIのソースコードからnpmライフサイクルコマンドを実行します。次のnpm run deployコマンドを実行し、Platformatic Cloudのワークスペース情報を入力してください。

$  npm run deploy

This application will be deployed to Platformatic Cloud. To change the target use the --deploy-service-host flag
? Select workspace type: static
? Enter workspace id: 09d9a354-b755-40da-b4ab-841a43d8c074
? Enter workspace key: ********************************
[13:41:52] INFO: Found Platformatic config file: platformatic.service.json
[13:41:54] INFO: Project has been successfully archived
[13:41:55] INFO: Uploading bundle (95.9 MB) to the cloud…
…
[13:42:52] INFO: Application has been successfully started

コマンドの実行が完了すると、Node.js APIのデプロイ先URLも表示されます。たとえば、次のようなURLです。https://something-something-funny.deploy.space

Platformatic Cloudのダッシュボード(https://platformatic.cloud)に戻ると、新しいセキュリティスキャンアプリケーションが作成されていることを確認できます。

濃い青色のアプリダッシュボード。「アプリを作成」タイルと、既存の「pkg-probe」アプリタイルが表示されています。

アプリケーションを開くと、パフォーマンス指標などのリアルタイムのステータスや、アプリケーションにアクセスするための公開URLを確認できます。

アクティブなpkg-probeのデプロイ、最新バンドルの詳細、リクエスト数、レイテンシ、接続中のクライアント数、失敗率の指標を表示するPlatformのワークスペースダッシュボード。

最後に、Platformaticを利用するNode.js APIで必要な設定が1つ残っています。CORSを有効にしましょう。

CORSとは何ですか?

クロスオリジンリソース共有(CORS)は、異なるオリジン間でリソースを共有する方法を管理するために、Webブラウザに実装されているセキュリティ機能です。オリジンとは通常、異なるドメイン、プロトコル、ポートを指します。バックエンドアプリケーションにおいてCORSは、サーバーのデータを別のオリジンのWebページと共有できるかどうか、また共有する場合はどのように共有するかを制御する重要な機能です。CORSがなければ、APIやその他のクロスオリジンリソースに依存する最新のWebアプリケーションは、深刻な制約に直面することになります。

CORSが重要なのはなぜですか?

このポリシーにより、Webページがそのページを配信したドメイン以外にリクエストを送信できなくなり、クロスサイトスクリプティング(XSS)攻撃など、特定の種類のサイバーセキュリティ脅威を防ぎます。一方、CORSでは、サーバー上のリソースへのアクセスを許可するドメインを指定することで、安全かつ制御されたアクセスを実現できます。これにより、複数のオリジンのリソースと安全に連携する、リッチでインタラクティブなWebアプリケーションを開発できます。

Node.js APIにCORS設定を追加しましょう。.envファイルを開いて、次のPlatformatic CORS設定を追加します。

PLT_SERVER_CORS_ORIGIN=http://localhost:5173

この設定例では、localhostで実行されているVue.jsのローカル開発サーバーのポートが指定されています。フロントエンドをNetlifyやVercelなどのクラウドホスティング環境にデプロイする場合は、それに合わせて設定してください。

次に、platformatic.service.jsonのserver設定ディレクティブを更新し、以下も含めます。

  "server": {
    "hostname": "{PLT_SERVER_HOSTNAME}",
     // other configuration options…
     // add CORS too:
    "cors": {
      "origin": "{PLT_SERVER_CORS_ORIGIN}"
    }
 }

成功

これで完了です!

これで、Snyk APIを使ってセキュリティの脆弱性をスキャンするNode.js Webアプリケーションを構築し、Platformatic Cloudのホスティング環境にデプロイして一般公開できました。

JavaScriptアプリのセキュリティ対策を始めましょう

Snykを無料で利用して、JavaScriptの脆弱性を検出・修正しましょう。

クレジットカードは不要です。

またはAzure AD Docker ID Bitbucketで登録

Snykを利用することで、利用規約およびプライバシーポリシーを含む当社の各種ポリシーに同意したものとみなされます。

続きを読む

Blog

フロンティアモデルは脆弱性を発見した。攻撃者だけがエクスプロイトチェーンを見つけた。

静的解析で欠陥は見つかりましたが、ライブ攻撃テストで侵害につながる連鎖を実証できたのは唯一でした。Evo COS、Claude Security、Claude Code Securityを比較します。

feature insights context
Blog

自律型攻撃はすでに始まっている。防御もそのスピードに追いつかなければならない。

自律型攻撃者によって、防御に使える時間は短くなっています。継続的な検出、修復、検証、予防で、セキュリティチームが攻撃に歩調を合わせる方法をご紹介します。

Blog

AIコーディングエージェントが不適切なアクセス制御を繰り返し実装する理由

AIコーディングエージェントは、コンパイルが通りレビューも通過する一方で、あるテナントのデータを別のテナントに公開してしまう認可ロジックを生成することがあります。不適切なアクセス制御が検出しにくい理由と、その防止策をご紹介します。