主頁 > 企業開發 > Node.js 安全指南

Node.js 安全指南

2021-02-01 06:29:00 企業開發

當專案周期快結束時,開發人員會越來越關注應用的“安全性”問題,一個安全的應用程式并不是一種奢侈,而是必要的,你應該在開發的每個階段都考慮應用程式的安全性,例如系統架構、設計、編碼,包括最后的部署,

在這篇教程中,我們將一步步來學習如何提高Node.js應用程式安全性的方法,

1. 資料驗證 - 永遠不要信任你的用戶

來自用戶輸入或其他系統的資料,你都必須要進行驗證,否則,這會對當前系統造成威脅,并導致不可想象的安全漏洞,現在,讓我們學習如何驗證Node.js中的傳入資料,你可以使用名為validator的模塊來執行資料驗證, 例如:

const validator = require('validator');
validator.isEmail('[email protected]'); //=> true
validator.isEmail('bar.com'); //=> false

另外,你也可以使用joi模塊來進行資料和模型的驗證,例如:

  const joi = require('joi');
  try {
    const schema = joi.object().keys({
      name: joi.string().min(3).max(45).required(),
      email: joi.string().email().required(),
      password: joi.string().min(6).max(20).required()
    });

    const dataToValidate = {
        name: "Shahid",
        email: "abc.com",
        password: "123456",
    }
    const result = schema.validate(dataToValidate);
    if (result.error) {
      throw result.error.details[0].message;
    }    
  } catch (e) {
      console.log(e);
  }

2. SQL注入攻擊

SQL注入可以讓惡意用戶通過傳遞非法引數,來篡改SQL陳述句,下面是一個例子,假設你寫了這樣一個SQL:

UPDATE users
    SET first_name="' + req.body.first_name +  '" WHERE id=1332;

在正常情況下,你希望這次查詢應該是這樣的:

UPDATE users
    SET first_name = "John" WHERE id = 1332;

但是現在,如果有人將first_name的值按下面這種方式傳遞:

John", last_name="Wick"; --

這時,你的SQL陳述句就會變成這樣:

UPDATE users
    SET first_name="John", last_name="Wick"; --" WHERE id=1001;

你會看到,WHERE條件被注釋掉了,這次更新會將整張表所有用戶的first_name改成Johnlast_name改成Wick,這下,你闖禍了!

如何避免SQL注入

避免SQL注入攻擊最有效的辦法就是將輸入資料進行過濾,你可以對每一個輸入資料逐一進行驗證,也可以用引數系結的方式驗證,開發者們最常用的就是引數系結的方式,因為它高效而且安全,

如果你在使用一些比較流行的ORM框架,例如sequelize、hibernate等等,那么框架中就已經提供了這種資料驗證和SQL注入保護機制,

如果你更喜歡依賴資料庫模塊,例如mysql for Node,那么你可以使用資料庫提供的過濾方法,下面代碼是使用mysql for Node的一個例子:

var mysql = require('mysql');
var connection = mysql.createConnection({
  host     : 'localhost',
  user     : 'me',
  password : 'secret',
  database : 'my_db'
});

connection.connect();

connection.query(
    'UPDATE users SET ?? = ? WHERE ?? = ?',
    ['first_name',req.body.first_name, ,'id',1001],
    function(err, result) {
    //...
});

??的地方被欄位名稱替換,?的地方被欄位值替換,這樣就保證了輸入值的安全性,

你也可以使用存盤程序來提高安全級別,但是由于缺乏可維護性,開發人員傾向于避免使用存盤程序,

同時,你還應該執行服務器端的資料驗證, 但我不建議你手動驗證每個欄位,可以使用joi等模塊來解決這個問題,

型別轉換

JavaScript是一種動態型別語言,即值可以是任何型別,你可以使用型別轉換方法來驗證資料的型別,這樣就能保證,只有指定型別的資料才可以進入資料庫,比如,用戶ID只能是數字型別,看下面的代碼:

var mysql = require('mysql');
var connection = mysql.createConnection({
  host     : 'localhost',
  user     : 'me',
  password : 'secret',
  database : 'my_db'
});

connection.connect();

connection.query(
    'UPDATE users SET ?? = ? WHERE ?? = ?',
    ['first_name',req.body.first_name, ,'id',Number(req.body.ID)],
    function(err, result) {
    //...
});

你注意到變化了嗎?這里我們使用了Number(req.body.ID)方法來確保用戶ID必須為數字,

3. 應用程式認證和授權

敏感資料(例如密碼)應該以一種安全的方式存盤在系統中,這樣,惡意用戶就不會濫用敏感資訊,在本節中,我們將學習如何存盤和管理通用的密碼,幾乎每個應用程式在其系統中都有不同的密碼存盤方式,

密碼哈希

哈希是一個將輸入值生成固定大小字串的函式,哈希函式的輸出值是無法解密的,因此可以說是“單向的”,因此,像密碼這樣的資料,存盤在資料庫中的值必須是哈希值,而不是明文,

你也許想知道,既然哈希是一種不可逆的加密方式,那么攻擊者又是如何取得密碼訪問權限的呢?

