Security Considerations for MLE

Besides the use of account privileges, MLE employs several other methods to ensure a high level of security.

Topics

MLE_PROG_LANGUAGES Initialization Parameter

A new initialization parameter, MLE_PROG_LANGUAGES, allows administrators to enable and disable Multilingual Engine completely or selectively enable certain languages. It takes the values ALL, JAVASCRIPT, or OFF and it can be set at multiple levels:

  • Container Database (CDB)

  • Pluggable Database (PDB)

  • Database session

If the parameter is set to OFF at CDB level, it cannot be enabled at PDB or session level. The same logic applies for PDB and session level: if MLE is disabled at the PDB level, it cannot be enabled at session level.

Note:

In Oracle Database 23ai, MLE supports JavaScript as its sole language. Setting the parameter to ALL or JAVASCRIPT has the same effect.

Note:

Setting MLE_PROG_LANGUAGES to OFF prevents the execution of JavaScript code in the database, it does not prevent the creation or modification of existing code.

See Also:

Oracle Database Reference for more information about MLE_PROG_LANGUAGES

Execution Contexts

When executing JavaScript code in the database, MLE uses execution contexts to isolate runtime state such as global variables and other important information. Execution contexts are created implicitly when using modules and environments and explicitly when using DBMS_MLE.

Regardless of the choice of JavaScript invocation, execution contexts are designed to prevent information leak.

The scope of JavaScript state never exceeds the lifetime of a database session. As soon as the session ends, either gracefully or forcefully, session state is discarded. If state needs to be preserved between sessions, you must persist it by storing it in a schema. If needed, state can be discarded by calling DBMS_SESSION.reset_package().

As an additional security measure, you can optionally specify the use of a restricted execution context, which disallows access to the database state. The PURE keyword is used in the creation of environments and in inline call specifications to indicate the use of a restricted context. An environment created using PURE can be referenced in module call specifications and using DBMS_MLE. PURE execution serves as a method to isolate certain code, such as third-party JavaScript libraries, from the database itself. This isolation can reduce the attack surface of supply chain attacks, in which access to the database state is a security concern.

See Also:

Runtime State Isolation

An MLE call specification is a PL/SQL unit referencing a function in an MLE module with an optional MLE environment attached. When you invoke a call specification in a session, the corresponding MLE module is loaded, the optional environment is applied, and the function specified in the call specification's signature clause is executed.

Before execution can begin, a corresponding execution context must be created (implicitly). Whether a new execution context is created or an existing context is reused depends on multiple factors, specifically:

  • The MLE module referenced in the call specification

  • The corresponding MLE environment

  • The database user executing the call specification

Separate execution contexts are created to prevent information leak as well as undesired side effects such as global variables in a module being overwritten by accident.

With each invocation of a call specification, additional execution contexts are created. This is done so that modules cannot interfere with one another.

The main criteria for creating execution contexts in a user session are the MLE module name and the corresponding MLE environment. Call specifications referring to different combinations of MLE module and environment lead to different individual execution contexts being created.

Further separation between execution contexts is performed based on the user invoking the call specification.

Example 10-1 Runtime State Isolation Scenario

This example provides a sample scenario for runtime state isolation. Database user USER1 creates the following MLE schema objects:

CREATE OR REPLACE MLE MODULE isolationMod LANGUAGE JAVASCRIPT AS

let id;      // global variable

export function doALotOfWork() {
  // a dummy function simulating a lot of work
  // the focus is on modifying a global variable

  id = 10;
}

export function getId() {

  return (id === undefined ? -1 : id)
}
/

CREATE OR REPLACE MLE ENV isolationEnv;

CREATE OR REPLACE PACKAGE context_isolation_package AS

  -- initialise runtime state
  procedure doALotOfWork as 
    mle module isolationMod 
    signature 'doALotOfWork()';
  
  -- access a global variable (part of session state)
  function getId return number as 
    mle module isolationMod 
    signature 'getId()';

  -- same function signature as before but referencing an environment
  function getIdwEnv return number as 
    mle module isolationMod 
    env isolationEnv
    signature 'getId()';
END;
/

When USER1, the owner of the MLE module, environment, and call specification (package), calls context_isolation_package.doALotOfWork(), the global variable (id) is initialized to 10.

BEGIN
    context_isolation_package.doALotOfWork();
END;
/

Because context_isolation_package.getId() references the same MLE module and the same (default) environment as context_isolation_package.doALotOfWork(), the user's session has access to the global variable:

SELECT CONTEXT_ISOLATION_PACKAGE.getId;

     GETID
----------
        10

When the combination of user, MLE module, and environment change, a new execution context is created. Although context_isolation_package.getIdwEnv() references the same MLE module as getID() and the user doesn't change, the function cannot retrieve the value of the global variable from the previously created execution context:

