webappsec

Safety first.

這幾天才注意到 W3C 的 Web Application Security Working Group,簡稱為 webappsec,專門負責安全相關的規範制訂,是 2011 年就成立的,算是很後知後覺吧,其實現在很多已經很廣為人知的 Web 安全機制都是出自他們之手,像是 CORSCSP,然後他們現在也很跟的上潮流,把標準的制訂也移到 Github 上了,其實會發現這個 Github repo 是因為最近在看 fetch 的 spec,裡面多了蠻多內容,而且有不少引用到其它新標準的地方,然後看這看著就看到 webappsec 這邊,順便就看了一下,有幾個新草稿好像還蠻有趣的,想說可以介紹一下,不過這些東西大部分都還不能用就是了。

第一個是 Secure Contexts,這個新東西目的很簡單,就是判斷現在的連線狀況是否安全,以前的話,前端只能看是不是使用 https protocol 連線,不過 Secure Context 有比較多的判斷流程,例如用 SSL 就不會被當成是安全的,要 TLS 才會被認為是安全,如果不是 TLS 連線則還會判斷連到哪裡,看看白名單黑名單之類的機制。

第二個是 Credential Management,主要是為了因應現在瀏覽器很多都有記下使用者填的表單資料,包括登入的表單,而這等於是把使用者某個網站的帳號密碼都記錄下來,不過其實瀏覽器要做這些功能也是會遇到很多問題,像是他要怎麼判斷現在的表單是登入表單,哪些欄位是帳號密碼,或是網站用不一樣的機制,例如 XHR 來登入,這樣瀏覽器如果無法知道是什麼機制,就無法替這些特殊機制的網站的使用者提供方便的功能,所以 webappsec 就提出 Credential Management 這個功能讓網站開發者可以透過設計好的介面來告訴瀏覽器他們的網站是怎樣登入的,然後可以儲存帳號密碼在瀏覽器端,之後提供 API 給 JavaScript 呼叫出來送到 Server 端驗證,不過說是呼叫出來,其實 JavaScript 也看不到密碼明碼,而只能直接送出 login 的 request:

navigator.credentials.get({ "password": true }).then(
  function(credential) {
    if (!credential) {
      // The user either doesn't have credentials for this site, or
      // refused to share them. Insert some code here to show a basic
      // login form (or, ideally, do nothing, since this API should
      // really be progressive enhancement on top of an existing form).
      return;
    }
    if (credential.type == "password") {
      credential.send("https://example.com/loginEndpoint")
        .then(function (response) {
          // Notify the user that signin succeeded! Do amazing, signed-in things!
        });
    } else {
      // See the Federated Sign-in example
    }
  }
);

這是從 spec 內複製出來的 sample code,一個重點是,JavaScript 程式碼其實碰不到你的密碼,只能直接把 credential send 出去,其它也還支援像是 Facebook 那種第三方登入的設計,以及把 credential 存進 store 等等機制。

第三個是 Subresource Integrity

<script src="https://analytics-r-us.example.com/v1.0/include.js"
        integrity="sha256-Rj/9XDU7F6pNSX8yBddiCIIS+XKDTtdq0//No0MH0AE="
        crossorigin="anonymous"></script>

這是個看範例馬上就能理解幹什麼用的,就是對網頁要用到的其它 resource 檔案包括:js、css 等加上驗證檔案正確性的 hash,為的是避免有第三方的檔案內容被惡意攻擊者修改過。

第四個是 Upgrade Insecure Requests,這是唯一目前已經可以用的,為的是解決 mixed content 的問題,也就是有的網站可能最近才改為 HTTPS 連線,但是網站內部用到的一些內容還是寫死 URL 用 HTTP,這時候瀏覽器就會跳出說網頁內容可能不安全,然而,這些使用 HTTP 的檔案其實可能用 HTTPS 連線也找的到,像是 Flickr、TED 等都有支援 HTTPS 連線,而 Upgrade 就是跟瀏覽器說如果這些內容找得到 HTTPS 的就用 HTTPS 的,而不是只看寫死的 URL,目前 Chrome 43 已經開始支援了,有個線上 demo 可以看,設定方法可以透過 CSP header 加上upgrade-insecure-requests或是寫到 meta 標籤裡面(demo 用的)

<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

其實這個標準我一開始以為是類似 HSTS,是對現在開的網址本身做判斷是不是有 HTTPS 可供選擇,有的話就改用 HTTPS 連線,仔細看之後才發現是用來處理 mixed content ,可是又看一看發現也有一部份比較新的草稿有講到這個功能,目前討論的版本是用 header:

HTTPS: 1

很簡潔不過還沒瀏覽器支援就是了。