土日の勉強ノート

AI、機械学習、最適化、Pythonなどについて、技術調査、技術書の理解した内容、ソフトウェア/ツール作成について書いていきます

Vue.jsのソースコードを確認する(ビルド後のソースも見てみる)

ハッキング・ラボのつくりかた 完全版 仮想環境におけるハッカー体験学習」と「体系的に学ぶ 安全なWebアプリケーションの作り方 第2版 脆弱性が生まれる原理と対策の実践」(通称:徳丸本)を参考に、セキュリティの勉強を進めています。

その上で必要な知識として、今回は、よく使われている Webアプリケーションのフレームワークである Vue.js を理解しています。

前回 は、Vue 2.x と Vue 3.x について、環境構築、プロジェクト作成、開発用サーバで動作確認、ビルド、ビルド後の生成物で動作確認まで行いました。

今回は、ファイル構成、各種ソースコードの内容の確認、ビルド後の生成物の内容を確認していきたいと思います。

それでは、やっていきます。

参考文献

はじめに

「セキュリティ」の記事一覧です。良かったら参考にしてください。

セキュリティの記事一覧

Vue.js とは、Webアプリケーションを構築するときに、特に UI(ユーザインタフェース)を得意としたフレームワークです。

Vue.js の公式サイトは以下です。日本語で書かれています。

ja.vuejs.org

Vue CLI の公式サイトは以下です。

cli.vuejs.org

使用する環境は、VirtualBox+Ubuntu 22.04 です。

各種ツールのバージョンです。

$ node -v
v20.13.1
$ npm -v
10.8.0
$ vue -V
@vue/cli 5.0.8

Vue 2.x の構成とビルド前のソースコード

前回作成した helloプロジェクトのビルド後の構成です。

ざっくり言うと、src 以下のソースコードを変更、追加して、public と src 以下を対象としてビルドすると、dist 以下が生成されて、最終的には dist 以下の生成物を使用します。

node_modules は、ライブラリ(パッケージ、モジュール)のようなもので、追加でインストールすると、ここに追加されていきます。かなりのファイル数ですが、中を見ることは、ほとんどないと思います。

トップにある各ファイルは、設定ファイルなどです。

tree -L 3
.
|-- README.md
|-- babel.config.js
|-- dist
|   |-- css
|   |   `-- app.2cf79ad6.css
|   |-- favicon.ico
|   |-- index.html
|   `-- js
|       |-- app.35ff291d.js
|       |-- app.35ff291d.js.map
|       |-- chunk-vendors.27e771c3.js
|       `-- chunk-vendors.27e771c3.js.map
|-- jsconfig.json
|-- node_modules
|   |-- (省略)
|-- package-lock.json
|-- package.json
|-- public
|   |-- favicon.ico
|   `-- index.html
|-- src
|   |-- App.vue
|   |-- assets
|   |   `-- logo.png
|   |-- components
|   |   `-- HelloWorld.vue
|   `-- main.js
`-- vue.config.js

1328 directories, 3505 files

前回は、public/index.html の内容だけ確認しました。<div id="app"></div> のところが、Vue.js で作ったものと置き換えられるところです。

src/main.js

src/main.js を見てみます。

vue モジュールから Vue をインポート、./App.vue から App をインポートしています。

Vue.config.productionTip = false は、true にすると、Webサーバで起動時に、ヒントが出力されるようです。

最後のところは、Vue のインスタンスを生成しています。#app が、public/index.html の id="app" を指定しているところです。

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')

src/App.vue

インポートしている vue はフレームワークの中にありますので、./App.vue を見ていきます。

<template> 内は、index.html に反映される HTML の記述で、<script> 内は JavaScript の記述で、<style> は CSS の記述です。1つのファイルに HTML に必要なものが全て入ってるところが Vue.js の特徴のようです。見やすいですし、管理しやすいですね。

HTML に、HelloWorld というコンポーネントタグが使われています。