SELECT CONTEXT_ISOLATION_PACKAGE.getIdwEnv;

 GETIDWENV
----------
        -1

A value of -1 indicates that the global variable in the JavaScript module was found to be uninitialized.

If USER1, as the owner of the MLE call specification, grants the execute privilege on the package to another user, let's say USER2, a different execution context is created for USER2 even though the same function is called:

GRANT EXECUTE ON CONTEXT_ISOLATION_PACKAGE TO user2;

When USER2 tries to read the value of the ID, a new context is created and the return value indicating an uninitialized context is returned:

SELECT user1.CONTEXT_ISOLATION_PACKAGE.getid;

     GETID
----------
        -1

In this example, module and environment are identical between USER1 and USER2 as per the call specification. However, the fact that the function is called by a different user causes a new execution context to be created.

Database Security Model

The fewer privileges granted to program units, accounts, and roles, the less likely it is for them to be misused. As with every application, the principle of granting only the minimum number of necessary privileges should be followed. This is especially true in higher-tier environments like production. Technologies such as Privilege Analysis can be used to track down unnecessary privileges, allowing you to revoke them after careful regression testing.

Each MLE call specification is created within its own security context. The context includes information such as:

  • The value of the AUTHID clause (definer or invoker)

  • Whether or not privileges are inherited in invoker's rights calls

  • Code Based Access Control

  • Current user

  • The qualified schema name

  • Enabled Roles and Privileges in the absence of code based access control (CBAC) and invoker's rights

The combination of these attributes forms the security context of a code unit such as a MLE call specification or module. Note that no such security context exists for the JavaScript code stored in an MLE module.

PL/SQL allows you to easily change these attributes for each PL/SQL unit. A procedure can be executed with the invoker's rights or the definer's rights, roles can be attached to PL/SQL units, and cross-schema (execute) grants are commonplace. With each execution of a PL/SQL unit the security context may potentially change. This applies equally to MLE call specifications.

The situation is different with JavaScript code: the security context does not change for JavaScript-to-JavaScript calls. JavaScript functions do not have any notion of associated invoker's or definer's rights, or roles granted on the function itself. All of these apply only to (PL/SQL) call specifications.

JavaScript executed using DBMS_MLE is a little more strict when it comes to its security context. The combination of currently active user, roles/privileges, and schema in effect are recorded at the time the execution context is created by calling DBMS_MLE.create_context(). This combination must not change until the JavaScript code is executed and the context is removed, or else an error is thrown.

See Also:

Oracle Database Security Guide for more information about Privilege Analysis

Considerations for Using MLE Call Specifications and Modules from Different Schemas

The same consideration that is used for other database applications written in, for example, PL/SQL apply for MLE JavaScript code as well. If a user is granted access to execute code from a schema other than their own, care needs to be taken to ensure the extent to which the code can use privileges of the calling user is appropriate.

Unlike PL/SQL, MLE JavaScript code stored in an MLE module is not associated with a particular set of roles, or any other notion of determining the security context in which the JavaScript code executes. From a high-level view, there are two important cases for cross-schema use of privileges:

  1. USER1 invokes a call specification located in USER2's schema. The AUTHID clause of the call specification in USER2's schema determines whether the code owned by USER2's schema executes with the privileges of the invoker (USER1) or definer (USER2). In case of an invoker's rights call specification, potentially attached roles (CBAC) and the setting of INHERIT PRIVILEGES determine the active roles and privileges in addition to those granted by USER1 by roles or direct grants.

  2. USER1 creates a call specification CallSpec_A for a module Module_A owned by USER1. CallSpec_A imports a JavaScript module Module_B owned by a different schema, USER2. The JavaScript code in Module_B is imported into an execution context created for USER1's call specification CallSpec_A. The JavaScript code in Module_B executes with the same privileges as any other JavaScript code in this execution such as in Module_A. USER1 must ensure that the code in Module_B is trustworthy and appropriate to execute with these privileges.

See Also:

Oracle Database Security Guide for more information about roles in definer's rights and invoker's rights PL/SQL units

Auditing MLE Operations in Oracle Database

Auditing is the monitoring and recording of configured database actions. As with any other auditable operations in Oracle Database, the use of MLE-related system privileges can be recorded.

Oracle provides the ORA_SECURECONFIG audit policy with the database. Starting with Oracle Database 23ai, the audit policy includes the use of the following MLE system privileges:

  • CREATE ANY MLE

  • ALTER ANY MLE

  • DROP ANY MLE

Administrators and security teams need to create and enable additional security policies if auditing the creation of MLE schema objects, including MLE modules, environments, and call specifications, is desired.

See Also:

Oracle Database Security Guide for more information about auditing in Oracle Database