最近項目中, 一個為了確保安全性而做的任務(wù)是移除代碼中的eval
. 我對eval
的不好略有耳聞, 但是它到底有多不好? 今天了解下.
Douglas Crockford說過:
The eval function (and its relatives, Function, setTimeout, and setInterval) provide access to the JavaScript compiler. This is sometimes necessary, but in most cases it indicates the presence of extremely bad coding. The eval function is the most misused feature of JavaScript.
這句話被很多人用來佐證eval
的不好. eval
被認(rèn)為為攻擊者進(jìn)行Cross-Site Scripting (XSS) 攻擊創(chuàng)造了便利. 但其實使用得當(dāng), eval
并沒有什么問題.
錯誤應(yīng)用
比方說下面這段代碼, 利用eval
去判斷一個表單元素是否被選中.
function isChecked(optionNumber) {
return eval("forms[0].option" + optionNumber + ".checked");
}
var result = isChecked(1);
這段代碼很容易用沒有eval
的方式實現(xiàn).
function isChecked(optionNumber) {
return forms[0]["option" + optionNumber].checked;
}
var result = isChecked(1);
這類似錯誤的eval
應(yīng)用可以簡單地使用[]
來避免.
調(diào)試
eval
中的代碼為調(diào)試帶來了難度. 現(xiàn)在Chrome Dev Tool可以debugeval
中的代碼, 但是仍然很麻煩. 所以, 從這點出發(fā), 為了開發(fā)效率, 也盡量不要用eval
.
效率
舊的瀏覽器中, 如果你使用eval
, 瀏覽器就要進(jìn)行兩次解析. 第一次解析JS代碼本身, 第二次解析eval中的代碼. 在不帶JS編譯引擎的瀏覽器中, 效率可能相差十倍.
即使對于帶JS編譯引擎的瀏覽器, eval
還是有問題. 大多數(shù)引擎運行代碼時會在兩種模式中選擇: 一個是fast path, 一個是slow path. 如果代碼穩(wěn)定, 比較容易預(yù)測, 那么引擎會使用fast path運行代碼, 效率高很多. 如果代碼很難預(yù)測, 那只能用slow path運行了. 由于帶eval
的代碼本身很難預(yù)測, 所以會走slow path, 因此也會造成效率低下.
安全性
eval
最讓人頭疼的地方就是安全性了. 如果你將用戶的輸入作為eval
的參數(shù), 那么就有XSS的風(fēng)險. 但是你只要確保不做出這種事, 使用eval
也是沒什么問題的.
另外一點是, 有些人說, 如果你使用eval
去運行瀏覽器返回的代碼, 那么就有可能受到中間人攻擊 (man-in-the-middle attack). 但是事實上, 如果一個人真的做到了中間人攻擊, 除了用eval
, 有更多簡單的方法讓他運行惡意代碼, 比如:
- 在代碼中插入
<script src="">
并引用惡意代碼. - 在JSON-P或者Ajax請求中插入惡意代碼.
另外, 中間人攻擊可以獲取用戶的cookie或者其他信息, 同時不篡改任何信息, 不被察覺. 這本身也是安全隱患, 與eval
無關(guān).
總之, 如果你無法相信瀏覽器返回的代碼, 那這本身產(chǎn)生的問題就遠(yuǎn)比eval
的問題大得多.
總結(jié)
eval
在調(diào)試和效率有不好的影響, 有一定的安全性隱患, 但是只要注意就可以避免. 總體來說, eval
盡量不要用.