安全限制



JavaScript 可以在瀏覽器執行程式,這就牽涉到許多安全性問題,使用者下載了網頁,下載了JavaScript程式碼偷偷地在執行,有些動作必須加以限制,以免使用者 的電腦遭竊取資料、讀寫或破壞,最基本的,瀏覽器不允許JavaScript對客戶端電腦作檔案存取的動作。

安全還有其它許多因素要考量,舉例來說,在過去,瀏覽器上可以設狀態列文字,不過這也會有安全疑慮,因為在某些情況下,使用者可以變造狀態列訊息來欺 瞞使用者。例如在滑鼠移到超鏈結時,理應顯示連結的網址,如果透過程式變造顯示的網址,使用者就會被誤導。例如:
<html>
  <head>
    <script type="text/javascript">
        window.onload = function() {
            document.getElementById('link').onmouseover = function() {
                window.defaultStatus = 'https://openhome.cc';
            };
        };
    </script>
  </head>
  <body>
      <a id="link" href="http://caterpillar.onlyfun.net">caterpillar</a>
  </body>
</html>

有些瀏覽器已取消了defaultStatus的 設定作用,不過在Internet Explorer上還可以用來設定狀態列文字顯示,在上例中,滑鼠移至超鏈結時,由於安全限制,就算在Internet Explorer上也不會顯示設定的文字,而會顯示href的 網址,只有在移開滑鼠時,才會顯示設定的文字。狀態列文字的設定有所疑慮,事實上,新的瀏覽器也不再包括狀態列了(像是Firefox 4、IE9、Chrome等)。

使用JavaScript可以另開視窗,不過沒辦法開啟太小的視窗,這是個很理所當然的考量,因為若可以開很小的視窗,使用者沒注意到它,那在這個小 視窗中就可以偷偷摸摸作些壞事了。

在瀏覽器中基於安全,<input> 的type為file時,你設定的value會被瀏覽器忽略,只能由使用者親自選取檔案。你透過JavaScript來設定檔案選 取框的value值 也沒用。

那麼,如果想要設定一個按鈕,讓使用者可以清除選取的檔案要怎麼作?透過JavaScript將value設 為空字串是沒用的。不過可以重新要求瀏覽器建立新的選取框。例如:
<html>
<head>
<title>SecurityConstraint-1</title>
<script type="text/javascript">
window.onload = function() {
document.getElementById('clear').onclick = function() {
var fileupload = document.getElementById('fileupload');
fileupload.innerHTML = fileupload.innerHTML;
};
};
</script>
</head>
<body>
<div id="fileupload"><input name="upload" type="file"></div>
<button id="clear">Clear</button>
</body>
</html>

在上例中,若你選取了檔案,並按下Clear按鈕時,取得的innerHTML<input name="upload" type="file" value="...">,當它被指定回innerHTML,瀏覽器會重新剖析並忽略value的部份。等於要求瀏覽器丟掉舊的<input name="upload" type="file">,建立新的<input name="upload" type="file">,在使用者的觀感中,自然就像是清除了選取框的內容。

再舉使用JavaScript取得檔案大小為例,在Firefox、Chrome中,可以透過files.item(0).size 特性來取得檔案大小。例如:
<html>
<head>
<title>SecurityConstraint-2</title>
<script type="text/javascript">
window.onload = function() {
document.getElementById('size').onclick = function() {
var size = document.getElementById('upload')
.files.item(0).size;
document.getElementById('console')
.innerHTML = 'Size: ' + size;
};
};
</script>
</head>
<body>
<input id="upload" name="upload" type="file"><br>
<button id="size">Size</button><br>
<span id="console"></span>
</body>
</html>

在Internet Explorer的話,無法使用以上方法,但在過去(Internet Explorer 6前),可以透過建立Image 或ActiveXObject(Scripting.FileSystemObject)來取得檔案大小,但因安全性問題,在新版 Internet Explorer都行不通了。以建立Image物件爲例,在過去可以:
<html>
  <head>
    <script type="text/javascript">
        window.onload = function() {
            document.getElementById('size').onclick = function() {
                var img = new Image();
                img.onload = function() {
                    var size = this.fileSize;
                    document.getElementById('console')
                            .innerHTML = 'Size: ' + size;
                };
                img.src = document.getElementById('upload').value;
            };
        };
    </script>
  </head>
  <body>
      <input id="upload" name="upload" type="file"><br>
      <button id="size">Size</button><br>
      <span id="console"></span>
  </body>
</html>

現在已行不通,因為這實際上是在進行下載指定檔案的動作,如果可以行的通,指定你電腦中的某個檔案,就可以將之載入Image物 件,之後還可以上傳到伺服器上(在Internet Explorer上,目前沒有現成方式可以取得檔案大小,只能透過像是Flash等其它方式取得)。

類似的限制還有iframe。例如:
<html>
<head>
<title>SecurityConstraint-3</title>
<script type="text/javascript">
window.onload = function() {
alert(window.frames['page'].document.body.innerHTML);
};
</script>
</head>
<body>
<iframe id="page" name="page"
src="https://openhome.cc"></iframe>
</body>
</html>

你可以取得iframe的內容,不過僅限與這個文件有相同來源的其它網頁才可以。若沒有這個限制,如果你是在內部網域,我指定你內部網域中某個內部網 站的網址,就可以取得網頁的內容,之後再上傳,也就是說,沒有這個限制,我就可以偷你內部網站中的東西。

如果你使用Ajax,所建立的Ajax非同步物件也會有相同的限制,你可以使用非同步物件來取得與文件相同來源的其它網頁,但不同來源的文件是無法取 得的。

這稱之為同源策略(Same-origin policy)。文 件相同來源指的是,與目前文件的URL協定主 機埠號相同的其它文件,才可以被 JavaScript取得,只要URL協定主 機埠號其中一個不同,就不可以取得。例如若 目前文件來源為http://caterpillar.onlyfun.net:80/Gossip/demo.html。那麼以下視為不同源...
  • https://caterpillar.onlyfun.net:80/Gossip/demo.html(協定不同)
  • http://openhome.cc:80/Gossip/demo.html(主機資訊不同,即使實體機器是同一台)
  • http://192.168.0.1:80/Gossip/demo.html(視為主機資訊不同)
  • http://caterpillar.onlyfun.net:8080/Gossip/demo.html(埠號不同)

<script> 的src可以指定外部URL,來自不同URL的.js檔案,可以在同一個頁面中運作,呼叫彼此變數或函式,但它們可取得的頁面必須 是與目前頁面相同來源,而不是與.js檔案相同來源。

子網域的文件,預設是不同源,但可以透過document.domain設定子網域為同 源,document.domain預設就是文件來源,例如若是 http://caterpillar.onlyfun.net:80/Gossip/demo.html,則document.domain就 是'caterpillar.onlyfun.net'。預設無法存取ooo.onlyfun.net、xxx.onlyfun.net的文件,你可 以將document.domain設 定為'onlyfun.net',如此來自ooo.onlyfun.net、xxx.onlyfun.net的文件就會被視為同源,注 意!document.domain只 能設為頂層網域,不能設其它網域。

以上簡介的是一些常見的JavaScript安全議題,實際上還有更多,甚至有些瀏覽器沒限制的,也可能被防毒軟體或防火牆防堵。