Merge pull request #10752 from RasmusWL/pymssql

Python: DB Modeling: Add `pymssql` and `executemany` in general
This commit is contained in:
Rasmus Wriedt Larsen
2022-10-11 15:55:04 +02:00
committed by GitHub
11 changed files with 85 additions and 16 deletions

View File

@@ -37,6 +37,7 @@ private import semmle.python.frameworks.Peewee
private import semmle.python.frameworks.Psycopg2
private import semmle.python.frameworks.Pycurl
private import semmle.python.frameworks.Pydantic
private import semmle.python.frameworks.Pymssql
private import semmle.python.frameworks.PyMySQL
private import semmle.python.frameworks.Requests
private import semmle.python.frameworks.RestFramework
@@ -51,6 +52,6 @@ private import semmle.python.frameworks.Tornado
private import semmle.python.frameworks.Twisted
private import semmle.python.frameworks.Ujson
private import semmle.python.frameworks.Urllib3
private import semmle.python.frameworks.Xmltodict
private import semmle.python.frameworks.Yaml
private import semmle.python.frameworks.Yarl
private import semmle.python.frameworks.Xmltodict

View File

@@ -21,17 +21,11 @@ private import semmle.python.frameworks.PEP249
* - https://dev.mysql.com/doc/connector-python/en/connector-python-example-connecting.html
*/
private module Mysql {
// ---------------------------------------------------------------------------
// mysql
// ---------------------------------------------------------------------------
/** Provides models for the `mysql` module. */
module MysqlMod {
/**
* The mysql.connector module
* See https://dev.mysql.com/doc/connector-python/en/connector-python-example-connecting.html
*/
class MysqlConnector extends PEP249::PEP249ModuleApiNode {
MysqlConnector() { this = API::moduleImport("mysql").getMember("connector") }
}
/**
* The mysql.connector module
* See https://dev.mysql.com/doc/connector-python/en/connector-python-example-connecting.html
*/
class MysqlConnector extends PEP249::PEP249ModuleApiNode {
MysqlConnector() { this = API::moduleImport("mysql").getMember("connector") }
}
}

View File

@@ -0,0 +1,25 @@
/**
* Provides classes modeling security-relevant aspects of the `pymssql` PyPI package.
* See https://pypi.org/project/pymssql/
*/
private import python
private import semmle.python.dataflow.new.DataFlow
private import semmle.python.dataflow.new.RemoteFlowSources
private import semmle.python.Concepts
private import semmle.python.ApiGraphs
private import semmle.python.frameworks.PEP249
/**
* Provides models for the `pymssql` PyPI package.
* See https://pypi.org/project/pymssql/
*/
private module Pymssql {
/**
* A model of `pymssql` as a module that implements PEP 249, providing ways to execute SQL statements
* against a database.
*/
class PymssqlPEP249 extends PEP249::PEP249ModuleApiNode {
PymssqlPEP249() { this = API::moduleImport("pymssql") }
}
}

View File

@@ -146,7 +146,7 @@ module PEP249 {
* Note: while `execute` method on a connection is not part of PEP249, if it is used, we
* recognize it as an alias for constructing a cursor and calling `execute` on it.
*
* See https://www.python.org/dev/peps/pep-0249/#id15.
* See https://peps.python.org/pep-0249/#execute.
*/
private DataFlow::TypeTrackingNode execute(DataFlow::TypeTracker t) {
t.startInAttr("execute") and
@@ -161,14 +161,44 @@ module PEP249 {
* Note: while `execute` method on a connection is not part of PEP249, if it is used, we
* recognize it as an alias for constructing a cursor and calling `execute` on it.
*
* See https://www.python.org/dev/peps/pep-0249/#id15.
* See https://peps.python.org/pep-0249/#execute.
*/
DataFlow::Node execute() { execute(DataFlow::TypeTracker::end()).flowsTo(result) }
/** A call to the `execute` method on a cursor (or on a connection). */
/**
* A call to the `execute` method on a cursor or a connection.
*
* See https://peps.python.org/pep-0249/#execute
*
* Note: While `execute` method on a connection is not part of PEP249, if it is used, we
* recognize it as an alias for constructing a cursor and calling `execute` on it.
*/
private class ExecuteCall extends SqlExecution::Range, DataFlow::CallCfgNode {
ExecuteCall() { this.getFunction() = execute() }
override DataFlow::Node getSql() { result in [this.getArg(0), this.getArgByName("sql")] }
}
private DataFlow::TypeTrackingNode executemany(DataFlow::TypeTracker t) {
t.startInAttr("executemany") and
result in [Cursor::instance(), Connection::instance()]
or
exists(DataFlow::TypeTracker t2 | result = executemany(t2).track(t2, t))
}
private DataFlow::Node executemany() { executemany(DataFlow::TypeTracker::end()).flowsTo(result) }
/**
* A call to the `executemany` method on a cursor or a connection.
*
* See https://peps.python.org/pep-0249/#executemany
*
* Note: While `executemany` method on a connection is not part of PEP249, if it is used, we
* recognize it as an alias for constructing a cursor and calling `executemany` on it.
*/
private class ExecutemanyCall extends SqlExecution::Range, DataFlow::CallCfgNode {
ExecutemanyCall() { this.getFunction() = executemany() }
override DataFlow::Node getSql() { result in [this.getArg(0), this.getArgByName("sql")] }
}
}

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added model of `executemany` calls on PEP-249 compliant database APIs, resulting in additional sinks for `py/sql-injection`.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added model of `pymssql` PyPI package as a SQL interface following PEP249, resulting in additional sinks for `py/sql-injection`.

View File

@@ -0,0 +1,2 @@
import python
import experimental.meta.ConceptsTest

View File

@@ -0,0 +1,6 @@
import pymssql
connection = pymssql.connect(host="localhost", user="user", password="passwd")
cursor = connection.cursor()
cursor.execute("some sql", (42,)) # $ getSql="some sql"
cursor.executemany("some sql", [(42,)]) # $ getSql="some sql"

View File

@@ -3,3 +3,4 @@ connection = pymysql.connect(host="localhost", user="user", password="passwd")
cursor = connection.cursor()
cursor.execute("some sql", (42,)) # $ getSql="some sql"
cursor.executemany("some sql", [(42,)]) # $ getSql="some sql"