JavaScript | eval() を使わずに安全に同じことをする方法

JavaScript
スポンサーリンク

では、先ほど話した「クロージャと eval の危険性」を理解するための
複雑だけど学びの多い練習サンプル4本セット を順番にすべて紹介します。

それぞれに

  • 💡 学びのポイント
  • 🧠 コード例
  • 🔍 結果・解説

をセットで掲載しています。
(すべてブラウザのコンソールやNode.jsでそのまま動作します)


サンプル①:安全なクロージャの例

💡 学び

関数が「外の変数」を覚えていることで、外部から直接アクセスできない値を保持できる

🧠 コード

function createSecretHolder(secret) {
  return {
    getSecret: function() {
      return secret;
    },
    setSecret: function(newSecret) {
      secret = newSecret;
    }
  };
}

const holder = createSecretHolder("🍎りんごの暗号");

console.log(holder.getSecret()); // 🍎りんごの暗号
holder.setSecret("🍇ぶどうの暗号");
console.log(holder.getSecret()); // 🍇ぶどうの暗号

// 外から直接アクセスはできない
console.log(holder.secret); // undefined
JavaScript

🔍 結果と解説

  • secret は関数スコープの中だけで保持されており、外部から直接改ざんできません。
  • これが「クロージャでプライベート変数を作る」典型例です。

サンプル②:toString() + eval の危険な例(スコープ喪失)

💡 学び

toString() した関数を eval で再生成すると、外部変数とのつながりが消える

🧠 コード

function makeAdder(x) {
  return function(y) {
    return x + y;
  };
}

const add10 = makeAdder(10);

console.log(add10(5)); // 15

// 関数を文字列化
const str = add10.toString();
console.log("文字列化結果:", str);

// evalで復元
const broken = eval('(' + str + ')');
console.log(broken(5)); // ❌ ReferenceError: x is not defined
JavaScript

🔍 結果と解説

  • xmakeAdder() の中でしか存在しません。
  • 文字列化して再生成した関数にはその「外側の記憶」がないため、x が未定義になりエラー。
  • クロージャの仕組みは文字列には含まれない!

サンプル③:悪意ある eval(危険な使い方)

💡 学び

eval()実行時に任意のコードを動かすため、ユーザー入力に使うのは非常に危険。

🧠 コード

function runUserCode(code) {
  try {
    console.log("実行します:", code);
    eval(code);
  } catch (e) {
    console.error("エラー:", e.message);
  }
}

// 安全そうに見える入力
runUserCode("console.log('こんにちは');");

// 悪意ある入力
runUserCode("alert('ハッキング!');");
runUserCode("document.body.innerHTML = '<h1>乗っ取られた!</h1>';");
JavaScript

🔍 結果と解説

  • eval() は、そのままコードを実行してしまうため、
    ユーザーが送った文字列に悪意ある内容があれば、すぐに被害が発生します。
  • セキュリティ上、eval はほぼ禁止レベル(特に外部入力と組み合わせるのは厳禁)。

サンプル④:安全な代替(Function + 検証つき)

💡 学び

どうしても動的にコードを扱いたい場合は、Function コンストラクタや安全なサンドボックスを利用する。

🧠 コード

function safeEval(expr) {
  // 数字・演算子・括弧以外を禁止する簡易フィルタ
  if (!/^[\d+\-*/().\s]+$/.test(expr)) {
    throw new Error("不正な文字が含まれています");
  }

  const func = new Function("return " + expr);
  return func();
}

console.log(safeEval("10 + 20 * 3")); // ✅ 70
console.log(safeEval("(5 + 3) * 2")); // ✅ 16
console.log(safeEval("alert('XSS')")); // ❌ エラー(検出)
JavaScript

🔍 結果と解説

  • Function コンストラクタで式を評価しても、ローカルスコープを汚染しない
  • さらに正規表現で文字列チェックを入れることで、
    安全な範囲内だけ評価できるよう制御できます。

まとめ:安全なコードの考え方

テーマ内容
✅ クロージャ外部スコープの値を安全に保持できる
⚠️ eval外部スコープは失われ、しかも危険(セキュリティリスク)
💀 悪用例ユーザー入力を eval() で処理すると乗っ取り可能
🛡️ 安全策Function() + 入力検証 or 専用の評価ライブラリを使う

ブラウザで動作するHTML実験ページ

内容構成

セクション内容
🔹 ① 安全なクロージャ値を外から守る方法
🔹 ② クロージャ喪失 (toString + eval)スコープが消える様子
🔹 ③ 危険な eval実行中に警告を表示(サンドボックス化)
🔹 ④ 安全な代替 (Function + 検証)安全に式を評価

See the Pen Learning Experiments with Closures and eval by MONO365 -Color your days- (@monoqlo365) on CodePen.

このページでできること

セクション実験内容学べること
プライベート変数の保持クロージャの仕組み
toString + eval のスコープ喪失クロージャは文字列化できない
悪意ある eval の防御eval() の危険性
Function + 検証安全な代替実装方法
タイトルとURLをコピーしました