C++ 安全性:2024 年防范 SQL 注入和 XSS 攻击

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

当 C++ 遇上 Web:为什么安全是您的首要难题

\n\n

您有没有想过,为什么黑客如此喜欢 C++ 应用程序?不,不是因为代码复杂。而是因为在追求性能的过程中,开发者常常忘记了C++ 安全性。并因此付出用户数据、声誉和金钱的代价。

\n\n

想象一下:您编写了一个出色的 C++ 服务器,处理请求快如闪电。但一个未转义的输入——攻击者就能窃取整个数据库。或者更糟的是,插入一个脚本,窃取所有网站访问者的会话。熟悉吗?如果不熟悉——太好了,说明您及时阅读了这篇文章。

\n\n

在本材料中,我们将分析两种最危险的 Web 应用程序攻击——SQL 注入和跨站脚本攻击 (XSS)——并展示如何在 C++ 中防范它们。没有魔法,只有真实的代码示例。开始吧。

\n\n

SQL 注入:黑客如何将您的查询变成武器

\n\n

SQL 注入是指攻击者在输入字段(例如登录名或搜索查询)中插入一段 SQL 代码。如果您的应用程序盲目地将此输入拼接到查询中,那么数据库将执行类似 DROP TABLE users 的操作,而不是按名称查找用户。或者更可怕的是,泄露所有密码。

\n\n

新手典型错误(以及如何避免)

\n\n

看看这段代码。它看起来无害,但这是一颗定时炸弹:

\n\n
// 危险!永远不要这样做\nstd::string username = getUserInput(); // 用户输入了:' OR '1'='1\nstd::string query = "SELECT * FROM users WHERE username = '" + username + "'";\n// 结果:SELECT * FROM users WHERE username = '' OR '1'='1'\n// 将返回所有用户!
\n\n

看到问题了吗?如果用户输入 ' OR '1'='1,查询将返回整个表。如果输入 '; DROP TABLE users; --,那么再见,数据库。

\n\n

正确方法:参数化查询

\n\n

在 C++ 中防范 SQL 注入唯一可靠的方法是使用参数化查询。数据库本身会区分代码和数据。以下是使用 libpqxx(用于 PostgreSQL)或 MySQL Connector/C++ 库的实现方式:

\n\n
#include <iostream>\n#include <pqxx/pqxx> // libpqxx 用于 PostgreSQL\n\nvoid safeQuery(const std::string& username) {\n    try {\n        pqxx::connection conn("dbname=mydb user=myuser password=mypass");\n        pqxx::work txn(conn);\n        \n        // 参数化查询:$1 是参数\n        std::string query = "SELECT * FROM users WHERE username = $1";\n        pqxx::result result = txn.exec_params(query, username);\n        \n        for (auto row : result) {\n            std::cout << "User: " << row["username"].c_str() << std::endl;\n        }\n        txn.commit();\n    } catch (const std::exception &e) {\n        std::cerr << "Error: " << e.what() << std::endl;\n    }\n}\n\nint main() {\n    std::string input;\n    std::cout << "Enter username: ";\n    std::getline(std::cin, input);\n    safeQuery(input);\n    return 0;\n}
\n\n

请注意:我们使用 txn.exec_params 而不是字符串拼接。数据库会自动转义特殊字符。即使输入 ' OR '1'='1,它也会被视为字符串,而不是 SQL 命令的一部分。

\n\n

如果使用原生 SQLite 怎么办?

\n\n

即使使用 SQLite,也可以安全地操作。使用 sqlite3_prepare_v2 和 sqlite3_bind_text:

\n\n
#include <sqlite3.h>\n#include <iostream>\n\nvoid safeSQLiteQuery(sqlite3* db, const std::string& username) {\n    sqlite3_stmt* stmt;\n    const char* sql = "SELECT * FROM users WHERE username = ?";\n    \n    if (sqlite3_prepare_v2                

博客

书籍推荐