Access_log to track failed logins

I have a login page that redirects (actually appends the parameter
“?error=true” to the URL and lets the user try again).

I was trying to re-define “access_log” with a full path and (for now)
“combined” to a separate file in that location in hopes of tracking
failed logins in a separate log. Originally, I had a regex nested
location for the error redirect, then I took it out and put it in its
own location. Nothing seems to work.

This doesn’t seem to work at all. An empty log gets created at startup,
but nothing ever gets written there. Is it because the access logging
is already done by the time the location is determined?

How can I somehow log when someone accesses the “login” page with the
“error=true” parameter on the URL?

Thanks,
AJ

On Tue, Dec 18, 2012 at 02:33:06PM -0500, AJ Weber wrote:

Hi there,

I have a login page that redirects (actually appends the parameter
“?error=true” to the URL and lets the user try again).

I was trying to re-define “access_log” with a full path and (for now)
“combined” to a separate file in that location

nginx chooses configuration based (primarily) on the “location”, which
is the local part of the request, excluding query string.

So whatever location matches /my/login/page will also match
/my/login/page?error=true.

Does that explain why your initial attempts did not do what you
expected?

This doesn’t seem to work at all. An empty log gets created at startup,
but nothing ever gets written there. Is it because the access logging
is already done by the time the location is determined?

No, the access logging is done in the context of whichever location the
request finishes in. It doesn’t appear in your error=true log, because
a request like /my/login/page%3Ferror=true was not made.

(As a test, make a request like that, and you should see it in the
new file.)

How can I somehow log when someone accesses the “login” page with the
“error=true” parameter on the URL?

Easiest? Log as normal, and post-process the access log. Something like

tail -F logs/access.log | grep error=true >> logs/error=true.log

may be close enough for a first pass.

Or let the application do this logging.

Otherwise, read Module ngx_http_log_module to see if that offers
anything.

Possibly logging to “logs/access.log-$arg_error”, or to something that
includes a variable set in a map based on $arg_error, would do what you
want? But be aware of the constraints.

Good luck,

f

Francis D. [email protected]

Does that explain why your initial attempts did not do what you expected?
No, unfortunately it doesn’t. I copied the “GET” from the “usual”
access log exactly. Thus, I know the call is being made, because it’s
being logged in the normal log, and I’m pretty sure I have the right
location string, because I copied it right out of the log.

Do I need to escape anything? I’ve tried = and ^~ matching and neither
seems to catch it.

This doesn’t seem to work at all. An empty log gets created at startup,
but nothing ever gets written there. Is it because the access logging
is already done by the time the location is determined?
No, the access logging is done in the context of whichever location the
request finishes in. It doesn’t appear in your error=true log, because
a request like /my/login/page%3Ferror=true was not made.

(As a test, make a request like that, and you should see it in the
new file.)
Yes, as I mentioned above, my requests DO get logged (always). They
just don’t go to the log I want them to.

but nothing ever gets written there. Is it because the access logging
is already done by the time the location is determined?

How can I somehow log when someone accesses the “login” page with the
“error=true” parameter on the URL?

Try at the http level:

map $arg_error $log_error {
default 0;
true 1;
}

and at the server level:

error_page 418 @log-error;

if ($log_error) {
return 418;
}

location @log-error {
access_log my_special.log;
}

–appa

On Tue, Dec 18, 2012 at 09:05:30PM -0500, AJ Weber wrote:

Hi there,

So whatever location matches /my/login/page will also match
/my/login/page?error=true.

Does that explain why your initial attempts did not do what you expected?

No, unfortunately it doesn’t. I copied the “GET” from the “usual”
access log exactly. Thus, I know the call is being made, because it’s
being logged in the normal log, and I’m pretty sure I have the right
location string, because I copied it right out of the log.

For nginx location{} matching,

/my/login/page

and

/my/login/page?error=true

are exactly the same. It is not possible to have one matched by one
location, and the other matched by another.

(So you need something other than location{} matching to distinguish
them.)

f

Francis D. [email protected]

This solution worked. Many thanks to you AND Francis for your replies
to help.

I always cringe when using the if-statement because of the “bad press”
it’s gotten in the past. I understand the push to use “location”
wherever possible, but sometimes a well-placed, simple if-statement is
exactly what’s needed!

Now the logging is working, and I wrote a (really just modified an
existing) fail2ban “jail” to watch for IP’s trying to hack the site.
Nothing’s foolproof, but every little bit helps!

Thanks to all again,
AJ