当 C++ 遇上 Web:为什么安全是您的首要难题
\n\n您有没有想过,为什么黑客如此喜欢 C++ 应用程序?不,不是因为代码复杂。而是因为在追求性能的过程中,开发者常常忘记了C++ 安全性。并因此付出用户数据、声誉和金钱的代价。
\n\n想象一下:您编写了一个出色的 C++ 服务器,处理请求快如闪电。但一个未转义的输入——攻击者就能窃取整个数据库。或者更糟的是,插入一个脚本,窃取所有网站访问者的会话。熟悉吗?如果不熟悉——太好了,说明您及时阅读了这篇文章。
\n\n在本材料中,我们将分析两种最危险的 Web 应用程序攻击——SQL 注入和跨站脚本攻击 (XSS)——并展示如何在 C++ 中防范它们。没有魔法,只有真实的代码示例。开始吧。
\n\nSQL 注入:黑客如何将您的查询变成武器
\n\nSQL 注入是指攻击者在输入字段(例如登录名或搜索查询)中插入一段 SQL 代码。如果您的应用程序盲目地将此输入拼接到查询中,那么数据库将执行类似 DROP TABLE users 的操作,而不是按名称查找用户。或者更可怕的是,泄露所有密码。
新手典型错误(以及如何避免)
\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在 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 命令的一部分。
如果使用原生 SQLite 怎么办?
\n\n即使使用 SQLite,也可以安全地操作。使用 sqlite3_prepare_v2 和 sqlite3_bind_text:
#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