JavaScript に、HelloWorld コンポーネントタグの実体を読み込んでいる箇所があります。

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  components: {
    HelloWorld
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

src/components/HelloWorld.vue

続いて、HelloWorld.vue です。

少し長いですが、HTML部分はブラウザに表示されていた内容で、{{ msg }} 以外は普通の HTML です。

JavaScript では、上の {{ msg }} に反映するための文字列(HelloWorld)を作っています。

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <p>
      For a guide and recipes on how to configure / customize this project,<br>
      check out the
      <a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
    </p>
    <h3>Installed CLI Plugins</h3>
    <ul>
      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
    </ul>
    <h3>Essential Links</h3>
    <ul>
      <li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
      <li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
      <li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
      <li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
      <li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
    </ul>
    <h3>Ecosystem</h3>
    <ul>
      <li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
      <li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
      <li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
      <li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
      <li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
    </ul>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
  margin: 40px 0 0;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

こういうソースコードをベースにして、フロントエンド開発では、Vue.js の各種パーツを追加して、見栄えのいい Webアプリケーションを作っていくんだと思います。

Vue 2.x ビルド後のソースコード

実際に、Vue.js で作られた Webアプリケーションが使われるときは、先ほどの xxx.vue のファイルではなく、ビルド後のソースコードが使われます。

よって、Webアプリケーションをハッキングするときは、このビルド後のソースコードを見ることになります。

distディレクトリには 7ファイルありますが、index.html、favicon.ico、css は割愛します。

js ディレクトリには、2つの JavaScriptファイルと、対応する 2つの mapファイルがあります。この mapファイルとは、SourceMap と言って、ブラウザでデバッグするときに必要になるものらしいです。

以下は、この SourceMap を jsディレクトリに配置したまま、Webサーバを起動したときのキャプチャです。distディレクトリには main.js などは無いはずなのに、ソースコードが見えてますね。

SourceMapを配置したときのブラウザの開発ツール
SourceMapを配置したときのブラウザの開発ツール

一方、SourceMap を jsディレクトリから削除した場合の同じ状況のキャプチャです。これが本番環境の状況だと思います。2つの JavaScriptファイルのみです。

SourceMapが無い場合のブラウザの開発ツール
SourceMapが無い場合のブラウザの開発ツール

app.6a7bde24.js

2つの JavaScriptファイルのうち、この app.xxx.js は、ユーザが作成した xxx.vue から構築された JavaScript だと思います。

もう1つの chunk-vendors.xxx.js は、Vue.js のライブラリから構築されたものだと思います。

これらをエディタで開くと、圧縮というか、空白、改行が削除された状態なので、とても読みにくいです。なので、VSCode を使って、ソースコードを整形します。

拡張機能の Prettier というツールを入れると、ソースコードを全選択→右クリック→ドキュメントのフォーマットをクリックすると、読みやすく整形してくれます。

整形したソースコードと言っても、普通に見たら、全く分かりません(笑)。chunk-vendors.xxx.js は、絶対無理な感じなので、app.xxx.js を諦めたら終了です。

ブラウザの開発ツールでデバッグできるので、無理やり読んでみようと思います。ソースコードをここに貼りにくいので、記事の最後に貼ります。

まず、全体の構成を把握します。

最初から理解できませんが、今使ってる参考書の「改訂3版JavaScript本格入門 ~モダンスタイルによる基礎から現場での応用まで」によると、app.6a7bde24.js は、全体で1つの即時関数で出来ているということだと思います。

末尾に、(); があるので、定義した関数を実行しているということだと思います。

実行される順番は、まず、5個の即時関数が並んだところが実行されて、var n のところ、n = のところ、という順番だと思います。

5個の即時関数のところは、おそらく、事前準備のような感じだと思います。完全に予想ですけど、デバッガでステップ実行してても、あまり、意味のあるようなことはしてなかったので。

(function () {
  "use strict";
  var t = {
    723(t, e, r){
    (省略)
    },
    153(t){
    (省略)
    },
  },
  e = {};
  function r(n) {
  (省略)
  }
  (r.m = t), (function() {
  (省略)
  }(), (function() {
  (省略)
  }(), (function() {
  (省略)
  }(), (function() {
  (省略)
  }(), (function() {
  (省略)
  })();
  var n = r.O(void 0, [504], function() {
    return r(723);
  });
  n = r.O(n);
})();

デバッガでしばらくステップ実行してましたが、今の JavaScript の文法の理解度では、意味を読み取るのは難しかったです。もう少し文法を理解してから再挑戦したいと思います。

おわりに

今回は、Vue.js のソースコードを確認しました。JavaScript にまだ慣れてなくて、ビルド後のソースコードを読むのは難しかったです。

JavaScript は、公式のロゴが存在しないらしいという情報が見つかりました。公式ではないですが、よく見るやつを、ありがたく使わせていただきます。

最後になりましたが、エンジニアグループのランキングに参加中です。

気楽にポチッとよろしくお願いいたします🙇

今回は以上です!

最後までお読みいただき、ありがとうございました。

付録:app.6a7bde24.jsの全文

(function () {
  "use strict";
  var t = {
      723: function (t, e, r) {
        var n = r(471),
          l = function () {
            var t = this,
              e = t._self._c;
            return e(
              "div",
              {
                attrs: {
                  id: "app",
                },
              },
              [
                e("img", {
                  attrs: {
                    alt: "Vue logo",
                    src: r(153),
                  },
                }),
                e("HelloWorld", {
                  attrs: {
                    msg: "Welcome to Your Vue.js App",
                  },
                }),
              ],
              1
            );
          },
          o = [],
          i = function () {
            var t = this,
              e = t._self._c;
            return e(
              "div",
              {
                staticClass: "hello",
              },
              [
                e("h1", [t._v(t._s(t.msg))]),
                t._m(0),
                e("h3", [t._v("Installed CLI Plugins")]),
                t._m(1),
                e("h3", [t._v("Essential Links")]),
                t._m(2),
                e("h3", [t._v("Ecosystem")]),
                t._m(3),
              ]
            );
          },
          s = [
            function () {
              var t = this,
                e = t._self._c;
              return e("p", [
                t._v(
                  " For a guide and recipes on how to configure / customize this project,"
                ),
                e("br"),
                t._v(" check out the "),
                e(
                  "a",
                  {
                    attrs: {
                      href: "https://cli.vuejs.org",
                      target: "_blank",
                      rel: "noopener",
                    },
                  },
                  [t._v("vue-cli documentation")]
                ),
                t._v(". "),
              ]);
            },
            function () {
              var t = this,
                e = t._self._c;
              return e("ul", [
                e("li", [
                  e(
                    "a",
                    {
                      attrs: {
                        href: "https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel",
                        target: "_blank",
                        rel: "noopener",
                      },
                    },
                    [t._v("babel")]
                  ),
                ]),
                e("li", [
                  e(
                    "a",
                    {
                      attrs: {
                        href: "https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint",
                        target: "_blank",
                        rel: "noopener",
                      },
                    },
                    [t._v("eslint")]
                  ),
                ]),
              ]);
            },
            function () {
              var t = this,
                e = t._self._c;
              return e("ul", [
                e("li", [
                  e(
                    "a",
                    {
                      attrs: {
                        href: "https://vuejs.org",
                        target: "_blank",
                        rel: "noopener",
                      },
                    },
                    [t._v("Core Docs")]
                  ),
                ]),
                e("li", [
                  e(
                    "a",
                    {
                      attrs: {
                        href: "https://forum.vuejs.org",
                        target: "_blank",
                        rel: "noopener",
                      },
                    },
                    [t._v("Forum")]
                  ),
                ]),
                e("li", [
                  e(
                    "a",
                    {
                      attrs: {
                        href: "https://chat.vuejs.org",
                        target: "_blank",
                        rel: "noopener",
                      },
                    },
                    [t._v("Community Chat")]
                  ),
                ]),
                e("li", [
                  e(
                    "a",
                    {
                      attrs: {
                        href: "https://twitter.com/vuejs",
                        target: "_blank",
                        rel: "noopener",
                      },
                    },
                    [t._v("Twitter")]
                  ),
                ]),
                e("li", [
                  e(
                    "a",
                    {
                      attrs: {
                        href: "https://news.vuejs.org",
                        target: "_blank",
                        rel: "noopener",
                      },
                    },
                    [t._v("News")]
                  ),
                ]),
              ]);
            },
            function () {
              var t = this,
                e = t._self._c;
              return e("ul", [
                e("li", [
                  e(
                    "a",
                    {
                      attrs: {
                        href: "https://router.vuejs.org",
                        target: "_blank",
                        rel: "noopener",
                      },
                    },
                    [t._v("vue-router")]
                  ),
                ]),
                e("li", [
                  e(
                    "a",
                    {
                      attrs: {
                        href: "https://vuex.vuejs.org",
                        target: "_blank",
                        rel: "noopener",
                      },
                    },
                    [t._v("vuex")]
                  ),
                ]),
                e("li", [
                  e(
                    "a",
                    {
                      attrs: {
                        href: "https://github.com/vuejs/vue-devtools#vue-devtools",
                        target: "_blank",
                        rel: "noopener",
                      },
                    },
                    [t._v("vue-devtools")]
                  ),
                ]),
                e("li", [
                  e(
                    "a",
                    {
                      attrs: {
                        href: "https://vue-loader.vuejs.org",
                        target: "_blank",
                        rel: "noopener",
                      },
                    },
                    [t._v("vue-loader")]
                  ),
                ]),
                e("li", [
                  e(
                    "a",
                    {
                      attrs: {
                        href: "https://github.com/vuejs/awesome-vue",
                        target: "_blank",
                        rel: "noopener",
                      },
                    },
                    [t._v("awesome-vue")]
                  ),
                ]),
              ]);
            },
          ],
          a = {
            name: "HelloWorld",
            props: {
              msg: String,
            },
          },
          u = a,
          c = r(656),
          h = (0, c.A)(u, i, s, !1, null, "b9167eee", null),
          v = h.exports,
          f = {
            name: "App",
            components: {
              HelloWorld: v,
            },
          },
          g = f,
          b = (0, c.A)(g, l, o, !1, null, null, null),
          I = b.exports;
        (n.Ay.config.productionTip = !1),
          new n.Ay({
            render: (t) => t(I),
          }).$mount("#app");
      },
      153: function (t) {
        t.exports =
          "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyNpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OTk2QkI4RkE3NjE2MTFFNUE4NEU4RkIxNjQ5MTYyRDgiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OTk2QkI4Rjk3NjE2MTFFNUE4NEU4RkIxNjQ5MTYyRDgiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NjU2QTEyNzk3NjkyMTFFMzkxODk4RDkwQkY4Q0U0NzYiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NjU2QTEyN0E3NjkyMTFFMzkxODk4RDkwQkY4Q0U0NzYiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5WHowqAAAXNElEQVR42uxda4xd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";
      },
    },
    e = {};

  function r(n) {
    var l = e[n];
    if (void 0 !== l) return l.exports;
    var o = (e[n] = {
      exports: {},
    });
    return t[n](o, o.exports, r), o.exports;
  }
  (r.m = t),
    (function () {
      var t = [];
      r.O = function (e, n, l, o) {
        if (!n) {
          var i = 1 / 0;
          for (c = 0; c < t.length; c++) {
            (n = t[c][0]), (l = t[c][1]), (o = t[c][2]);
            for (var s = !0, a = 0; a < n.length; a++)
              (!1 & o || i >= o) &&
              Object.keys(r.O).every(function (t) {
                return r.O[t](n[a]);
              })
                ? n.splice(a--, 1)
                : ((s = !1), o < i && (i = o));
            if (s) {
              t.splice(c--, 1);
              var u = l();
              void 0 !== u && (e = u);
            }
          }
          return e;
        }
        o = o || 0;
        for (var c = t.length; c > 0 && t[c - 1][2] > o; c--) t[c] = t[c - 1];
        t[c] = [n, l, o];
      };
    })(),
    (function () {
      r.d = function (t, e) {
        for (var n in e)
          r.o(e, n) &&
            !r.o(t, n) &&
            Object.defineProperty(t, n, {
              enumerable: !0,
              get: e[n],
            });
      };
    })(),
    (function () {
      r.g = (function () {
        if ("object" === typeof globalThis) return globalThis;
        try {
          return this || new Function("return this")();
        } catch (t) {
          if ("object" === typeof window) return window;
        }
      })();
    })(),
    (function () {
      r.o = function (t, e) {
        return Object.prototype.hasOwnProperty.call(t, e);
      };
    })(),
    (function () {
      var t = {
        524: 0,
      };
      r.O.j = function (e) {
        return 0 === t[e];
      };
      var e = function (e, n) {
          var l,
            o,
            i = n[0],
            s = n[1],
            a = n[2],
            u = 0;
          if (
            i.some(function (e) {
              return 0 !== t[e];
            })
          ) {
            for (l in s) r.o(s, l) && (r.m[l] = s[l]);
            if (a) var c = a(r);
          }
          for (e && e(n); u < i.length; u++)
            (o = i[u]), r.o(t, o) && t[o] && t[o][0](), (t[o] = 0);
          return r.O(c);
        },
        n = (self["webpackChunkhello"] = self["webpackChunkhello"] || []);
      n.forEach(e.bind(null, 0)), (n.push = e.bind(null, n.push.bind(n)));
    })();
  var n = r.O(void 0, [504], function () {
    return r(723);
  });
  n = r.O(n);
})();
//# sourceMappingURL=app.6a7bde24.js.map