Gatsby(React)とXSS
Mar 28, 2021 17:40 · 1717 words · 4 minute read
最近「React & GatsbyJS開発入門」を見ながら、ReactとGatsbyを触っています。
React & GatsbyJS開発入門 - mottox2(つのぶえ出版) - BOOTH
Gatsbyでは、「外部サイトのRSS」や「HeadlessCMS」などからデータを取得し、取得したデータを組み込んだ静的サイトをビルドすることができます。
外部から受け取ったデータを使ってコンテンツを組み立てるとなると、試してみたくなるのがXSS(Cross-site Scripting)です。
ということで、GatsbyでXSSが発生するのか検証してみました。
目次
XSS(Cross-site Scripting)とは?
「外部から入力されたデータを使ってコンテンツを作成する」機能を悪用する攻撃手法です。
外部から「悪意のあるデータ」を入力された場合、Webアプリ上でスクリプトが実行されたり、表示内容が改ざんされてしまう可能性があります。
安全なウェブサイトの作り方 - 1.5 クロスサイト・スクリプティング
XSSについてもっと知りたい方は、安定の徳丸本がおすすめです。
検証内容
今回はGolangのHugoで生成されたRSSを、Gatsbyの「gatsby-source-rss-feed」というプラグインで読み込みます。
「外部から受け取ったスクリプトを使って作成したコンテンツ」でXSSが発生するか確認します。
全体像
環境構築
早速検証環境を作っていきます。
Hugo
まずはHugoの環境を作ります。
今回はanankeのThemeを使ってみました。
$ hugo new site hugo-malicious-site
$ cd hugo-malicious-site/
$ git init
$ git submodule add https://github.com/budparr/gohugo-theme-ananke.git themes/ananke
$ echo 'theme = "ananke"' >> config.toml
下記のコンテンツを作成しました。
$ hugo new sample-post.md
$ hugo new sample-post2.md
出来上がったindex.xmlです。
Gatsby
続いてGatsbyの環境を作ります。
$ npm init gatsby
$ npm run develop
Hello Gatsby!
HugoのRSSを読み込む処理を追加します。
プラグインを追加
$ npm install gatsby-source-rss-feed
gatsby-config.jsにプラグインの情報を追記
module.exports = {
siteMetadata: {
title: "Gatsby-XSS-Sample",
},
plugins: [
{
resolve: `gatsby-source-rss-feed`,
options: {
url: `http://localhost:1313/index.xml`,
name: `MaliciousSite`,
},
},
],
};
データが読み込めているか、GraphiQLで確認します。
$ npm run develop
Hugo側で設定したスクリプトを読み込めていることが確認できました。
読み込んだスクリプトを画面上に表示する処理を実装します。
今回は「/src/pages/index.js」で下記のように読み込みました。
import * as React from "react";
import { graphql } from "gatsby";
const LinkItem = (props) => {
const { title, link } = props.post;
return (
<li>
<a href={link}>{title}</a>
</li>
);
};
const IndexPage = (props) => {
return (
<ul>
{props.data.allFeedMaliciousSite.nodes.map((post) => {
return <LinkItem post={post} key={post.link} />;
})}
</ul>
);
};
export const query = graphql `
query MyQuery {
allFeedMaliciousSite {
nodes {
title
link
}
}
}
`;
export default IndexPage;
検証環境情報
検証実施時点の環境情報はこちら。
"dependencies": {
"gatsby": "^3.1.2",
"gatsby-source-rss-feed": "^1.2.2",
"react": "^17.0.1",
"react-dom": "^17.0.1"
}
検証結果
それではいよいよ検証です。
$ npm run develop
で開発サーバを起動し、ブラウザから表示内容を確認します。
確認した結果がこちら。
Hugoから読み込んだスクリプトは実行されませんでした。
Gatsbyの公式ドキュメントによると、JSXに含まれるHTMLタグは自動でエスケープ処理されます。
ただし、外部から受け取ったデータを扱う場合には気をつけないといけないパターンもあるようです。
- aタグのhref属性に「javascript:」から始まる文字列でスクリプトを渡した場合
- dangerouslySetInnerHTMLを使った場合
どうしてもこのような処理をする必要がある場合、公式ドキュメントでは「sanitize-html」や「DOMPurify」を使うことを薦めています。
まとめ
Gatsbyを利用する場合、「href属性」と「dangerouslySetInnerHTML」に気をつければXSSが発生する可能性は低そう。
(まだ発見されていない攻撃パターンが存在する可能性もあるので、”低そう”としています。)