UNPKG

@aikidosec/firewall

Version:

Zen by Aikido is an embedded Web Application Firewall that autonomously protects Node.js apps against common and critical attacks

92 lines (91 loc) 4.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MySQL2 = void 0; const Context_1 = require("../agent/Context"); const wrapExport_1 = require("../agent/hooks/wrapExport"); const isPlainObject_1 = require("../helpers/isPlainObject"); const wrap_1 = require("../helpers/wrap"); const checkContextForSqlInjection_1 = require("../vulnerabilities/sql-injection/checkContextForSqlInjection"); const SQLDialectMySQL_1 = require("../vulnerabilities/sql-injection/dialects/SQLDialectMySQL"); class MySQL2 { constructor() { this.dialect = new SQLDialectMySQL_1.SQLDialectMySQL(); } inspectQuery(operation, args) { const context = (0, Context_1.getContext)(); if (!context) { return undefined; } if (args.length > 0) { if (typeof args[0] === "string" && args[0].length > 0) { const sql = args[0]; return (0, checkContextForSqlInjection_1.checkContextForSqlInjection)({ operation: operation, sql: sql, context: context, dialect: this.dialect, }); } if ((0, isPlainObject_1.isPlainObject)(args[0]) && args[0].sql && typeof args[0].sql === "string") { const sql = args[0].sql; return (0, checkContextForSqlInjection_1.checkContextForSqlInjection)({ operation: operation, sql: sql, context: context, dialect: this.dialect, }); } } return undefined; } // This function is copied from the OpenTelemetry MySQL2 instrumentation (Apache 2.0 license) // https://github.com/open-telemetry/opentelemetry-js-contrib/blob/21e1331a29e06092fb1e460ca99e0c28b1b57ac4/plugins/node/opentelemetry-instrumentation-mysql2/src/utils.ts#L150 getConnectionPrototypeToInstrument(connection) { const connectionPrototype = connection.prototype; const basePrototype = Object.getPrototypeOf(connectionPrototype); // mysql2@3.11.5 included a refactoring, where most code was moved out of the `Connection` class and into a shared base // so we need to instrument that instead, see https://github.com/sidorares/node-mysql2/pull/3081 // This checks if the functions we're instrumenting are there on the base - we cannot use the presence of a base // prototype since EventEmitter is the base for mysql2@<=3.11.4 if (typeof (basePrototype === null || basePrototype === void 0 ? void 0 : basePrototype.query) === "function" && typeof (basePrototype === null || basePrototype === void 0 ? void 0 : basePrototype.execute) === "function") { return basePrototype; } // otherwise instrument the connection directly. return connectionPrototype; } wrap(hooks) { const wrapConnection = (exports, pkgInfo, isPromise) => { const connectionPrototype = this.getConnectionPrototypeToInstrument(isPromise ? exports.PromiseConnection : exports.Connection); if (!(0, wrap_1.isWrapped)(connectionPrototype.query)) { // Wrap connection.query (0, wrapExport_1.wrapExport)(connectionPrototype, "query", pkgInfo, { kind: "sql_op", inspectArgs: (args) => this.inspectQuery("mysql2.query", args), }); } if (!(0, wrap_1.isWrapped)(connectionPrototype.execute)) { // Wrap connection.execute (0, wrapExport_1.wrapExport)(connectionPrototype, "execute", pkgInfo, { kind: "sql_op", inspectArgs: (args) => this.inspectQuery("mysql2.execute", args), }); } }; const pkg = hooks.addPackage("mysql2"); // For all versions of mysql2 newer than 3.0.0 pkg .withVersion("^3.0.0") .onRequire((exports, pkgInfo) => wrapConnection(exports, pkgInfo, false)); // For all versions of mysql2 newer than / equal 3.11.5 // Reason: https://github.com/sidorares/node-mysql2/pull/3081 pkg .withVersion("^3.11.5") .onFileRequire("promise.js", (exports, pkgInfo) => { return wrapConnection(exports, pkgInfo, true); }); } } exports.MySQL2 = MySQL2;