<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                眾所周知,HTTP是一種無狀態的協議,也就是說:當客戶端每次發出請求時,下一次請求無法得知上一次請求的狀態(所包含的狀態數據)。一旦數據交換完畢,客戶端與服務器端的連接就會關閉,再次交換數據需要建立新的連接。那么如何才能把一個用戶的狀態數據保存或者關聯起來?由此產生了cookie和session這兩門技術來解決這一問題。 會話(Session)跟蹤是Web程序中常用的技術,用來跟蹤用戶的整個會話。常用的會話跟蹤技術是Cookie與Session。Cookie通過在客戶端記錄信息確定用戶身份,Session通過在服務器端記錄信息確定用戶身份。 * * * * * # cookie 首先產生了 cookie 這門技術來解決這個問題,由于HTTP是一種無狀態的協議,服務器單從網絡連接上無從知道客戶身份。怎么辦呢?就給客戶端們頒發一個通行證吧,每人一個,無論誰訪問都必須攜帶自己通行證。這樣服務器就能從通行證上確認客戶身份了。這就是Cookie的工作原理。 cookie是一個實際存在的東西,它是 http 協議的一部分。 ## 處理流程(B代表瀏覽器,S代表服務器): 1. B首次請求S 2. S將cookie放在響應頭中發送給B,具體是response頭中的`Set-Cookie` 3. B接收到cookie之后,將cookie進行存儲 4. 之后每次B請求S時,將cookie放在請求頭中發送給S,具體是request頭中的`Cookie` ## 使用場景 1. 非重要的用戶信息 2. 瀏覽記錄(例如京東、天貓等都有瀏覽記錄的功能) 3. 猜你喜歡 S通過分析cookie里面存儲的用戶的瀏覽記錄,來給用戶推“猜你喜歡”的商品 ## 參數 其他可選的 cookie 參數會影響將 cookie 發送給服務器端的過程,主要有以下幾種: * path:表示 cookie 影響到的路徑,匹配該路徑才發送這個 cookie。 * expires 和 maxAge:告訴瀏覽器這個 cookie 什么時候過期,expires 是 UTC 格式時間,maxAge 是 cookie 多久后過期的相對時間。當不設置這兩個選項時,會產生 session cookie,session cookie 是 transient 的,當用戶關閉瀏覽器時,就被清除。一般用來保存 session 的 session_id。 * secure:當 secure 值為 true 時,cookie 在 HTTP 中是無效,在 HTTPS 中才有效。 * httpOnly:瀏覽器不允許腳本操作 document.cookie 去更改 cookie。一般情況下都應該設置這個為 true,這樣可以避免被 xss 攻擊拿到 cookie。 ## cookie在node.js(express)中的應用 express 在 4.x 版本之后,session管理和cookies等許多模塊都不再直接包含在express中,而是需要單獨添加相應模塊。 ### 下載安裝 express4 中操作cookie需要使用 `cookie-parser`模塊(https://github.com/expressjs/cookie-parser )。 ``` cnpm i cookie-parser -S ``` ### 使用步驟 1. 加載express模塊 2. 創建express實例app 3. 加載cookie-parser模塊 4. app使用cookieParser 5. `res.cookie()`設置cookie,`req.cookie `就可以訪問瀏覽器攜帶的cookie了,其中`req.signedCookies`是訪問的是加密模式下的cookie。 ``` let express = require('express') // 首先引入 cookie-parser 這個模塊 let cookieParser = require('cookie-parser') let app = express() app.listen(3000) /* 使用 cookieParser 中間件,cookieParser(secret, options) 其中 secret 用來加密 cookie 字符串(下面會提到 signedCookies) options 傳入上面介紹的 cookie 可選參數 */ app.use(cookieParser()) app.get('/', (req, res) => { // Cookies that have not been signed console.log('Cookies: ', req.cookies) // Cookies that have been signed console.log('Signed Cookies: ', req.signedCookies) }) ``` # session 除了使用cookie,Web應用程序中還經常使用session來記錄客戶端狀態。session是服務器端使用的一種記錄客戶端狀態的機制,使用上比cookie簡單一些,相應的也增加了服務器的存儲壓力。 ## 什么是session? Session是另一種記錄客戶狀態的機制,不同的是Cookie保存在客戶端瀏覽器中,而Session保存在服務器上。客戶端瀏覽器訪問服務器的時候,服務器把客戶端信息以某種形式記錄在服務器上。這就是Session。客戶端瀏覽器再次訪問時只需要從該Session中查找該客戶的狀態就可以了 ## session的產生背景? cookie 雖然很方便,但是使用 cookie 有一個很大的弊端,cookie 中的所有數據在客戶端就可以被修改,數據非常容易被偽造,那么一些重要的數據就不能存放在 cookie 中了,而且如果 cookie 中數據字段太多會影響傳輸效率。為了解決這些問題,就產生了 session,session 中的數據是保留在服務器端的。 session 的運作通過一個 session_id 來進行。session_id 通常是存放在客戶端的 cookie 中,比如在 express 中,默認是 connect.sid 這個字段,當請求到來時,服務端檢查 cookie 中保存的 session_id 并通過這個 session_id 與服務器端的 session data 關聯起來,進行數據的保存和修改。 ## 存儲位置 session 可以存放在 : 1. 內存 2. cookie本身 3. redis 或 memcached 等緩存中 4. 數據庫 5. 文件 6. 集群 線上來說,緩存的方案比較常見,存數據庫的話,查詢效率相比前三者都太低,不推薦。cookie session 有安全性問題,下面會提到。 ## session在node.js(express)中的應用 ### 下載安裝 express 中操作 session 要用到`express-session`模塊 (https://github.com/expressjs/session ) ``` cnpm i express-session -S ``` 這個模塊,主要的方法就是 session(options),其中 options 中包含可選參數,主要有: * name: 設置 cookie 中,保存 session 的字段名稱,默認為 connect.sid 。 * store: session 的存儲方式,默認存放在內存中,也可以使用 redis,mongodb 等。* express 生態中都有相應模塊的支持。 * secret: 通過設置的 secret 字符串,來計算 hash 值并放在 cookie 中,使產生的 signedCookie 防篡改。 * cookie: 設置存放 session id 的 cookie 的相關選項,默認為: `default: { path: '/', httpOnly: true, secure: false, maxAge: null }` * genid: 產生一個新的 session_id 時,所使用的函數, 默認使用 uid2 這個 npm 包。 * rolling: 每個請求都重新設置一個 cookie,默認為 false。 * resave: 即使 session 沒有被修改,也保存 session 值,默認為 true。 ## session存儲舉例 ### 在內存中存儲 session express-session 默認使用內存來存 session,對于開發調試來說很方便。 ``` var express = require('express'); // 首先引入 express-session 這個模塊 var session = require('express-session'); var app = express(); app.listen(5000); // 按照上面的解釋,設置 session 的可選參數 app.use(session({ secret: 'recommand 128 bytes random string', // 建議使用 128 個字符的隨機字符串 cookie: { maxAge: 60 * 1000 } })); app.get('/', function (req, res) { // 檢查 session 中的 isVisit 字段 // 如果存在則增加一次,否則為 session 設置 isVisit 字段,并初始化為 1。 if(req.session.isVisit) { req.session.isVisit++; res.send('<p>第 ' + req.session.isVisit + '次來此頁面</p>'); } else { req.session.isVisit = 1; res.send("歡迎第一次來這里"); console.log(req.session); } }); ``` ### 在 redis 中存儲 session session 存放在內存中不方便進程間共享,因此可以使用 redis 等緩存來存儲 session。 假設你的機器是 4 核的,你使用了 4 個進程在跑同一個 node web 服務,當用戶訪問進程1時,他被設置了一些數據當做 session 存在內存中。而下一次訪問時,他被負載均衡到了進程2,則此時進程2的內存中沒有他的信息,認為他是個新用戶。這就會導致用戶在我們服務中的狀態不一致。 使用 redis 作為緩存,可以使用`connect-redis`模塊(https://github.com/tj/connect-redis )來得到 redis 連接實例,然后在 session 中設置存儲方式為該實例。 ``` var express = require('express'); var session = require('express-session'); var redisStore = require('connect-redis')(session); var app = express(); app.listen(5000); app.use(session({ // 假如你不想使用 redis 而想要使用 memcached 的話,代碼改動也不會超過 5 行。 // 這些 store 都遵循著統一的接口,凡是實現了那些接口的庫,都可以作為 session 的 store 使用,比如都需要實現 .get(keyString) 和 .set(keyString, value) 方法。 // 編寫自己的 store 也很簡單 store: new redisStore(), secret: 'somesecrettoken' })); app.get('/', function (req, res) { if(req.session.isVisit) { req.session.isVisit++; res.send('<p>第 ' + req.session.isVisit + '次來到此頁面</p>'); } else { req.session.isVisit = 1; res.send('歡迎第一次來這里'); } }); ``` 我們可以運行 redis-cli 查看結果,如圖可以看到 redis 中緩存結果。 ## 各種存儲的利弊 上面我們說到,session 的 store 有四個常用選項:1)內存 2)cookie 3)緩存 4)數據庫 其中,開發環境存內存就好了。一般的小程序為了省事,如果不涉及狀態共享的問題,用內存 session 也沒問題。但內存 session 除了省事之外,沒有別的好處。 cookie session 我們下面會提到,現在說說利弊。用 cookie session 的話,是不用擔心狀態共享問題的,因為 session 的 data 不是由服務器來保存,而是保存在用戶瀏覽器端,每次用戶訪問時,都會主動帶上他自己的信息。當然在這里,安全性之類的,只要遵照最佳實踐來,也是有保證的。它的弊端是增大了數據量傳輸,利端是方便。 緩存方式是最常用的方式了,即快,又能共享狀態。相比 cookie session 來說,當 session data 比較大的時候,可以節省網絡傳輸。推薦使用。 數據庫 session。除非你很熟悉這一塊,知道自己要什么,否則還是老老實實用緩存吧。 ### signedCookie 上面都是講基礎,現在講一些專業點的。 上面有提到 cookie 雖然很方便,但是使用 cookie 有一個很大的弊端,cookie 中的所有數據在客戶端就可以被修改,數據非常容易被偽造 其實不是這樣的,那只是為了方便理解才那么寫。要知道,計算機領域有個名詞叫 簽名,專業點說,叫 信息摘要算法。 比如我們現在面臨著一個菜鳥開發的網站,他用 cookie 來記錄登陸的用戶憑證。相應的 cookie 長這樣:dotcom_user=alsotang,它說明現在的用戶是 alsotang 這個用戶。如果我在瀏覽器中裝個插件,把它改成 dotcom_user=ricardo,服務器一讀取,就會誤認為我是 ricardo。然后我就可以進行 ricardo 才能進行的操作了。之前 web 開發不成熟的時候,用這招甚至可以黑個網站下來,把 cookie 改成 dotcom_user=admin 就行了,唉,那是個玩黑客的黃金年代啊。 OK,現在我有一些數據,不想存在 session 中,想存在 cookie 中,怎么保證不被篡改呢?答案很簡單,簽個名。 假設我的服務器有個秘密字符串,是 this_is_my_secret_and_fuck_you_all,我為用戶 cookie 的 dotcom_user 字段設置了個值 alsotang。cookie 本應是 {dotcom_user: 'alsotang'} 這樣的。 而如果我們簽個名,比如把 dotcom_user 的值跟我的 secret_string 做個 sha1 sha1('this_is_my_secret_and_fuck_you_all' + 'alsotang') === '4850a42e3bc0d39c978770392cbd8dc2923e3d1d' 然后把 cookie 變成這樣 ``` { dotcom_user: 'alsotang', 'dotcom_user.sig': '4850a42e3bc0d39c978770392cbd8dc2923e3d1d', } ``` 這樣一來,用戶就沒法偽造信息了。一旦它更改了 cookie 中的信息,則服務器會發現 hash 校驗的不一致。 畢竟他不懂我們的 secret_string 是什么,而暴力破解哈希值的成本太高。 ### cookie-session 上面一直提到 session 可以存在 cookie 中,現在來講講具體的思路。這里所涉及的專業名詞叫做 對稱加密。 假設我們想在用戶的 cookie 中存 session data,使用一個名為 session_data 的字段。 存 ``` var sessionData = {username: 'alsotang', age: 22, company: 'alibaba', location: 'hangzhou'} ``` 這段信息的話,可以將 sessionData 與我們的 secret_string 一起做個對稱加密,存到 cookie 的 session_data 字段中,只要你的 secret_string 足夠長,那么攻擊者也是無法獲取實際 session 內容的。對稱加密之后的內容對于攻擊者來說相當于一段亂碼。 而當用戶下次訪問時,我們就可以用 secret_string 來解密 sessionData,得到我們需要的 session data。 signedCookies 跟 cookie-session 還是有區別的: - 是前者信息可見不可篡改,后者不可見也不可篡改 - 是前者一般是長期保存,而后者是 session cookie cookie-session 的實現跟 signedCookies 差不多。 不過 cookie-session 我個人建議不要使用,有受到回放攻擊的危險。 回放攻擊指的是,比如一個用戶,它現在有 100 積分,積分存在 session 中,session 保存在 cookie 中。他先復制下現在的這段 cookie,然后去發個帖子,扣掉了 20 積分,于是他就只有 80 積分了。而他現在可以將之前復制下的那段 cookie 再粘貼回去瀏覽器中,于是服務器在一些場景下會認為他又有了 100 積分。 如果避免這種攻擊呢?這就需要引入一個第三方的手段來驗證 cookie session,而驗證所需的信息,一定不能存在 cookie 中。這么一來,避免了這種攻擊后,使用 cookie session 的好處就蕩然無存了。如果為了避免攻擊而引入了緩存使用的話,那不如把 cookie session 也一起放進緩存中。 ### session cookie 初學者容易犯的一個錯誤是,忘記了 session_id 在 cookie 中的存儲方式是 session cookie。即,當用戶一關閉瀏覽器,瀏覽器 cookie 中的 session_id 字段就會消失。 常見的場景就是在開發用戶登陸狀態保持時。 假如用戶在之前登陸了你的網站,你在他對應的 session 中存了信息,當他關閉瀏覽器再次訪問時,你還是不懂他是誰。所以我們要在 cookie 中,也保存一份關于用戶身份的信息。 比如有這樣一個用戶 ``` {username: 'alsotang', age: 22, company: 'alibaba', location: 'hangzhou'} ``` 我們可以考慮把這四個字段的信息都存在 session 中,而在 cookie,我們用 signedCookies 來存個 username。 登陸的檢驗過程偽代碼如下: ``` if (req.session.user) { // 獲取 user 并進行下一步 next() } else if (req.signedCookies['username']) { // 如果存在則從數據庫中獲取這個 username 的信息,并保存到 session 中 getuser(function (err, user) { req.session.user = user; next(); }); } else { // 當做為登陸用戶處理 next(); } ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看