Skip to Main Content
Ted Struik - Oracle
Search For
Home
Home
Ted Struik - Oracle
Search
Site Map
Statistics
Page Errors
Apex
Apex
General
Autocomplete
Conditions
Errors
Items used in PL/SQL
Validations
Dynamic Actions
Logs
Version
App-wide Items
Error Handling
Apex Views
Apex Upgrade 4.2 to 5.1
Apex Upgrade 20.2 to 23.1
Database Dependencies
Show Source Code
URLs
Authorization
Modal Dialogs
Apex Office Print (AOP)
Apex-Sert
Warn on Unsaved Changes
Form Regions
Breadcrumbs
Reports
Checkboxes
Download
Errors
Nowrap Columns
Substitution Strings
Use IR results in pl/sql
Clickable Row
Row Highlight
Translate Filters etc.
Bar Charts
Column Usage
Reset Pagination
Hide IR Actions menu items
Get Classic Report query
Sorting strings as numbers
Search needs Filters
Reset button for IR
Interactive Grid
ORA-20987
ERR-1002
Copying Text
IG Info
Multiple Row Select
Read Only Options
Search
Sort and Search
Page Items to Submit
Single Row View
Popup LOV Sorting
Images & Fonts
Standard Icons & Fonts
WebDav
Font Awesome
Icons/image popup LOV
Lists
Hierarchy
LOVs
Definition Bug
Set 1-item LOV to Disabled
With Clause Errors
Modal LOV Plugin
HTML / CSS / JavaScript
Vertical Align
Legend CSS
Geolocation
Apex.confirm
Pie Charts
Codemirror
Theme Roller
Catching Key Strokes
Browser Cache
Locale
RequireJS
Collapsible Regions
Find JavaScript (or CSS)
Import / Export
Dynamic Translations
Translated Pages
APEXExport (java)
apex_export (pl/sql)
Component Settings
Charts
Translate Charts
[Reports] Bar Charts
Shuttles
Shuttle Sorting
Disable Shuttle Items
Menus
Accordion-Like
Scroll bug
Authorization
Session State
About Session State
Rollback & Commit
Performance of v()
Apex Clone Session
Request
Session State in Views
Collections
ORA-20101 & ORA-20104
ORA-00001
Max Row Count
ORA-02291
(PL)SQL
(PL)SQL
External Tables
SQL Plus
Conditions
Long
ORDImage
Date & Timestamp
CGI environment
Sys_context
Rounding percentages
Apex_string.split in SQL
Dbms_metadata
Instr
Regular Expressions
Rollback to Savepoint
Use table aliases
(Pipelined) Bulk Collect
JSON
Source Code Search (PL/SQL)
Source Code Search (SQL)
Format Models
Pipelined Table Functions
Hint no_unnest
Listagg
(Re)compile Objects
HTML
Creating PL/SQL with LLMs
DBA
DBA
Backup & Restore
Users
Export & Import
DBMS Jobs
Tablespaces
Table Size
Flush cache
Access Control List (ACL)
Locks
Java
Constraints
Object Dependencies
Package Dependencies 1
Package Dependencies 2
Grants
SQL History
Startup Errors
ORDS
Synonyms
Miscellaneous
Miscellaneous
Holidays
E-mail
NLExtract
Windows
VPN
VMware
Links
Google
Visualization Orgchart
Hide Search Results
Reverse Proxy
To-do List
Cytoscape
Graphics
Upscaling
Amazon Prices
Domoticz
DDoS
Hobbies
Hobbies
Motorcycles
'95 Kawasaki ZZR 600
'94 Kawasaki ZZR 1100
'91 Honda CBR 600 F2
'95 Kawasaki ZZR 1100
'99 Honda CBR 1100 XX
'00 Honda CBR 1100 XX
'02 Kawasaki ZX-12R (NL)
'05 Ducati 999 (NL)
'08 Honda Fireblade
'07 Suzuki Bandit 1250A
'18 Suzuki GSX-S 1000 F
MotoGP
Garfield
Lyrics
Skydive
Woodworking
Pantorouter
16 inch Bandsaw
Introduction
Frame
Wheels
Wheel mounts
Blade guides
Trunions and table
Enclosure
Alignment and more
Box Joint Jig
Foldable Sawhorses
Strip Sander XL
Sony RX10 IV
Yes Minister
WinAmp
Focal Onyx
DDoS
Go
Rows
1
5
10
15
20
25
50
Actions
Report Settings
Bot Pk Id is null
Edit Filter
Remove Filter
Score >= 2
Edit Filter
Remove Filter
Score >= 2
Highlight Row, #000000 on #ffd6d2: Score >= 2
Edit Highlight
Remove Highlight
Bot Pk Id
Score >= 2
1 inactive setting
View Date
Last View Date
First View Date
Score
N
Page Id N
Ip Start
Ip Address 1
Ip Address 2
Ip Address N
Agent
Agent N
Bot Pk Id
Bot Type
Ip From
Ip To
Info Source
User Agent Regex
Description
2026-07-12
2026-07-12 20:44:30
2026-07-12 10:04:57
2.0
2165
192
94.157.
.***.***
.***.***
1
DuckAssistBot/1.2; (+http://duckduckgo.com/duckassistbot.html)
112
1 - 1 of 1
Column Actions
Search
Info
DDoS attacks (or Brute Force attacks or other bot-related behavior that amounts to the same thing) are becoming a bit of a problem for my server.
Thousands of requests per hour are too much for my modest setup, so I had to take some measures.
So I created a query to find suspicious IP addresses and/or User Agents using apex_workspace_activity_log. See the code below - I hid the complete IP addresses for privacy reasons.
If I identify an attack, I can add a "rewrite rule" to Apache (on my proxy server) to block an IP range or User Agent. More info on that
here
and
here
.
This is not ideal of course. A problem has to arise first, before I can act. But it's better than doing nothing.
I should look into other measures like Mod_evasive, Mod_security, Fail2ban, etc., but for now this sort of works.
ModSecurity
Update May 2023
:
Things were getting out of hand, so I installed ModSecurity on my Apache reverse proxy server (Apache 2.4 on AlmaLinux 8).
That turned out to be quite simple (after a few hours of trying all sorts of cookbooks that did not work...). Here's what I did:
dnf -y update dnf -y install mod_security dnf -y install mod_security_crs systemctl restart httpd
You will need to deactivate ModSecurity from any machine/subnet that is allowed to use Apex Builder. Otherwise saving anything in the Apex Builder will result in a 403 error.
In my case I need to do this for IP 192.168.2.254, which is my internal router address.
vi /etc/httpd/modsecurity.d/local_rules/modsecurity_localrules.conf # add this line: SecRule REMOTE_ADDR "^192.168.2.254" id:1,phase:1,nolog,allow,ctl:ruleEngine=Off
You can check the log here:
tail -f /var/log/httpd/modsec_audit.log
And to check if it all works, perform an "illegal" request:
curl -d "id=1 AND 1=1" https://tedstruik-oracle.nl/ords/f?p=25384
which should return:
403 Forbidden
Forbidden
You don't have permission to access this resource.
Apache Ultimate Bad Bot Blocker
Update March 2026
:
The traffic from all sorts of bots was getting out of hand again, with performance issues and ORDS errors as a result.
I saw a lot of AI bots in the logs, which is to be expected of course.
I already blocked quite a few bots, and I tried to keep track of all the new ones, but that was getting harder and harder to do by hand.
So as an additional line of defense, I tried
Apache Ultimate Bad Bot Blocker
.
Seems to work just fine, but it will take a couple of weeks to be sure.
Code
Page
Identification
Page ID
1162
Name
Miscellaneous - DDoS
Page Alias
MISCELLANEOUS-DDOS
Region
Identification
Sequence
10
Title
DDoS
Type
Interactive Report
Source
Location
Local Database
Query Type
SQL Query
Region Source
select t.view_date ,t.last_view_date ,t.first_view_date ,t.n ,t.page_id_n ,t.ip_start ,substr(t.ip_address_1, 1, instr(t.ip_address_1,'.',1,2)-1) || '.***.***' as ip_address_1 ,substr(t.ip_address_2, 1, instr(t.ip_address_2,'.',1,2)-1) || '.***.***' as ip_address_2 ,t.ip_address_n ,t.agent ,t.agent_n ,t.pk_id ,t.bot_type ,t.ip_from ,t.ip_to ,t.info_source ,t.user_agent_regex ,t.description ,t.score from ted_p1162_v t
View
View
Name
TED_P1162_V
DDL
with iv_a as ( select /*+materialize */ a.view_date , a.apex_session_id , max(a.ip_address) over (partition by a.apex_session_id) as ip_address , a.agent , a.page_id , a.page_name , a.elapsed_time from apex_workspace_activity_log a where a.application_id = nvl(nv('APP_ID'), 25384) ) , iv_b as ( select trunc(iv_a.view_date) as view_date -- Group by Day , max(iv_a.view_date) as last_view_date , min(iv_a.view_date) as first_view_date , count(*) as n -- number of requests , count(distinct iv_a.page_id) as page_id_n -- number of unique requested pages , substr(iv_a.ip_address, 1, instr(iv_a.ip_address, '.', 1, 2)) as ip_start -- first 2 numbers of the IP address, useful for attacks that use an IP range , min( substr(iv_a.ip_address, 1, instr(iv_a.ip_address, ',')-1) ) as ip_address_1 -- lowest IP address within the "first 2 numbers" group , max( substr(iv_a.ip_address, 1, instr(iv_a.ip_address, ',')-1) ) as ip_address_2 -- highest IP address within the "first 2 numbers" group , count(distinct iv_a.ip_address) as ip_address_n -- number of unique IP addresses within the "first 2 numbers" group , min(iv_a.agent) as agent -- an example of a User Agent used (there may be more than 1, but if so then it is not interesting) , count(distinct iv_a.agent) as agent_n -- number of unique User Agents within the "first 2 numbers" group from iv_a group by trunc(iv_a.view_date) , substr(iv_a.ip_address, 1, instr(iv_a.ip_address, '.', 1, 2)) ) , iv_c as ( select iv_b.* , bot.* -- info from my Bots table (if applicable) from iv_b left join ted_access_log_bots bot on bot.pk_id = ted_access_log.bot_pk_id(p_ip_address => iv_b.ip_address_1, p_user_agent => iv_b.agent) where iv_b.n >= 100 -- 100 seems about right for my purposes ) select iv_c.view_date , iv_c.last_view_date , iv_c.first_view_date , iv_c.n , iv_c.page_id_n , iv_c.ip_start , iv_c.ip_address_1 , iv_c.ip_address_2 , iv_c.ip_address_n , iv_c.agent , iv_c.agent_n , iv_c.pk_id , iv_c.bot_type , iv_c.ip_from , iv_c.ip_to , iv_c.info_source , iv_c.user_agent_regex , iv_c.description , ( ( case when iv_c.agent_n > 1 then 1 else 0 end ) -- normal visitors have 1 user agent + ( case when iv_c.ip_address_n > 1 then 1 else 0 end ) -- normal visitors have 1 IP address + ( case when iv_c.page_id_n = 1 then 1 else 0 end ) -- normal visitors go to more than 1 page + ( case when iv_c.n >= 1000 then 1 else 0 end ) -- normal visitors do not visit 1000 pages ) * ( case when iv_c.pk_id is not null then .2 else 1 end ) -- bots are probably OK as score -- scores >= 2 are most likely a hit from iv_c