1. 程式人生 > >Node學習入門篇(七):Connect自帶的中介軟體

Node學習入門篇(七):Connect自帶的中介軟體

本章內容

  • 解析cookie、請求主體和查詢字串的中介軟體
  • 實現Web程式核心功能的中介軟體
  • 處理Web程式安全的中介軟體
  • 提供靜態檔案服務的中介軟體

解析cookie、請求主體和查詢字串的中介軟體

  • 常用中介軟體
    這裡寫圖片描述

    這裡寫圖片描述

注意:All node patches will be removed - all middleware should work without Connect and with similar frameworks like restify(connect內建中介軟體已經從connect中分離處理,使用時需要單獨安裝、引入)

  • 未簽名cookie

1) install

npm install cookie-parser

2) 常規(未簽名)cookie測試

var connect = require('connect');
var app = connect();
var cookieParser = require('cookie-parser')
app.use(cookieParser('sysuygm is cool'));
app.use(function(req, res) {
    console.log(req.cookies);
    console.log(req.signedCookies);
        "cookie"
:req.cookies, "signedCookies":req.signedCookies })); });

3)客戶端結果

傳送

accept: application/json
accept-encoding: gzip, deflate
accept-language: en-US,en;q=0.8
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36
Authorization: Basic ZmFmYTpmYWZh
Cookie: foo=
bar;bar=baz

收到

{
"cookie": {
"foo": "bar",
"bar": "baz",
"io": "GXHOFF8zxkVibldwAAAO"
},
"signedCookies": {}
}
  • 簽名cookie

簽名cookie更適合敏感資料,因為用它可以驗證cookie資料的完整性,有助於防止中間人攻擊。有效的簽名cookie放在req.signedCookies物件中。把兩個物件分開是為了體現開發者的意圖。如果把簽名的和未簽名的cookie放到同一個物件中,常規cookie可能就會被改造,仿冒簽名的cookie

簽名cookie看起來像tobi.DDm3AcVxE9oneYnbmpqxoyhyKsk一樣,點號(.)左邊的是cookie的值,右邊是在伺服器上用SHA-1 HMAC生成的加密雜湊值(基於雜湊的訊息認證碼)。如果cookie的值或者HMAC被改變的話,Connect的解籤會失敗

1) 使用簽名的cookie

cookieParser()中介軟體沒有提供任何通過Set-Cookie響應頭向HTTP客戶端寫出站cookie的功能。但Connect可以通過res.setHeader()函式寫入多個Set-Cookie響應頭

app.use(function(req, res) {
    console.log(req.cookies);
    // console.log(req.signedCookies);
    res.setHeader('Set-Cookie',
    'foo-bar;Expires=True,08 Jun 2021 10:18 GMT');
    res.end(JSON.stringify( {'seccuss':true}));
});

2) curl 檢視

>curl http://localhost:3000/ -H "Cookie:foo-bar" --head
HTTP/1.1 200 OK
Content-Type: application/json
Set-Cookie: foo-bar;Expires=True,08 Jun 2021 10:18 GMT
Date: Sun, 15 Apr 2018 15:16:58 GMT
Connection: keep-alive

bodyParser():解析請求主體

  • 假設你要用HTML標籤接受使用者上傳的檔案。用一行程式碼新增bodyParser()中介軟體就全齊了
  • bodyParser()元件為你提供了req.body屬性,可以用來解析JSON、x-www-form-urlencoded和multipart/form-data請求
  • 如果是multipart/form-data請求,比如檔案上傳,則還有req.files 物件
  • 這是個非常有用的元件,實際上它整合了其他三個更小的元件:json(), urlencoded(), 和multipart()

1) 先安裝

npm install body-parser

2) 使用

var cookieParser = require('cookie-parser')
// app.use(bodyParser()); 最好是像下面那樣顯示指定子元件,否則會提示冗餘

// parse application/x-www-form-urlencoded
 app.use(bodyParser.urlencoded({ extended: false }));

// parse application/json
 app.use(bodyParser.json());

app.use(function(req, res) {
    console.log(req.body.username);
    // console.log(req.signedCookies);
    res.end(JSON.stringify( {
        'username':req.username,
        'password':req.pass
    }));
});

POST資料

{
  "username": "caicai",
  "pass":"sysuygm"
}

如果bodyParser()在記憶體中快取json和x-www-form-urlencoded請求主體,產生一個大字串,那攻擊者會不會做一個超級大的JSON請求主體對伺服器做拒絕服務攻擊呢?答案基本上是肯定的,所以Connect提供了limit()中介軟體元件。

limit():請求主體的限制

  • limit()中介軟體元件的目的是幫助過濾巨型的請求
  • 防止指令碼攻擊
    (好像已經被丟棄了)

