Microsoft Access
Microsoft Access is a database management system (DBMS) that combines the relational Microsoft Jet Database Engine with a graphical user interface and software-development tools. (Wikipedia)
Manipulating the Access object model via code -- either with Access-hosted VBA, or with some external code -- opens up the possibility of SQL injection:
Using the standard COM data access libraries -- DAO and ADO. Note that the Access object model has shortcuts to objects in the DAO and ADO object models for the current Access database:
- DAO.Database: Application.CurrentDb and Application.CodeDb
ADODB.Connection: CurrentProject.AccessConnection, CurrentProject.Connection, CodeProject.AccessConnection, CodeProject.Connection
Preventing SQL injection while using objects from these libraries is described here.
- RecordSource property of a form or report -- the table name, query name or
SELECT
statement which returns the set of records to which the form/report is bound - RowSource property of a ListBox or ComboBox -- tells Access how to provide a list of values to the control; can be a
SELECT
statement - RowSource property of a field in a table or query -- part of the definition of the default UI control used for the field; works like ListBox.RowSource / ComboBox.RowSource.
- DoCmd.RunSQL
If an SQL statement is concatenated from user input or other strings, and used with one of the above properties / methods, this is vulnerable to SQL injection:
' VBA example
Dim frm As Form
Set frm = Forms!frmStudents
frm.RecordSource = "SELECT * FROM Students WHERE FirstName = '" & InputBox("Enter student's first name") & "'"
If the user inputs ' OR '1
into the InputBox
, all the records from Students
will be returned.
Injection in contexts which support expressions
Even without VBA, there are a number of contexts where Access allows expressions, such as function calls and string
concatenations. If a function expects SQL in one or more of its arguments (like the built-in domain aggregate functions
-- DCount
, DMin
, DLookup
), concatenating user input into a value for the function argument is vulnerable to SQL
injection. For example, using the
If
macro action and the
DCount
domain aggregate function:
If the user inputs ' OR '1
then the expression will always evaluate to True
(as long as there are records in the Users
table).
Note that any function which expects some form of structured text (e.g. JSON, XML, command line execution) may be similarly vulnerable when being passed a string concatenated from user input:
' VBA code
Shell Chr(34) & Forms!RunCommand!CommandLine & Chr(34)
This sort of function-argument vulnerability can happen in any context which supports using expressions:
- Saved queries
- VBA code
- Macro actions which support expressions
- Property values that support expressions
- RecordSource / RowSource / DoCmd.RunSQL, which take SQL with such expressions
Referencing globally available state
Usually, string concatenation can be avoided altogether, by referencing globally available state directly. The following types of state are available:
value of a control on a currently open form or report
sql SELECT * FROM Students WHERE FirstName = Forms!Students!FirstName
TempVars -- globally available temporary variables
sql SELECT * FROM Students WHERE FirstName = TempVars!StudentFirstName
TempVars are set using VBA:
vb TempVars!StudentFirstName = "Robert' OR '1"
or the SetTempVar macro action.
VBA functions defined in one of the database modules
sql SELECT * FROM Students WHERE FirstName = GetStudentFirstName()
The function can wrap a module-level variable:
vb Private StudentFirstName As String Function GetStudentFirstName() As String GetStudentFirstName = StudentFirstName End Function Sub SetStudentFirstName(newFirstName As String) StudentFirstName = newFirstName End Sub
or a function-level
Static
variable, in which case you must use an optional parameter to set the value:vb Function GetStudentFirstName(Optional ByVal newFirstName As Variant) As String Static studentFirstName As String If Not IsMissing(newFirstName) Then studentFirstName = newFirstName GetStudentFirstName = studentFirstName End Function
parameters set with
DoCmd.SetParameter
(cannot be used in all contexts, see below)
These are available in the following contexts:
- saved queries
- the RecordSource property of a form or report
- the RowSource property of a form/report listbox or combobox, or of a table / query field
- domain aggregate functions
- Expressions within macros
- filters passed in to the
DoCmd.OpenForm
andDoCmd.OpenReport
methods DoCmd.RunSQL
Note that parameters set with SetParameter
cannot be used by filters or DoCmd.RunSQL
Sources
1. How do I use parameters in VBA in the different contexts in Microsoft Access? (StackOverflow) 2. SQL injection and Access macros (StackOverflow)