Quando C++ encontra a web: por que a segurança é sua maior dor de cabeça
\n\nVocê já se perguntou por que os hackers amam tanto aplicações C++? Não, não porque o código é complexo. Mas porque, na busca por desempenho, os desenvolvedores frequentemente esquecem da segurança em C++. E pagam por isso com dados de usuários, reputação e dinheiro.
\n\nImagine: você escreveu um servidor incrível em C++ que processa requisições mais rápido que um raio. Mas uma única entrada sem escape — e um invasor rouba todo o banco de dados. Ou, pior ainda, insere um script que rouba as sessões de todos os visitantes do site. Familiar? Se não — ótimo, significa que você está lendo este artigo na hora certa.
\n\nNeste material, vamos analisar os dois ataques mais perigosos em aplicações web — SQL Injection e Cross-Site Scripting (XSS) — e mostrar como se proteger deles especificamente em C++. Sem mágica, com exemplos reais de código. Vamos lá.
\n\nSQL Injection: como hackers transformam sua consulta em arma
\n\nSQL Injection é quando um invasor insere em um campo de entrada (como login ou busca) um trecho de código SQL. Se sua aplicação simplesmente insere essa entrada na consulta, em vez de buscar um usuário pelo nome, o banco executará algo como DROP TABLE users. Ou, pior ainda, exibirá todas as senhas.
Erro típico de iniciante (e como evitá-lo)
\n\nVeja este código. Parece inofensivo, mas é uma bomba-relógio:
\n\n// PERIGOSO! Nunca faça isso\nstd::string username = getUserInput(); // usuário digitou: ' OR '1'='1\nstd::string query = "SELECT * FROM users WHERE username = '" + username + "'";\n// Resultado: SELECT * FROM users WHERE username = '' OR '1'='1'\n// Retornará todos os usuários!\n\nPercebeu o problema? Se o usuário digitar ' OR '1'='1, a consulta retornará toda a tabela. E se digitar '; DROP TABLE users; --, então goodbye, banco de dados.
Abordagem correta: consultas parametrizadas
\n\nA única maneira confiável de proteção contra SQL Injection em C++ é usar consultas parametrizadas. O banco de dados diferencia automaticamente código de dados. Veja como fica com a biblioteca libpqxx (para PostgreSQL) ou MySQL Connector/C++:
\n\n#include <iostream>\n#include <pqxx/pqxx> // libpqxx para 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 // Consulta parametrizada: $1 é o parâmetro\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\nObserve: usamos txn.exec_params em vez de concatenação de strings. O banco de dados escapa os caracteres especiais automaticamente. Mesmo que o usuário digite ' OR '1'='1, isso será tratado como string, e não como parte do comando SQL.
E se você estiver usando SQLite puro?
\n\nMesmo com SQLite é possível trabalhar com segurança. Use sqlite3_prepare_v2 e 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