query():查詢字串解析

  • 它解析查詢字串,為程式提供req.query物件
  • 它會將請求傳送過來的查詢字串以JSON格式作為響應返回去
    (似乎已經被廢棄?)

favicon():提供favicon

(似乎已經被廢棄?)
使用 serve-favicon代替,用static-favicon會提示:

(node:3324) 
DeprecationWarning: static-icon deprecated; switch to module serve-favicon

使用firefox才能看到favicon!

::1 - - [Sun, 15 Apr 2018 16:55:37 GMT] "GET / HTTP/1.1" 200 - "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
undefined
::1 - - [Sun, 15 Apr 2018 16:59:42 GMT] "GET / HTTP/1.1" 200 - "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0"
undefined
::1 - - [Sun, 15 Apr 2018 16:59:54 GMT] "GET / HTTP/1.1" 200 - "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0"

logger():記錄請求

已被廢棄,現在用morgan代替, 直接安裝morgan

body-parser deprecated bodyParser: use individual json/urlencoded middlewares connect.js:27:9
body-parser deprecated undefined extended: provide extended option ..\node_modules\body-parser\index.js:105:29
morgan deprecated undefined format: specify a format connect.js:30:9
morgan deprecated default format: use combined format connect.js:30:9
listening...
undefined
::1 - fafa [Sun, 15 Apr 2018 16:48:14 GMT] "POST /?username=pppp HTTP/1.1" 200 - "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"

vhost():虛擬主機

  • vhost()(虛擬主機)中介軟體是一種通過請求頭Host路由請求的簡單、輕量的辦法
  • 這項任務通常是由反向代理完成的,可以把請求轉發到執行在不同埠上的本地伺服器那裡
  • vhost()元件在同一個Node程序中完成這一操作,它將控制權交給跟vhost例項關聯的Node HTTP伺服器
  • 可使子域名在Express中更容易管理。
  • 缺點:如果一個網站引發了崩潰,你的所有網站都會宕掉(因為它們都執行在同一個程序中)

session():會話管理

需要安裝 session-parser,且在cookie-parser前引入。

安全相關部分

basicAuth():HTTP基本認證

  • 基本認證是非常簡單的HTTP認證機制,並且在使用時應該小心,因為如果不是通過HTTPS進行認證,使用者憑證很可能會被攻擊者截獲

  • basicAuth()在最新的connect中已無法使用,且無法單獨使用,似乎只有Express中才能使用。

app.use(basicAuth(connect.basicAuth(auth)));
                          ^

TypeError: connect.basicAuth is not a function
    at Object.<anonymous> (F:\後臺開發\wechat\lib\connect.js:30:27)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    at Function.Module.runMain (module.js:693:10)
    at startup (bootstrap_node.js:188:16)
    at bootstrap_node.js:609:3

csrf():跨站請求偽造防護

  • 跨站請求偽造(CSRF)利用站點對瀏覽器的信任漏洞進行攻擊
  • csrf()會生成一個包含24個字元的唯一ID,認證令牌,作為req.session._csrf附到使用者的會話上
  • 這個令牌會作為隱藏的輸入控制元件_csrf出現在表單中,CSRF在提交時會驗證這個令牌
>npm install csrf

使用:
為了確保csrf()可以訪問req.body._csrf(隱藏輸入控制元件的值)和req.session._csrf,你要確保csrf()新增在了bodyParser()和session()的下面

app.use(favicon(__dirname + '/timg.ico'));
// app.use(basicAuth(connect.basicAuth(auth)));
app.use(cookieParser('private-key'));
app.use(session({
    keys:['aaa','bbb','ccc'],
    maxAge:360000*24,
    name:'session'
}));
app.use(bodyParser());
//新增在bodyParser()和session()的下面
app.use(csrf());
app.use(morgan());

errorHandler():開發錯誤處理

  • 可以基於請求頭域Accept提供詳盡的HTML、JSON和普通文字錯誤響應
  • errorHandler()是要用在開發過程中的,不應該出現在生產環境中

安裝:

npm install errorhandler

example:

var connect = require('connect')
var errorhandler = require('errorhandler')

var app = connect()

if (process.env.NODE_ENV === 'development') {
  // only use in development 
  app.use(errorhandler())
}

static():靜態檔案服務

  • static()中介軟體實現了一個高效能的、靈活的、功能豐富的靜態檔案伺服器,支援HTTP快取機制、範圍請
  • 有對惡意路徑的安全檢查,預設不允許訪問隱藏檔案(檔名以.開頭),會拒絕有害的null位元組
  • static()本質上是一個非常安全的、完全能勝任的靜態檔案服務中介軟體,可以保證跟目前各種HTTP客戶端的相容
  • 假定你的程式遵循典型的場景,要返回./public目錄下的靜態資原始檔

compress():壓縮靜態檔案

directory():目錄列表