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