正如我上面提到的那樣,哈希加密使用輸入字串并生成固定長度的輸出值,因此,攻擊者采取了相反的方法,他們從常規密碼串列中生成哈希,然后將哈希與系統中的哈希進行比較以找到密碼,這種攻擊方式叫做查表法(Lookup Tables)

這就是為什么你作為系統架構師,絕不允許系統中使用簡單通用密碼的原因,為了避免攻擊,你也可以使用一種叫”salt"的東西,我們稱之為“哈希加鹽法”,將salt附加到密碼哈希中,從而使輸入值唯一,salt值必須是隨機的不可預測的,我們建議你使用的哈希演算法是BCrypt,在Node.js中,你可以使用bcyrpt節點模塊執行哈希處理,

請參考下面例子中的代碼:

const bcrypt = require('bcrypt');

const saltRounds = 10;
const password = "Some-Password@2020";

bcrypt.hash(
    password,
    saltRounds,
    (err, passwordHash) => {

    //we will just print it to the console for now
    //you should store it somewhere and never logs or print it

    console.log("Hashed Password:", passwordHash);
});

SaltRounds函式是哈希函式的成本,成本越高,生成的hash密碼越安全,你應該根據服務器的計算能力來確定salt值,密碼的hash值生成后,用戶輸入的密碼將會和存盤在資料庫中的hash值比對,參考代碼如下:

const bcrypt = require('bcrypt');

const incomingPassword = "Some-Password@2020";
const existingHash = "some-hash-previously-generated"

bcrypt.compare(
    incomingPassword,
    existingHash,
    (err, res) => {
        if(res && res === true) {
            return console.log("Valid Password");
        }
        //invalid password handling here
        else {
            console.log("Invalid Password");
        }
});

密碼存盤

無論你是用資料庫還是檔案來存盤密碼,都不能使用明文存盤,我們在上一節已經學到,你可以將密碼進行哈希后存盤在資料庫中,我推薦密碼欄位用varchar(255)資料型別,你也可以選擇不限長度的欄位型別,如果你使用的是bcrypt,則可以使用varchar(60)欄位型別,因為bcrypt會生成固定長度為60個字符的哈希,

認證和授權

一個擁有合適的角色權限系統,將會阻止一些惡意用戶在系統中做一些越權的事情,為了實作正確的授權程序,將合適的角色和權限分配給每個用戶,以便他們可以執行權限范圍內的某些任務,在Node.js中,你可以使用著名的ACL模塊,根據系統中的授權來開發訪問控制串列,

const ACL = require('acl2');
const acl = new ACL(new ACL.memoryBackend());
// guest is allowed to view blogs
acl.allow('guest', 'blogs', 'view')
// check if the permission is granted
acl.isAllowed('joed', 'blogs', 'view', (err, res) => {
    if(res){
        console.log("User joed is allowed to view blogs");
    }
});

請查閱acl2檔案以獲取更多資訊和示例代碼,

4. 暴力攻擊防護

黑客經常會使用軟體反復使用不同的密碼嘗試獲得系統權限,直到找到有效密碼為止,這種攻擊方式叫做暴力攻擊,為了避免這種攻擊,一種簡單有效的辦法是“讓他等一會”,也就是說,當某人嘗試登錄系統并嘗試輸入無效密碼3次以上時,請讓他們等待60秒左右,然后再嘗試,這樣,攻擊者將大大提高時間成本,并且將使他們永遠無法破解密碼,

防止這種攻擊的另一種方法是屏蔽無效登錄請求的IP,系統在24小時內允許每個IP進行3次錯誤地登錄嘗試,如果有人嘗試進行暴力破解,則將其IP封鎖24小時, 許多公司已使用這種方法來防止暴力攻擊, 如果使用Express框架,則有一個中間件模塊可在傳入請求中啟用速率限制, 它稱為express = brute

下面是一個例子,

安裝依賴項

npm install express-brute --save

在路由中啟用它

const ExpressBrute = require('express-brute');
const store = new ExpressBrute.MemoryStore(); // stores state locally, don't use this in production
const bruteforce = new ExpressBrute(store);

app.post('/auth',
    bruteforce.prevent, // error 429 if we hit this route too often
    function (req, res, next) {
        res.send('Success!');
    }
);
//...

5. HTTPS安全傳輸

現在已經2021年了,你也應該使用HTTPS來向網路中發送資料了,HTTPS是具有安全通信支持的HTTP協議的擴展,使用HTTPS,可以保證用戶在互聯網中發送的資料是被加密的,是安全的,

在這里我不打算詳細介紹HTTPS協議的作業原理,我們只討論如何使用它,這里我強烈推薦使用LetsEncrypt來為你的所有域名生成安全證書,

你可以在基于Apache和Nginx的Web服務器上使用LetsEncrypt,我強烈建議你在反向代理或網關層上使用HTTPS協議,因為它們有很多繁重的計算操作,

6. 會話劫持保護

