如何获取文心一言API密钥(分步指南)
Typescript SQL注入指南:示例和预防
在本文中,我们将在基于 Typescript 的应用程序环境中讨论 SQL 注入。我们的目标是研究什么是 SQL 注入、它如何影响您组织的基础设施以及您可以采取哪些措施来减轻其损害。在本文结束时,您应该全面了解 SQL 注入、安全问题如何影响您的代码以及如何正确解决这些问题。
我们将使用 NodeJS 作为示例项目的首选平台,并使用 Typescript 作为编码语言。
注意:本文面向 NodeJS 和 Typescript 开发人员。因此,我们希望您对 NodeJS 开发堆栈有基本的了解,并具有使用 Typescript 进行编码的经验。如果您尚未涉足其中,请参阅Typescript 网站以获取更多信息。尽管如此,SQL 注入在各个平台和语言中都相当一致,因此无论如何您都应该能够从本文中获得一些价值。
从 NodeJS 和 Typescript 开始
在我们进入 SQL 注入之前,让我们准备一个简单的样板项目,以便您可以试用代码并完成即将学习的内容。
首先,确保已安装 NodeJS。你可以在 macOS 中运行以下命令来执行此操作:
curl "https://nodejs.org/dist/latest/node-${VERSION:-$(wget -qO- https://nodejs.org/dist/latest/ | sed -nE 's|.*>node-(.*)\.pkg</a>.*|\1|p')}.pkg" > "$HOME/Downloads/node-latest.pkg" && sudo installer -store -pkg "$HOME/Downloads/node-latest.pkg" -target "/"
或者,您可以使用 Brew 通过以下命令进行安装:
brew install nodejs
如果您运行任何其他系统,您可以在 NodeJS 网站上找到说明。
现在,创建一个 NodeJS 项目非常简单。只需创建一个名为“nodejs_typescript_sample”的文件夹(您可以随意命名此文件夹)并导航到该文件夹。进入后,创建一个名为 app.js 的文件(这次我们建议您确实这样命名)并粘贴以下代码:
const http = require('http');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
然后您可以转到终端并使用以下命令运行代码:
node app.js
访问 http://localhost:3000,您应该会看到一条消息“Hello World”。
很简单,对吧?
什么是 SQL 注入?
现在我们来简单解释一下什么是 SQL 注入。它是一种利用数据库集成不充分和用户输入验证不完善而进行的注入攻击。
输入平台的恶意SQL指令可以到达ORM层,通过面向用户的输入字段直接进入SQL数据库,并接管整个系统。
SQL 注入攻击的主要目的是操纵数据库中的数据、迫使系统交出其数据,或两者兼而有之。
由于 SQL 注入攻击以系统数据库为目标,一旦成功,即可提供全部或部分访问权限,因此影响可能非常巨大。因此,人们可以有理由相信这些漏洞非常复杂,并且只用于复杂的攻击。但事实上,大多数 SQL 注入攻击并不是特别复杂或罕见。
事实上,情况恰恰相反。
SQL 注入示例
为了说明这一点,让我们看一下针对允许用户输入的系统的 SQL 注入攻击的典型实现。
想象一下,您在模型层或数据库集成层中有代码,您可以通过格式化以下 SQL 查询命令来检索用户信息:
query = 'SELECT * FROM Users WHERE Email = "' + USERNAME + '" AND Pass = "' + PASSWORD + '";'
如您所见,这个简单(且非常危险)的查询命令搜索用户表并检索具有匹配凭据的用户。
任何对 SQL 有基本了解的不良行为者都可以利用用户输入缺乏验证的情况,输入开发人员未预见到有效用户提供的值。
例如,如果你在该查询中输入如下内容,系统将把表中的所有用户交给攻击者:
" or ""="
现在应该清楚的是,这种攻击的复杂性和复杂性都很少。它依靠简单的输入验证来生存和消亡。然而,这并不意味着 SQL 注入攻击不能很复杂,也不能成为更强大和更复杂的攻击的一部分。
常见的 SQL 注入攻击
除了我们之前探讨过的“””=”””攻击外,还有几种注入攻击形式也很常见。攻击者可以利用这些攻击,在充分了解数据库结构并反复试验的情况下,成功攻击易受攻击的系统。
- 始终为真(或 ‘ 1=1 ‘)攻击
- 从用户中选择*,其中UserId = 105或1 = 1;
- 查询堆叠攻击
- SELECT * FROM products WHERE id = 10; DROP members–
- 数据泄露(或查询评论)攻击
- 从健康记录中选择 * 其中日期 = ’22/04/1999’;–‘ 并且 ID = 33
缓解 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});
});
});
});
如您所见,查询指令现在使用 ? 字符作为占位符来提供参数。这告诉查询库清理并验证输入的值以防止注入。这是一个微妙的变化,但它对我们代码的安全性有重大影响。
总结:如何防止 Typescript SQL 注入
我们探讨了 SQL 注入并提供了一些示例,我们可以这样总结最佳策略:
- 在视图级别实现输入验证和字段屏蔽。
- 确保您的模型层正确使用占位符。
- 避免使用可以访问数据库的不安全的包。
- 利用应用程序安全监控功能。
- 与您的团队一起执行安全政策和最佳实践。
遵守正确的 SQL 注入预防措施并不复杂。
由于我们拥有稳健且久经考验的方法和库,我们可以毫不费力地提供可靠的保护。但是,根据代码库的大小和复杂性,您的里程可能会有所不同。
尽管如此,这种保护所需的时间投入将在未来几年带来回报。
文章来源:Typescript SQL Injection Guide: Examples and Prevention