Auswahl  

Access Control Lists mit dbms_network_acl_admin 

Oracle
DBA:PL/SQL
RDBMS 12.x
14.12.18 (MP)
25.09.19 (MP)
PL/SQL , DBA, Firewall, dbms_network_acl_admin

Body

Viele Applikationen verwenden die Möglichkeiten zur Mailversendung aus Oracle heraus, sei es mit UTL_SMTP, sei es mit UTL_MAIL. Bis Version 10g reichte es, wenn der Eigentümer der Sende-Prozedur das EXECUTE-Recht auf das jeweilige Package hatte. Soll auf 11g migriert werden, so erfordert dies einen zusätzlichen administrativen Aufwand.

Mit Version 11g wurde nämlich das Sicherheitskonzept dahingehend erweitert, dass Netzwerkzugriffe über Access Control Lists (ACLs) freigegeben werden müssen. Das betrifft neben UTL_SMTP und UTL_MAIL auch die Packages UTL_TCP, UTL_HTTP und UTL_INADDR. Wenn ein entsprechender Aufruf erfolgt, ohne dass der Host bzw. Port explizit freigegeben wurde, so erfolgt nun die Fehlermeldung:

ORA-24247: Netzwerkzugriff von Zugriffskontrollliste (ACL) abgelehnt


Darüber hinaus wurden die angegebenen Packages auf Invoker Rights umgestellt, und auch entsprechende Prozeduren, die mit diesen Packages arbeiten, sollten mit AUTHID CURRENT_USER erstellt werden, um ein Unterlaufen der ACLs zu verhindern.

Am einfachsten kann der DBA ACLs über das Package DBMS_NETWORK_ACL_ADMIN verwalten. Zunächst muss eine ACL erstellt werden, wie in den folgenden Beispielen gezeigt:

Für SMTP (Email Versand über einen Email Server):

BEGIN
 DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE (host => '172.30.30.20',
 ace => xs$ace_type(privilege_list => xs$name_list('smtp'),
 principal_name => 'SCOTT',
 principal_type => xs_acl.ptype_db) );
END;
/

 

Oracle REST Verbindungen (ORDS) z.B. für APEX:

BEGIN
 DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE (host => '172.30.30.20',
 ace => xs$ace_type(privilege_list => xs$name_list('connect'),
 principal_name => 'APEX_190200',
 principal_type => xs_acl.ptype_db) );
END;
/

 

Für LDAP Verbindungen mit einem Microsoft AD (hier via APEX):

BEGIN
 DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE (host => '172.30.30.20',
 lower_port => 389,
 ace => xs$ace_type(privilege_list => xs$name_list('connect'),
 principal_name => 'APEX_190200',
 principal_type => xs_acl.ptype_db) );
END;
/

 

Für Debugging im SQL*Developer:

BEGIN
 DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE (host => '172.30.30.20',
 lower_port => null,
 upper_port => null,
 ace => xs$ace_type(privilege_list => xs$name_list('jdwp'),
 principal_name => 'SCOTT',
 principal_type => xs_acl.ptype_db) );
END;
/

Wir hatten häufig Probleme damit die ACLS wieder zu löschen. Es scheint so zu sein, dass wenn auf einem Rechner eine Freigabe auf eine spezielle Portrange und eine Freigabe ohne Portbeschränkung (lower_port und upper_port = NULL) existiert, diese ACLS nicht mehr zu löschen ist.

Aber wir haben eine Alternative entwickelt:
Zuerst schauen wir mal nach, welche ACL´s vergeben sind:

select na.host,na.lower_port,na.upper_port,nap.principal,privilege
        from dba_network_acls na, DBA_NETWORK_ACL_PRIVILEGES nap
        where na.acl=nap.acl
        and host='172.30.30.20';

Der folgende Block nimmt eine IP Adresse entgegen (Zeile 2: 172.30.30.20) und erstellt ein Skript zum Löschen aller ACLs auf diese IP Adresse.
Natürlich könnten Sie den Filter abwandeln z.B. alle ACL´s eines Benutzers löschen.
Sie können auch die ACLs direkt löschen, wenn sie v_debug auf FALSE setzen. Sie sollten sich vorher jedoch erst mal ansehen, was gelöscht werden würde !
Der Packageaufruf DBMS_NETWORK_ACL_ADMIN.UNASSIGN_ACL ist eigentlich desupported, es gab jedoch für uns keine andere Alternative,
die wirklich beim Löschen funktioniert hat. Wir können nur keine Gewähr für die Funktionalität übernehmen.
DECLARE
v_server VARCHAR2(256):=lower('172.30.30.20');
v_debug BOOLEAN:=TRUE;
BEGIN
FOR c IN (select na.host,na.lower_port,na.upper_port,nap.principal,privilege,na.acl
        from dba_network_acls na, DBA_NETWORK_ACL_PRIVILEGES nap
        where host=v_server ) LOOP