會話(session)是任何動態Web應用程式最重要的部分,一個安全的會話對用戶和系統來說真的是非常必要的,會話是使用Cookie實作的,因此必須確保其安全以防止會話劫持,以下是可以為每個cookie設定的屬性串列以及它們的含義:

  • secure - 該屬性告訴瀏覽器僅在通過HTTPS發送請求時才發送cookie,
  • HttpOnly - 該屬性用于防止跨站點腳本攻擊,因為它不允許通過JavaScript訪問cookie,
  • domain - 該屬性用于與請求URL的服務器域名進行比較,如果域名匹配,或者是其子域,那么接下來就會檢查path屬性,
  • path - 除了domian之外,還可以指定cookie有效的URL路徑, 如果domain和路徑匹配,則可以在請求中發送cookie,
  • expires - 該屬性用于設定持久性的cookie,cookie只會在超過了設定的日期才會過期,

在Express框架中,你可以使用express-session npm模塊來管理會話,

const express = require('express');
const session = require('express-session');
const app = express();

app.use(session({
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: true,
  cookie: { secure: true, path: '/'}
}));

7. 跨站點請求偽造攻擊(CSRF)防護

跨站點請求偽造攻擊利用系統中受信任的用戶,對Web應用程式執行有害的惡意操作,在Node.js中,我們可以使用csurf模塊來緩解CSRF攻擊,該模塊需要首先初始化express-sessioncookie-parser,你可以看看下面的示例代碼:

const express = require('express');
const cookieParser = require('cookie-parser');
const csrf = require('csurf');
const bodyParser = require('body-parser');

// setup route middlewares
const csrfProtection = csrf({ cookie: true });
const parseForm = bodyParser.urlencoded({ extended: false });

// create express app
const app = express();

// we need this because "cookie" is true in csrfProtection
app.use(cookieParser());

app.get('/form', csrfProtection, function(req, res) {
  // pass the csrfToken to the view
  res.render('send', { csrfToken: req.csrfToken() });
});

app.post('/process', parseForm, csrfProtection, function(req, res) {
  res.send('data is being processed');
});

app.listen(3000);

在網頁上,你需要創建一個隱藏輸入域,將CSRF令牌保存在該輸入域中,例如:

<form action="/process" method="POST">
  <input type="hidden" name="_csrf" value="https://www.cnblogs.com/frontworld/archive/2021/01/31/{{csrfToken}}">

  Favorite color: <input type="text" name="favoriteColor">
  <button type="submit">Submit</button>
</form>

如果使用的是AJAX請求,那么CSRF令牌可以通過請求頭(header)來傳遞,

var token = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
  headers: {
    'CSRF-Token': token
  }

8. 拒絕服務

拒絕服務或DOS攻擊,可以讓攻擊者通過破壞系統,使系統被迫關閉服務或用戶無法訪問服務,攻擊者通常會向系統發送大量的流量和請求,從而增加服務器CPU和記憶體負載,導致系統崩潰,為了緩解Node.js應用程式中的DOS攻擊,首先是要識別此類事件, 我強烈建議將這兩個模塊集成到系統中,

  • Account lockout - 在n次嘗試失敗后,將帳戶或IP地址鎖定一段時間(例如24小時?)
  • Rate limiting - 限制用戶在特定時間段內只能請求系統n次,例如,單個用戶每分鐘只能請求3次,

正則運算式拒絕服務攻擊(ReDOS)是DOS攻擊的一種,攻擊者利用系統中正則運算式的設計缺陷或計算復雜度來大量消耗服務器的系統資源,造成服務器的服務中斷或停止,

我們可以使用一些工具來檢查有風險的正則運算式,從而避免這些正則運算式的使用,例如這個工具:

https://github.com/davisjam/vuln-regex-detector

9. 依賴關系驗證

我們在專案中都使用了大量的依賴項,我們還需要檢查并驗證這些依賴關系,以確保整個專案的安全性,NPM已經具有這樣的審核功能來查找專案的漏洞,只需在源代碼目錄中運行下面的命令即可:

npm audit

要修復漏洞,可以運行此命令:

npm audit fix

您也可以先進行dry run來檢查修復程式,然后再將其應用到專案中,

npm audit fix --dry-run --json

10. HTTP安全頭資訊

HTTP提供了一些安全頭資訊,可以防止常見的攻擊,如果使用的是Express框架,則可以使用helmet模塊,1行代碼就可以啟用所有安全頭,

npm install helmet --save

下面來看看如何使用:

const express = require("express"); 
const helmet = require("helmet");  
const app = express(); 
app.use(helmet());  
//...

這將啟用以下HTTP頭:

  • Strict-Transport-Security
  • X-frame-Options
  • X-XSS-Protection
  • X-Content-Type-Protection
  • Content-Security-Policy
  • Cache-Control
  • Expect-CT
  • Disable X-Powered-By

這些HTTP頭可防止惡意用戶的各種攻擊,例如點擊劫持,跨站點腳本攻擊等,

(本文完)

公眾號 - 前端新世界

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/255107.html

標籤:其他

上一篇:原型鏈

下一篇:原型鏈

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more