在現代Web開發中,保障使用者身分的安全性是一個至關重要的課題。本篇將深入討論使用JWT實作身分驗證和實際安全技巧,其中包括防範SQL注入和更詳細的XSS防護。使用JWT實作身分驗證JSONWebTokenJWT是一種常見的身分驗證機制,它提供了安全而有效的方式來管理使用者身分。以下是在Express中實作JWT身分驗證的詳細步驟:安裝jsonwebtoken首先我們使用指令安裝jsonwebtoken:npminstalljsonwebtoken創建與驗證JWT在身分驗證的過程中,不僅要能夠成功創建JWT,還需要能夠確保JWT的內容是有效且沒有被篡改的。以下是創建和驗證JWT的詳細操作:創建JWT在/login路由中,我們創建一個包含使用者資訊的JWT:constjwtrequire"jsonwebtoken";app.post"/login",req,res{//模擬使用者身分驗證constuser{id:1,name:"PardnChiu"};//創建JWT,並設置過期時間jwt.sign{user},"SecretKey]",{expiresIn:"1h"},err,token{iferr{res.status500.json{err:err};}else{res.json{token};};};};在這個例子中,jwt.sign函數接收三個參數:{user}:儲存在JWT中的使用者資訊。SecretKey]:簽署JWT的密鑰,請妥善保管密鑰。{expiresIn:"1h"}:Token過期時間,範例中設定為一小時。驗證JWT在路由/needAuth中,我們使用jwt.verify方法來驗證JWT:constjwtrequire"jsonwebtoken";app.get"/needAuth",getToken,req,res{//驗證token內容jwt.verifyreq.token,"SecretKey]",err,data{iferr{res.sendStatus403;}else{res.json{message:"Success",data:data};};};};//取得token內容functiongetTokenreq,res,next{constauthorizationreq.headers"authorization"];iftypeofauthorization!"undefined"{consttokenauthorization.split""1];req.tokentoken;next;}else{res.sendStatus403;};};在這個例子中,jwt.verify函數接收三個參數:req.token:要驗證的JWT。SecretKey]:簽署JWT的密鑰,必須與創建JWT時使用的密鑰相同。回調函數:用於處理驗證結果,如果驗證成功,data將包含JWT中的資訊。這樣,我們就能確保只有在JWT是有效且未被篡改的情況下,才能讀取/needAuth頁面。防範SQL注入SQL注入是一種嚴重的安全威脅,攻擊者可能通過不當處理SQL查詢而獲取應用程式的資料庫訊息。以下是更詳細的SQL注入防護技巧:使用參數化查詢使用參數來查詢是防範SQL注入的有效方法。這樣可以確保用戶輸入不會被直接插入SQL查詢:constmysqlrequire"mysql";constdbmysql.createConnection{host:"HOST]",user:"ACCOUNT]",password:"PASSWORD]",database:"DATABASE]"};app.get"/user/:id",asyncreq,res{constidreq.params.id;db.querySELECTFROMusersWHEREid?,id],err,r{//處理結果};};避免動態拼接SQL不要使用動態拼接SQL字符串,這可能會讓應用程式容易受到注入攻擊。而是使用預處理語句或ORM物件關聯映射來建構查詢。預備語句如使用參數化查詢範例中,?是預處理語句的參數占位符,而不會將id直接插入SQL查詢字符串。使用ORM物件關聯映射ORM是一種將應用程式中的物件與資料庫中的表格進行映射的技術。這樣的映射允許你使用物件導向的方式來操作資料庫,而不需要直接處理SQL查詢。使用ORM可以大大減少動態拼接SQL字符串的風險,因為ORM通常會處理與資料庫的交互。以下是使用Sequelize一個Node.js中的ORM的簡單例子:constSequelizerequire"sequelize";constsequelizenewSequelize"DATABASE]","ACCOUNT]","password]",{host:"HOST]",dialect:"mysql"};//定義User模型constUsersequelize.define"user",{id:{type:Sequelize.INTEGER,primaryKey:true,autoIncrement:true},name:Sequelize.STRING,};app.get"/user/:id",asyncreq,res{constidreq.params.id;try{constuserawaitUser.findByPkid;res.jsonuser;}catcherr{res.status500.json{error:err};}};在這個例子中,User模型代表了資料庫中的users表格,而不需要直接使用SQL查詢。防範跨站腳本攻擊XSS跨站腳本攻擊是另一種威脅,攻擊者可能通過在網頁上插入惡意腳本,竊取用戶信息。以下是更詳細的XSS防護技巧:輸出轉義輸出轉義是一種機制,它將用戶輸入的特殊字元轉換為其對應的HTML實體,從而防止這些字元被解釋為HTML或JavaScript代碼。這樣可以防止潛在的XSS攻擊。在使用模板引擎時,通常會自動處理輸出轉義。模板引擎會將用戶輸入的字元轉換為安全的HTML實體,確保其不會執行任何惡意的腳本。ContentSecurityPolicyCSP雖然輸出轉義是一個有效的防禦手段,但還有其他進階的安全機制可以增加對抗XSS攻擊的強度。其中之一是ContentSecurityPolicyCSP。CSP是一個HTTP標頭,它可以告訴瀏覽器僅執行特定來源的資源,從而有效地防止不信任的腳本的執行。在Express中,你可以添加CSP標頭:app.usereq,res,next{res.setHeader"ContentSecurityPolicy","scriptsrc'self'";next;};上方範例中,scriptsrc'self'表示只允許執行來自相同來源的腳本。這有助於防止執行來自其他來源的惡意腳本。系列文章ahref"https://pardn.io/blog/nodejsinstall"target"self"Node.js.JavaScript的後端魔法/aahref"https://pardn.io/blog/nodejspromiseasync"target"self"Promise與Async/Await的非同步設計/aahref"https://pardn.io/blog/nodejshelloworld"target"self"建立第一個Node.js應用程式有多難?/aahref"https://pardn.io/blog/nodejsexpress"target"self"什麼?Express竟然如此的好用/aahref"https://pardn.io/blog/nodejsmongodbmysql"target"self"前進資料庫!MongoDB與MySQL/aahref"https://pardn.io/blog/nodejsmiddleware"target"self"中介軟體Middleware與定制流程/aahref"https://pardn.io/blog/nodejspugejs"target"self"服務端渲染SSR的救星!Pug與EJS/a實作JWT會員登入以及防範SQL注入與XSS攻擊ahref"https://pardn.io/blog/nodejsrestfulapi"target"self"RESTfulAPI該怎麼設計?/aahref"https://pardn.io/blog/nodejsmochasupertest"target"self"Mocha?Supertest?單元與整合測試?/aahref"https://pardn.io/blog/nodejspm2"target"self"搭配Pm2讓Node.js持久化在線/a相關連結作者:PardnChiu]https://github.com/pardnchiuNode.js官方網站:https://nodejs.org/zhtw]https://nodejs.org/zhtwnpmjsonwebtoken:https://www.npmjs.com/package/jsonwebtoken]https://www.npmjs.com/package/jsonwebtoken