淺談前端安全-xss

引言

當代社會網絡的快速普及,人們愈來愈依賴網絡,廣大網絡用戶經過互聯網瞭解更多信息的同時,也面臨着信息泄露的風險。網絡安全成爲了社會發展的焦點話題,展示在用戶面前的前端界面愈來愈多元化,這就須要更多地去了解信息安全,這篇文章主要談xss攻擊 github

xss(Cross Site Scripting)跨站腳本攻擊

觀察如下代碼,它們若是做爲html的節點內容,就會引發xss攻擊javascript

<p><svg onload=prompt(/xss/)></p>
<iframe src="http://www.baidu.com" height="250" width="300"></iframe>
<a href="javascript:alert('xss')">你好</a>
<img src=1 onerror=alert('xss')>
複製代碼

所以,XSS 攻擊,通常是指攻擊者經過在網頁中注入惡意腳本,當用戶瀏覽網頁時,惡意腳本執行,控制用戶瀏覽器行爲的一種攻擊方式。html

而後談談跨站這個詞: 咱們通常但願網站運行的全部邏輯均來自本站,當本站運行了其餘網站的東西,例如常見的js腳本,就可能產生跨站腳本攻擊,固然在這裏咱們能夠理解爲不侷限於遠程腳本,由於一般探測是否頁面是否存在潛在的xss攻擊,都會使用一個alert框,也被稱作xss探測器。舉個簡單的例子:前端

例子1
// server.js
const express = require('express');
const app = express();
app.get('/', function(req, res){
  res.send('hello world')
})

app.get('/index', function(req, res){
  const id = req.query.id
  res.send(`<textarea>${id}</textarea>`)
})
app.listen(3001)
複製代碼

在瀏覽器輸入網址 localhost:3001/index?id=</textarea><script>alert(1)</script>java

在谷歌瀏覽器的運行結果

按下回車的那一瞬,並沒看到預期的彈框,心裏一陣失落,但同時也注意到了textarea輸入框並無東西,因而想莫非是谷歌瀏覽器已經作了什麼事情,來預防此種簡易的攻擊,打開console面板 git

果真,好吧,輸給了chrome,我仍是心服口服的,在這裏值得提一下,谷歌的安全機制仍是很完善的,這種簡單的反射性跨站攻擊,谷歌直接就幫忙處理攔截了,safari也會對這種簡易的攻擊作基本的攔截。 github

換個瀏覽器,firefox

好吧,好大一個框! chrome

xss攻擊的原理

本質: 插值形成的注入。數據庫

腳本程序 + 數據源 = 渲染結果

腳本程序: <textarea>${id}</textarea>express

數據源 渲染結果
id: 1 <textarea>1</textarea>
id: </textarea><script>alert(1)</script> <textarea></textarea><script>alert(1)</script></textarea>

在這個例子中,攻擊者首先把盛放數據的容器提早閉合,而後經過script標籤爲數據賦予行爲,讓數據源再也不單純,改變整個程序的邏輯,從而實現攻擊的目的後端

只是彈個框嗎?

說到這裏,咱們已經用了個簡單的例子引出了今天的主題xss,也許有人內心會有疑問,不就是彈個框嗎?果然如此嗎?咱們能夠換個角度考慮一下,咱們平時寫的腳本能幹什麼?

  • 獲取頁面數據

  • 獲取cookie

  • 劫持前端的邏輯

  • 發送請求

  • ...

    所以,xss也能夠幹這些事,只有你想不到,沒有黑客作不到的,攻擊者經過注入腳本,能夠經過dom抓取頁面中的數據,也能夠經過document.cookie獲取用戶的cookie,通常cookie保存有用戶登錄態,攻擊者只須要將這個cookie種在本身的瀏覽器中,就能夠獲取用戶的各類信息,模擬用戶進行各類操做等。

業界被攻擊案例

上網搜了下以前被xss惡意攻擊的案例,發現了一個典型,做爲前端工程師,或多或少都知道站酷這個網站,這是國內很是有名的設計師交流平臺,在官網首頁有個搜索功能,當輸入搜索關鍵詞後點擊搜索,關鍵詞會在搜索結果頁二次顯示 站酷

值得說明的是:如今站酷已經修復了,目前的效果是對標籤進行了處理

xss攻擊分類

  • 反射型xss攻擊
  • 存儲型xss攻擊
  • dom型xss攻擊

我理解的三者的區別:

反射型xss攻擊:

經過url連接點擊觸發,是一次性行爲,實質是服務器端沒有對用戶的惡意輸入作安全處理,直接反射相應內容。文章開始的例子1就是一個典型的反射型xss攻擊,這類攻擊能夠經過url辨別,谷歌這類安全性高的瀏覽器,基本能夠自動處理這類攻擊

