
掌握ChatGPT插件與自定義GPT
Server running at http://${hostname}:${port}/
);
});
然后您可以轉(zhuǎn)到終端并使用以下命令運(yùn)行代碼:
node app.js
訪問 http://localhost:3000,您應(yīng)該會看到一條消息“Hello World”。
很簡單,對吧?
現(xiàn)在我們來簡單解釋一下什么是 SQL 注入。它是一種利用數(shù)據(jù)庫集成不充分和用戶輸入驗(yàn)證不完善而進(jìn)行的注入攻擊。
輸入平臺的惡意SQL指令可以到達(dá)ORM層,通過面向用戶的輸入字段直接進(jìn)入SQL數(shù)據(jù)庫,并接管整個(gè)系統(tǒng)。
SQL 注入攻擊的主要目的是操縱數(shù)據(jù)庫中的數(shù)據(jù)、迫使系統(tǒng)交出其數(shù)據(jù),或兩者兼而有之。
由于 SQL 注入攻擊以系統(tǒng)數(shù)據(jù)庫為目標(biāo),一旦成功,即可提供全部或部分訪問權(quán)限,因此影響可能非常巨大。因此,人們可以有理由相信這些漏洞非常復(fù)雜,并且只用于復(fù)雜的攻擊。但事實(shí)上,大多數(shù) SQL 注入攻擊并不是特別復(fù)雜或罕見。
事實(shí)上,情況恰恰相反。
為了說明這一點(diǎn),讓我們看一下針對允許用戶輸入的系統(tǒng)的 SQL 注入攻擊的典型實(shí)現(xiàn)。
想象一下,您在模型層或數(shù)據(jù)庫集成層中有代碼,您可以通過格式化以下 SQL 查詢命令來檢索用戶信息:
query = 'SELECT * FROM Users WHERE Email = "' + USERNAME + '" AND Pass = "' + PASSWORD + '";'
如您所見,這個(gè)簡單(且非常危險(xiǎn))的查詢命令搜索用戶表并檢索具有匹配憑據(jù)的用戶。
任何對 SQL 有基本了解的不良行為者都可以利用用戶輸入缺乏驗(yàn)證的情況,輸入開發(fā)人員未預(yù)見到有效用戶提供的值。
例如,如果你在該查詢中輸入如下內(nèi)容,系統(tǒng)將把表中的所有用戶交給攻擊者:
" or ""="
現(xiàn)在應(yīng)該清楚的是,這種攻擊的復(fù)雜性和復(fù)雜性都很少。它依靠簡單的輸入驗(yàn)證來生存和消亡。然而,這并不意味著 SQL 注入攻擊不能很復(fù)雜,也不能成為更強(qiáng)大和更復(fù)雜的攻擊的一部分。
除了我們之前探討過的“””=”””攻擊外,還有幾種注入攻擊形式也很常見。攻擊者可以利用這些攻擊,在充分了解數(shù)據(jù)庫結(jié)構(gòu)并反復(fù)試驗(yàn)的情況下,成功攻擊易受攻擊的系統(tǒng)。
現(xiàn)在您已經(jīng)對 SQL 注入攻擊如何利用您的系統(tǒng)有了基本的了解,讓我們來看看一些簡單的預(yù)防措施。
首先,有必要解決在面向用戶的前端代碼中實(shí)現(xiàn)的用戶輸入驗(yàn)證問題。此驗(yàn)證將成為您抵御不良行為者的第一道防線,并充當(dāng)用戶的響應(yīng)機(jī)制。
我們需要確保用戶提供的值具有相應(yīng)的范圍和清理功能。這意味著,例如,如果輸入字段用于接收電子郵件,則它不允許用戶提交包含無效電子郵件的表單 – 或者根本沒有值。
這個(gè)想法的簡單實(shí)現(xiàn)如下:
const email_regex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
function validate(email: string): boolean {
if (email == "") {
alert("Email must be filled out");
return false;
} else if (email_regex.test(email.toLowerCase()) == false) {
alert("Email must be valid");
return false;
}
return true;
}
當(dāng)然,我們可以通過輸入掩碼和響應(yīng)式表單樣式來擴(kuò)展這種方法。這可以告知用戶提供的值無效,從而改善用戶體驗(yàn)。
其次,我們必須在應(yīng)用程序級別實(shí)現(xiàn)輸入驗(yàn)證,因?yàn)榇蠖鄶?shù)業(yè)務(wù)層都存在于該級別。此策略可以簡單到在到達(dá)模型層之前重新驗(yàn)證并在適當(dāng)?shù)那闆r下清理用戶輸入。
此外,添加“node-mysql”等第三方庫可以提供更強(qiáng)大的保護(hù)層來抵御這些攻擊。
最后,一旦解決了頂層問題,我們就可以著手保護(hù)數(shù)據(jù)庫層的安全。
我們需要做的就是實(shí)現(xiàn)所謂的查詢占位符或名稱占位符。這些占位符(此處用 ? 符號表示)指示接口層自動轉(zhuǎn)義傳遞給它的輸入并驗(yàn)證其類型和格式,以使其符合數(shù)據(jù)庫結(jié)構(gòu)。
例如,如果給一個(gè)期望整數(shù)的列提供一個(gè)字符串,則查詢將中止并引發(fā)異常。
假設(shè)您有一種檢索敏感信息并傳遞未經(jīng)驗(yàn)證的用戶輸入的方法。
app.post("/records", (request, response) => {
const data = request.body;
const query = SELECT * FROM health_records WHERE id = (${data.id})
;
// === MySQL ===
const mysql = require('mysql');
const mycon = mysql.createConnection({ host: host, user: user, password: pass, database: db });
mycon.connect(function(err) {
mycon.query(query, (err, rows) => {
if(err) throw err;
response.json({data:rows});
});
});
});
這段代碼可能會引發(fā)很多麻煩。
但解決這個(gè)問題非常簡單。
app.post("/records", (request, response) => {
const data = request.body;
// === MySQL ===
const mysql = require('mysql');
const mycon = mysql.createConnection({ host: host, user: user, password: pass, database: db });
mycon.connect(function(err) {
mycon.query('SELECT * FROM health_records WHERE id = ?', [data.id], (err, res) => {
if(err) throw err;
response.json({data:rows});
});
});
});
如您所見,查詢指令現(xiàn)在使用 ? 字符作為占位符來提供參數(shù)。這告訴查詢庫清理并驗(yàn)證輸入的值以防止注入。這是一個(gè)微妙的變化,但它對我們代碼的安全性有重大影響。
我們探討了 SQL 注入并提供了一些示例,我們可以這樣總結(jié)最佳策略:
遵守正確的 SQL 注入預(yù)防措施并不復(fù)雜。
由于我們擁有穩(wěn)健且久經(jīng)考驗(yàn)的方法和庫,我們可以毫不費(fèi)力地提供可靠的保護(hù)。但是,根據(jù)代碼庫的大小和復(fù)雜性,您的里程可能會有所不同。
盡管如此,這種保護(hù)所需的時(shí)間投入將在未來幾年帶來回報(bào)。
文章來源:Typescript SQL Injection Guide: Examples and Prevention