IF NOT v_debug THEN
    SYS.DBMS_NETWORK_ACL_ADMIN.REMOVE_HOST_ACE (
    host        =>c.host,
    lower_port => c.lower_port,
    upper_port => c.upper_port,
    ace          =>xs$ace_type(
        privilege_list => xs$name_list(c.privilege),     
        principal_name => c.principal,
        principal_type => xs_acl.ptype_db),
        remove_empty_acl=>TRUE);
  ELSE      
        dbms_output.put_line(' BEGIN SYS.DBMS_NETWORK_ACL_ADMIN.REMOVE_HOST_ACE (');
        dbms_output.put_line(' host        =>'''||c.host||'''');
        IF c.lower_port IS NOT NULL THEN
           dbms_output.put_line(', lower_port => '||c.lower_port);
        END IF;
         IF c.lower_port IS NOT NULL THEN
            dbms_output.put_line(', upper_port =>'|| c.upper_port);
         END IF;
        dbms_output.put_line(',ace          =>xs$ace_type(
        privilege_list => xs$name_list('''||c.privilege||'''),     
        principal_name =>'''||c.principal||''',
        principal_type => xs_acl.ptype_db),
        remove_empty_acl=>TRUE);
        END;
        /');
        dbms_output.put_line('BEGIN DBMS_NETWORK_ACL_ADMIN.UNASSIGN_ACL (');
       dbms_output.put_line('acl =>'''||c.acl||''',   host=>'''||c.host||'''');
       IF c.lower_port IS NOT NULL THEN
           dbms_output.put_line(', lower_port => '||c.lower_port);
        END IF;
         IF c.lower_port IS NOT NULL THEN
            dbms_output.put_line(', upper_port =>'|| c.upper_port);
         END IF;
        dbms_output.put_line(');');
        dbms_output.put_line('END;');
       dbms_output.put_line('/');
    END IF;
END LOOP;
END;
/


Für die Version 11g musste noch eine andere Syntax für das Erstellen der ACLs verwendet werden:

BEGIN
   DBMS_NETWORK_ACL_ADMIN.CREATE_ACL (
      acl          => 'utl_smtp.xml',
      description  => 'Mailversendung',
      principal    => 'SCOTT',
      is_grant     => TRUE,
      privilege    => 'connect');
END;
/

Die ACL wird dann einem Host zugewiesen, wobei auf einen Port bzw. auf einen Bereich eingeschränkt werden kann.

BEGIN
   DBMS_NETWORK_ACL_ADMIN.ASSIGN_ACL (
      acl          => 'utl_smtp.xml',
      host         => 'mailserver',
      lower_port   => 25);
END;
/


In diesem Beispiel wäre nur der Port 25 auf dem Host mailserver freigegeben. Wird zusätzlich ein upper_port mit angegeben, so ist der Bereich zwischen den beiden Werten freigegeben.
Einem Host bzw. einem Port-Range kann immer nur eine ACL zugewiesen sein. Bei einer erneuten Zuweisung wird die alte Zuweisung entfernt. Statt Namen können auch IP-Adressen angegeben werden, und es kann mit dem Stern (*) als Wildcard gearbeitet werden, um ganze Bereiche einer Domäne bzw. ganze Subnetze zu verwalten.

SCOTT kann nun im obigen Beispiel über den Port 25 Mails versenden. Wenn er eine entsprechende Prozedur mit Invoker Rights schreibt und das EXECUTE-Recht an einen User DUMMY vergibt, so braucht dieser zusätzlich die entsprechende Freigabe:

BEGIN
   DBMS_NETWORK_ACL_ADMIN.ADD_PRIVILEGE (
      acl          => 'utl_smtp.xml',
      principal    => 'DUMMY',
      is_grant     => TRUE,
      privilege    => 'connect');
END;
/

Besuchen Sie uns doch bei einer unsere über 40 Oracle Schulungen in München - Unterhaching.