存儲型xss攻擊:

顧名思義,存儲,通常涉及後端數據存儲,常見的場景就是APP的意見反饋模塊,前端經過接口把用戶輸入的信息傳給後端,當有些後臺管理系統須要展現反饋意見時,就會取數據庫中的這些數據,當這些數據中含有攻擊的腳本,那就形成了存儲型xss攻擊。這種攻擊是持久性的。

dom型攻擊:

客戶端的腳本程序能夠動態地檢查和修改頁面內容,而不依賴於服務器端的數據。可能引發dom型xss的:使用innerHTML, documen.write屬性...

xss的注入點

  • html節點內容動態生成
  • html屬性,屬性是由用戶輸入的信息組成的
<img src="null" onerror='alert(document.cookie)' />
複製代碼
  • js代碼-js代碼存在後臺注入的變量或者用戶的信息
// test.html
  <script>
    const info = '';alert(1);''
    const data = `hello${info}`
  </script>
複製代碼
  • 富文本標籤

xss防護

1 瀏覽器自帶的防護:

X-XSS-Protection: Chrome 和 Safari 的一項功能,可在檢測到反射的跨站點腳本(XSS)攻擊時阻止頁面加載 可選的值:

  • X-XSS-Protection: 0
  • X-XSS-Protection: 1
  • X-XSS-Protection: 1; mode=block 啓用 XSS
  • X-XSS-Protection: 1; report=reporting-uri
  • 0 禁用 XSS 過濾.
  • 1 啓用 XSS 過濾(一般在瀏覽器中默認)。若是檢測到跨站點腳本攻擊,瀏覽器將清理頁面(刪除不安全的部分)。
  • mode = block 若是檢測到攻擊,瀏覽器將阻止頁面的呈現,而不是消毒該頁面
  • report = (僅限 Chromium)啓用 XSS
  • 篩選。若是檢測到跨站點腳本攻擊,瀏覽器將清理頁面並報告違規行爲。這使用 CSP report-uri指令的功能發送報告。
  • 攔截結果:
    防護範圍: 反射型xss攻擊

2. html標籤轉義

將標籤符號'<', '>'全局轉義

...
const escapeHtml = (str) => {
  str = str.replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quto;') .replace(/'/g, '&#39;') .replace(/ /g, '&#32;') return str } ... app.get('/index', (req, res) => { const id = req.query.id || '' res.send(`<textarea>${escapeHtml(id)}</textarea>`) }) 複製代碼

輸出:

用戶輸入什麼,顯示什麼,而且也沒形成xss攻擊。

3.白名單過濾

高度定製要展現的內容,這裏我使用了cheerio來將html字符串解析成html實體, cheerio

// <img src="123" onerror="alert(1)"></img>使用cheerio的輸出
{ type: 'tag',
  name: 'img',
  attribs: { src: '123', onerror: 'alert(1)' },
  children: [],
  next: null,
  prev: null,
  parent: null,
  root:
   { type: 'root',
     name: 'root',
     attribs: {},
     children: [ [Circular] ],
     next: null,
     prev: null,
     parent: null 
   } 
}


複製代碼
// server.js 無關代碼已省略
...
const whiteList = {
  'img': ['src']
}
const xssFilter = (html) => {
  if (!html) return ''
  const $ = cheerio.load(html, {
    normalizeWhitespace: true,
    xmlMode: true
  })
  $('*').each((index, elem) => {
    if (!whiteList[elem.name]) {
      $(elem).remove()
      return
    }
    for (var attr in elem.attribs) {
      if (whiteList[elem.name].indexOf(attr) === -1) {
        $(elem).attr(attr, null)
      }
    }
  })
  onsole.log(html, $.html())
  return $.html()
}
app.get('/api', (req, res) => {
  const cb = (result) => {
    result = result.map(item => {
      const { comment, name, time } = item
      return {
        name,
        time,
        comment: xssFilter(comment)
      }
    })
    res.send({
      data: result,
      message: 'success',
      status: 1
    })
  }
  model.find({}, cb) // 自定義的查詢方法
})
...
複製代碼

過濾結果: 由於白名單隻配置了:'img': ['src'], 所以img的onerror屬性被過濾,其餘不在白名單的標籤總體被過濾

4.csp(Content Security Policy)

csp文檔

csp是個http的頭,實質是用於規定內容是否可執行,所以只要將用戶的內容標記爲不可執行,就ok了~~~

// server.js
...
app.use((req, res, next) => {
  res.set({
    'Content-Security-Policy': "default-src 'self'"
  })
  next()
})
...
複製代碼

沒有攻擊成功

相關文章
相關標籤/搜索