Closed atc0005 closed 4 years ago
The following comments were pulled from an internal issue I opened elsewhere to log some thoughts. Transferring here as they're relevant and (AFAICT) not particularly sensitive in nature.
EDIT: As of this writing, I have yet to hear back from OCLC Support. I have to assume that the outcome will be that we're on our own to come up with a solution.
Does blocking an IP require restarting EZproxy?
Perhaps we can write to a config file to block further sessions, but match existing sessions to their IPs and block those IPs?
Determines how long in minutes an EZproxy session should remain valid after the last time it is accessed. The default of 120 determines that a session remains valid until 2 hours after the last time the user accesses a database through EZproxy. MaxLifetime is the only setting that is position dependent in config.txt. In normal use, it should appear before the first TITLE line.
If nothing else, the MaxLifetime
value could be tweaked further to increase the likelihood that the session times out and is subject to the same block as other abusers.
https://help.oclc.org/Library_Management/EZproxy/Configure_resources/RejectIP
Perhaps have the main EZproxy config file pull in an include file of rejected IP Address entries?
The logic could perhaps check to see when a user was blocked and if it was X minutes past, add a RejectIP
entry in order to force the user session to terminate. After X minutes, the IP could be removed and the blocked/disabled user account entry would serve to prevent repeat abuse for the existing account. The temporary IP block would limit potential Denial of Service to legitimate users of the system.
Workflow (scratch notes, some logic debugging needed):
Limit
(EZproxy setting for maximum concurrent sessions per account) times, resulting in Limit
number of temporary IP blocksAt this point legitimate users (other than the blocked user account) are mostly unaffected as we no longer have temporary IP blocks for the specific user account in place.
@auadamw How does the workflow in https://github.com/atc0005/brick/issues/13#issuecomment-623075903 sound?
We would potentially need to ingest +1 more files in order to handle this, and would probably want to add an ingest for one more file past that (so +2 overall).
We might also drop the MaxLifetime
value further than we already have it (not mentioning that specific detail here) to help with this as well, though if we get the logic working as specified in https://github.com/atc0005/brick/issues/13#issuecomment-623075903 it wouldn't matter as much if we use a temporary IP block to force session expiration.
The assumption there is that the bulk of the unauthorized behavior would occur during early morning or off-hours and any IP block triggered would minimally impact legitimate users.
I gave this some more thought and I think we can use an existing tool to lighten the development time/costs for the initial implementation: fail2ban
.
Modified workflow below.
Limit
(EZproxy setting for maximum concurrent sessions per account) times, resulting in Limit
number of IP Address block requests from Splunk serverMaxSession
limit in EZproxyThis allows the brick web app to focus exclusively on:
Direct/measurable upsides:
Further refinement:
MaxLifetime
+ some small additional amount of timeThis workflow should allow for the live sessions to timeout, the user account to be blocked and new sessions to be blocked.
I missed a response from OCLC Support on April 28th (just found it). Snippet of that response (leaving out the support tech's information):
Thank you for contacting OCLC Product Support.
Unfortunately, EZproxy does not currently have the mechanism to terminate sessions with given attributes. There is only limitations on session duration and user permissions based on your authentication method.
To secure your EZproxy server from suspicious login activity, you may set IntruderIPAttempts. This will set any restrictions based on the directive definitions when logging in. For more details, see the following documentation: https://help.oclc.org/Library_Management/EZproxy/Configure_resources/IntruderIPAttempts
Let me know if I can be of any further assistance on this request.
My response back:
Hi,
Sorry for my late response (I just found this email).
We're already using the IntruderIPAttempts directive to block user accounts based on thresholds that seem to work fairly well for the most egregious abuse (bots, "rage" logins when users forget passwords, etc).
Our use case in this discussion is tied to an external indicator that an account has been abused, so we're looking to shutdown a specific user account based on external tooling. After some research, it is beginning to look our solution will be to (automatically) block the associated IP at the host firewall level long enough for the EZproxy MaxLifetime value to be reached and force the session to timeout. That host firewall entry could then be (automatically) unblocked a short time later. Combined with adding the associated user account to a flat-file (or AD group or ...), this should prevent new sessions for the associated account.
Any major flaws in that plan?
Leaving out some emails in the thread, but received one back today confirming that the recommended RejectIP
directive does require restarting EZproxy in order to take effect. That makes that option less desirable due to that requirement (e.g., if we accidentally introduce a config error we could bring down the service).
brick web app is running with several log files open
- log file for user account block requests
- log file for IP Address block requests
Note to self: Unfortunately I don't recall why I suggested two log files; fail2ban is perfectly capable of (and is intended for) monitoring log files based on patterns. We log to one log file and fail2ban parses the entries looking for a pattern that it has been configured to take action on. When it finds the pattern, it extracts the IP Address and blocks it (temporarily, or "permanently") as indicated previously.
At this point I'm trying to figure out exactly how the log messages will be recorded. I've got the templates setup, I figured out when logging occurs, but now I'm trying to figure out when fail2ban will be triggered.
Some misc notes below as I think out loud.
Every payload received ...
It is tempting to have fail2ban look at the reported log entries, but that removes the ability to ignore specific usernames or IP Addresses and still log that the payload was received.
Reminder to self:
fail2ban requires a timestamp in the source file to determine when the event occurred. This is needed (if I recall correctly) so that it can tell where it last processed. I don't recall if this is also so it can tell when an IP was last blocked (I believe that this state is tracked elsewhere in case the origin log file rotates, etc).
Regardless, a list of bare IPs for fail2ban to process is probably not advisable for numerous reasons, though it could be useful to sysadmins who wish to quickly remove a blocked IP. I think for that we'll need to use Ansible or become comfortable using "recipes" to unblock fail2ban-blocked IPs as needed (which is doable to begin with).
Finished giving a demo earlier to our team where we were given the "go ahead" to install this application on our test EZproxy server for real world testing. After I happened to search GitHub for "ezproxy" and found this project:
https://github.com/calvinm/ezproxy-abuse-checker
which has a Perl script named block_user.pl
with this block close to the end of the file:
if ($block_session) {
system("/opt/ezproxy/ezproxy kill $block_session");
}
Strange, but that looks like they're able to terminate a user session using built-in EZproxy functionality. This is the support that the OCLC Support rep told me wasn't available. I suspect the tech I spoke with honestly didn't know about the feature, and it's possible that it's not even documented well.
Will dig further.
Strange, but that looks like they're able to terminate a user session using built-in EZproxy functionality. This is the support that the OCLC Support rep told me wasn't available. I suspect the tech I spoke with honestly didn't know about the feature, and it's possible that it's not even documented well.
Will dig further.
OCLC Support misunderstood what I wrote back, so I took our test EZproxy instance and did some testing. The net result is that I was able to retrieve my own login session ID from two different locations:
EZPROXY_INSTALL_PATH/ezproxy.hst
S SESSION_ID OTHER_STUFF
EZPROXY_INSTALL_PATH/audit/YYYYMMDD.txt
Login.Success
Login.Success.Relogin
Further testing would be needed to determine if both files can provide the session ID reliably.
I then went through the steps to confirm that I could terminate my session using the retrieved ID:
$ sudo ./ezproxy kill
Session must be specified
$ sudo grep -E '^S ' ezproxy.hst
S SESSION_ID_HERE REDACTED
$ sudo ./ezproxy kill SESSION_ID_HERE
Session SESSION_ID_HERE terminated
SESSION_ID_HERE
is a placeholder for the real session ID, which I've omitted from the example output.
Wrapping up initial release for v0.1.0 today/tomorrow. Going to leave this issue open for further research/testing with the goal of deciding on a "final" (as much as anything can be final) direction for the next release.
Wrapping up initial release for v0.1.0 today/tomorrow. Going to leave this issue open for further research/testing with the goal of deciding on a "final" (as much as anything can be final) direction for the next release.
Spun off GH-31 for that research instead of dragging this existing issue across milestones. Leaving this at the v0.1.0 milestone since the bulk of the work/notes reflects the fail2ban
implementation direction.
Blocking a user account can be done by adding the account to a specific flat-file referenced by EZproxy, but historically we've had to login to the admin panel to terminate a session. Is there an API we can use? If we can't kill existing sessions, perhaps we can match against an IP Address and block that instead?
References: