これはOracle APEX特有の脆弱性というわけではなく、Webアプリケーションであれば何でも当てはまるはずです。10年以上前は「ブラウザでJavaScriptの実行は禁止する」ということも行われていましたが、今は現実的な対応とはいえません。
ユーザーに近いブラウザ側で制約をかけた方がアプリケーションは使いやすくなりますが、悪意のあるユーザーからデータを保護するといったセキュリティ上の対策はサーバー側に実装する必要があります。
いくつか例を紹介します。
サンプル・データセットのEMP/DEPTに含まれる表EMPをソースとしたクラシック・レポートを作成します。
一覧する従業員の絞り込みに使用するページ・アイテムとしてP1_DEPTNOを作成します。部門の値を選択すると、その部門に所属する従業員のみがレポートに一覧されます。
ページ・アイテムP1_DEPTNOのタイプとして選択リストを選び、LOVのSQL問合せとして以下を記述します。
select dname d, deptno r from dept where deptno <> 10
ページ・アイテムP1_DEPTNOの値が変更されたときにレポートがリフレッシュされるように、動的アクションを作成しています。
レポートのWHERE句にdeptno = :P1_DEPTNOという条件を設定し、送信するページ・アイテムにP1_DEPTNOを指定します。
これでレポートとしてはページ・アイテムP1_DEPTNOで指定された従業員しか一覧せず、ページ・アイテムP1_DEPTNOではDEPTNOから10(部門名はACCOUNTING)を除外しているため、ブラウザからの操作では部門ACCOUNTINGの従業員は一覧できません。
以下が通常の操作です。部門としてRESEARCH、SALES、OPERATIONSのどれかが選択可能で、選択した部門の従業員が一覧されます。
var select = document.getElementById("P1_DEPTNO");
var option = document.createElement("option");
option.text = "ACCOUNTING";
option.value = "10";
select.add(option);
apex.items.P1_DEPTNO.value = 10;
レポートのWHERE句を以下に変更し、DEPTNOが10の従業員はつねに一覧に表示しないようにすると、ブラウザ側で何をしても部門ACCOUNTINGの従業員は表示されません。
deptno = :P1_DEPTNO and deptno != 10
続いて動的アクションによるデータの保護を回避します。
ボタンRefeshをクリックすると従業員のレポートがリフレッシュされ、従業員の一覧が表示されます。その際に動的アクションで表示条件を設定しています。
if ( true ) {
apex.items.P1_ALLOW.value = 0;
}
else
{
apex.items.P1_ALLOW.value = 1;
}
レポートのWHERE句に以下の条件を設定します。
1 = :P1_ALLOW
送信するページ・アイテムとしてP1_ALLOWを設定します。
このレポートに従業員を一覧させます。以下のJavaScriptのコードを実行します。名前がonClick Refreshという動的アクションを見つけて、先頭のTRUEアクションを削除します。その後にP1_ALLOWに1を設定します。
var da = apex.da.gEventList.find(item => item.name === "onClick Refresh");
delete da.actionList[0];
apex.items.P1_ALLOW.value = 1;
JavaScriptのコードを実行した後にボタンRefreshをクリックすると、P1_ALLOWを0に設定するTRUEアクションが削除されているため、P1_ALLOWは1から変わりません。結果としてレポートに従業員が一覧されます。
例えばユーザーごとに表示/非表示の条件を設定したいのであれば、認可スキームの設定などが簡単な対応になります。
今回の記事は以上になります。
簡単なアプリケーションですが、今回の記事で使用したアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/test-browser-side-condition.zip
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完