Sanity Checks für Ordner und Dateinamen hinzugefügt
This commit is contained in:
@@ -42,20 +42,40 @@ create or replace package body pck_net_storage as
|
||||
end if;
|
||||
end f_build_url;
|
||||
|
||||
-- Normalisiert einen Ordnerpfad: stellt sicher, dass er mit / endet.
|
||||
-- null bleibt null (= Bucket-Root).
|
||||
function f_normalize_prefix (i_prefix in varchar2) return varchar2
|
||||
is
|
||||
begin
|
||||
if i_prefix is null
|
||||
then
|
||||
return null;
|
||||
end if;
|
||||
|
||||
return rtrim(i_prefix, '/') || '/';
|
||||
end f_normalize_prefix;
|
||||
|
||||
procedure p_assert_allowed (i_object_key in varchar2)
|
||||
/*Kopf------------------------------------------------------------------------------------------------
|
||||
-- Beschreibung: Prüft den Objektschlüssel auf Path-Traversal-Angriffe und Tenant-Scope.
|
||||
-- Wirft Application Error -20004 bei Path Traversal, -20005 bei Scope-Verletzung.
|
||||
-- Beschreibung: Prüft den Objektschlüssel auf Gültigkeit, Path-Traversal-Angriffe und Tenant-Scope.
|
||||
-- Wirft Application Error -20008 bei null-Key, -20004 bei Path Traversal,
|
||||
-- -20005 bei Scope-Verletzung.
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- Parameter: i_object_key Zu prüfender Objektschlüssel
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- MA Datum Änderung
|
||||
-- SCK 2026-04-08 Prozedur erstellt
|
||||
-- SCK 2026-04-10 Null-Prüfung und führender-Slash-Check ergänzt
|
||||
------------------------------------------------------------------------------------------------Kopf*/
|
||||
is
|
||||
l_tenant_prefix varchar2(256);
|
||||
begin
|
||||
if instr(i_object_key, '..') > 0
|
||||
if i_object_key is null
|
||||
then
|
||||
raise_application_error(-20008, 'Object key darf nicht null sein');
|
||||
end if;
|
||||
|
||||
if instr(i_object_key, '..') > 0 or substr(i_object_key, 1, 1) = '/'
|
||||
then
|
||||
raise_application_error(-20004, 'Path traversal attempt detected');
|
||||
end if;
|
||||
@@ -166,13 +186,14 @@ create or replace package body pck_net_storage as
|
||||
l_count number := 0;
|
||||
l_done boolean := false;
|
||||
l_cur_start varchar2(1024) := i_start_with;
|
||||
l_parent_folder varchar2(1024) := f_normalize_prefix(i_parent_folder);
|
||||
c_page_size constant number := 1000;
|
||||
begin
|
||||
while not l_done
|
||||
loop
|
||||
l_url := f_build_url()
|
||||
|| '?limit=' || c_page_size
|
||||
|| (case when i_parent_folder is not null then '&prefix=' || utl_url.escape(i_parent_folder, false) else '' end)
|
||||
|| (case when l_parent_folder is not null then '&prefix=' || utl_url.escape(l_parent_folder, false) else '' end)
|
||||
|| (case when i_include_subfolders = 'N' then '&delimiter=/' else '' end);
|
||||
|
||||
if l_cur_start is not null
|
||||
@@ -202,7 +223,8 @@ create or replace package body pck_net_storage as
|
||||
rec.object_name
|
||||
,rec.object_size
|
||||
,to_date(substr(rec.last_modified, 1, 19), 'YYYY-MM-DD"T"HH24:MI:SS')
|
||||
,'N'
|
||||
-- Explizit angelegte Ordner sind Zero-Byte-Objekte mit trailing /
|
||||
,(case when rec.object_name like '%/' then 'Y' else 'N' end)
|
||||
,rec.etag
|
||||
);
|
||||
l_count := l_count + 1;
|
||||
@@ -316,10 +338,14 @@ create or replace package body pck_net_storage as
|
||||
-- SCK 2026-04-08 Funktion erstellt
|
||||
------------------------------------------------------------------------------------------------Kopf*/
|
||||
is
|
||||
l_parent_folder varchar2(1024) := f_normalize_prefix(i_parent_folder);
|
||||
begin
|
||||
pck_mitarbeiterrecht.p_hat_recht('LESEN_ALLES');
|
||||
p_assert_allowed(i_parent_folder);
|
||||
return f_list_objects_internal(i_parent_folder, i_include_subfolders, i_start_with, i_limit);
|
||||
if l_parent_folder is not null
|
||||
then
|
||||
p_assert_allowed(l_parent_folder);
|
||||
end if;
|
||||
return f_list_objects_internal(l_parent_folder, i_include_subfolders, i_start_with, i_limit);
|
||||
end f_list_objects;
|
||||
|
||||
function f_download_object (i_object_key in varchar2) return blob
|
||||
@@ -384,6 +410,11 @@ create or replace package body pck_net_storage as
|
||||
pck_mitarbeiterrecht.p_hat_recht('SCHREIBEN_ALLES');
|
||||
p_assert_allowed(i_object_key);
|
||||
|
||||
if substr(i_object_key, -1) = '/'
|
||||
then
|
||||
raise_application_error(-20012, 'Object Key darf nicht mit / enden — zum Anlegen von Ordnern p_create_folder verwenden');
|
||||
end if;
|
||||
|
||||
-- TEST
|
||||
--l_response := f_make_request(
|
||||
-- i_method => 'PUT'
|
||||
@@ -446,14 +477,14 @@ create or replace package body pck_net_storage as
|
||||
l_objects t_net_storage_tab;
|
||||
l_response clob;
|
||||
l_obj_path t_object_path;
|
||||
l_prefix varchar2(1024) := f_normalize_prefix(i_prefix);
|
||||
begin
|
||||
pck_mitarbeiterrecht.p_hat_recht('ADMIN');
|
||||
p_assert_allowed(i_prefix);
|
||||
p_assert_allowed(l_prefix);
|
||||
|
||||
-- TEST
|
||||
-- Alle Objekte im Ordner auflisten (rekursiv, alle Tiefen)
|
||||
--l_objects := f_list_objects_internal(
|
||||
-- i_parent_folder => i_prefix
|
||||
-- i_parent_folder => l_prefix
|
||||
-- ,i_include_subfolders => 'Y'
|
||||
-- ,i_start_with => null
|
||||
-- ,i_limit => 0
|
||||
@@ -471,12 +502,12 @@ create or replace package body pck_net_storage as
|
||||
-- end if;
|
||||
--end loop;
|
||||
|
||||
l_obj_path := f_split_object_key(i_prefix);
|
||||
l_obj_path := f_split_object_key(l_prefix);
|
||||
pck_log.p_info(
|
||||
i_module => c_log_module
|
||||
,i_action => 'DELETE_FOLDER'
|
||||
,i_message => 'Ordner "' || l_obj_path.filename || '" rekursiv gelöscht | Pfad: ' || l_obj_path.path
|
||||
,i_object_ref => i_prefix
|
||||
,i_object_ref => l_prefix
|
||||
);
|
||||
end p_delete_folder;
|
||||
|
||||
@@ -504,6 +535,16 @@ create or replace package body pck_net_storage as
|
||||
pck_mitarbeiterrecht.p_hat_recht('SCHREIBEN_ALLES');
|
||||
p_assert_allowed(i_object_key);
|
||||
|
||||
if i_new_name is null or length(trim(i_new_name)) = 0
|
||||
then
|
||||
raise_application_error(-20013, 'Neuer Dateiname darf nicht leer sein');
|
||||
end if;
|
||||
|
||||
if instr(i_new_name, '/') > 0
|
||||
then
|
||||
raise_application_error(-20014, 'Dateiname darf keinen Schrägstrich enthalten — zum Verschieben p_move_object verwenden');
|
||||
end if;
|
||||
|
||||
-- Verzeichnispfad aus dem aktuellen Key extrahieren
|
||||
if instr(i_object_key, '/') > 0
|
||||
then
|
||||
@@ -560,10 +601,19 @@ create or replace package body pck_net_storage as
|
||||
l_body clob;
|
||||
l_response clob;
|
||||
l_obj_path t_object_path;
|
||||
l_target_prefix varchar2(1024);
|
||||
begin
|
||||
pck_mitarbeiterrecht.p_hat_recht('SCHREIBEN_ALLES');
|
||||
p_assert_allowed(i_object_key);
|
||||
|
||||
if i_target_prefix is null
|
||||
then
|
||||
raise_application_error(-20015, 'Zielpräfix darf nicht null sein');
|
||||
end if;
|
||||
|
||||
l_target_prefix := f_normalize_prefix(i_target_prefix);
|
||||
p_assert_allowed(l_target_prefix);
|
||||
|
||||
-- Dateinamen aus dem aktuellen Key extrahieren
|
||||
if instr(i_object_key, '/') > 0
|
||||
then
|
||||
@@ -572,7 +622,7 @@ create or replace package body pck_net_storage as
|
||||
l_filename := i_object_key;
|
||||
end if;
|
||||
|
||||
l_new_key := i_target_prefix || l_filename;
|
||||
l_new_key := l_target_prefix || l_filename;
|
||||
p_assert_allowed(l_new_key);
|
||||
|
||||
select json_object(
|
||||
@@ -594,7 +644,7 @@ create or replace package body pck_net_storage as
|
||||
pck_log.p_info(
|
||||
i_module => c_log_module
|
||||
,i_action => 'MOVE'
|
||||
,i_message => 'Datei "' || l_obj_path.filename || '" verschoben | Von: ' || l_obj_path.path || ' | Nach: ' || i_target_prefix
|
||||
,i_message => 'Datei "' || l_obj_path.filename || '" verschoben | Von: ' || l_obj_path.path || ' | Nach: ' || l_target_prefix
|
||||
,i_object_ref => i_object_key
|
||||
);
|
||||
end p_move_object;
|
||||
@@ -617,21 +667,35 @@ create or replace package body pck_net_storage as
|
||||
l_folder_key varchar2(1024);
|
||||
l_response clob;
|
||||
l_obj_path t_object_path;
|
||||
l_prefix varchar2(1024) := f_normalize_prefix(i_prefix);
|
||||
begin
|
||||
pck_mitarbeiterrecht.p_hat_recht('SCHREIBEN_ALLES');
|
||||
p_assert_allowed(i_prefix);
|
||||
|
||||
if i_folder_name is null or length(trim(i_folder_name)) = 0
|
||||
then
|
||||
raise_application_error(-20010, 'Ordnername darf nicht leer sein');
|
||||
end if;
|
||||
|
||||
if instr(i_folder_name, '/') > 0
|
||||
then
|
||||
raise_application_error(-20011, 'Ordnername darf keinen Schrägstrich enthalten');
|
||||
end if;
|
||||
|
||||
if l_prefix is not null
|
||||
then
|
||||
p_assert_allowed(l_prefix);
|
||||
end if;
|
||||
|
||||
-- Ordner als leeres Objekt mit trailing Slash anlegen
|
||||
l_folder_key := i_prefix || i_folder_name || '/';
|
||||
l_folder_key := l_prefix || i_folder_name || '/';
|
||||
p_assert_allowed(l_folder_key);
|
||||
|
||||
-- TEST
|
||||
--l_response := f_make_request(
|
||||
-- i_method => 'PUT'
|
||||
-- ,i_url => f_build_url(l_folder_key)
|
||||
-- ,i_body_blob => empty_blob()
|
||||
-- ,i_content_type => 'application/octet-stream'
|
||||
--);
|
||||
l_response := f_make_request(
|
||||
i_method => 'PUT'
|
||||
,i_url => f_build_url(l_folder_key)
|
||||
,i_body_blob => empty_blob()
|
||||
,i_content_type => 'application/octet-stream'
|
||||
);
|
||||
|
||||
l_obj_path := f_split_object_key(l_folder_key);
|
||||
pck_log.p_info(
|
||||
|
||||
Reference in New Issue
Block a user