Re: htaccess limits

Paul <[email protected]> Fri, 8 May 2026 14:20:02 -0400
Newsgroups gmane.comp.apache.user
Organization Stormy Weather
Message-ID <[email protected]>
On 2026-05-08 06:53, Nutchanon Wetchasit wrote:
> On Thu, 7 May 2026, Stormy-SDLU wrote:
> 
>> What is best practice to disallow all access to the cgi-bin
>> except for the local web form.
>> I have a vague memory of 127.0.0.1 being usable by apache 2.4.x
> 
> Sanity check first: by "local web form", did you mean:
> 
> A. HTML form located on the same website.
Yes,
> B. Browser accessing such form is running right on the server;
>     but the attackers came from the Internet. (Unlikely)
No, intranet and from external I{P addresses
> C. Browser accessing such form is running on same Intranet as the server
>     (Intranet, not Internet); but the attackers came from the Internet.
As above, tested from  internal and external IPs
[snip]
> F. A, B, and C combined.
See above
> If what you meant was just A., then `.htaccess` alone would not help you
> that much other than papering up a bit over the issue. [1]
> Attacker could bypass such measure in a relatively-easy way
> once he wised up to what you were trying to do.
Agreed.  At this point it's only about 75 effective
> 
> A more proper way to prevent such kind of abuse, is to implement
> the same measure that's used for preventing cross-site request forgery (CSRF).
> This is not really doable in `.htaccess`, and require you to switch the form
> from static HTML to CGI, as well as modifying the CGI application itself
> to add such protection. [2][4]

I'm looking at CSRF and other possibilities (thanks for the extensive 
notes below), but am wondering if I could use a modified
     <Directory /www/mysite/cgi-bin???>
         <LimitExcept GET HEAD>
             Require all denied
         </LimitExcept>
     </Directory>
for just the cgi directory?
It's in production, so I haven't tried yet

Again tnx and br -- Paul

> 
> But if your answer was not A. however, then we could continue to discuss
> about using `.htaccess` to ward against such access.
> 
> Regards,
> Nutchanon Wetchasit
> (Just another Apache user)
> 
> 
> [1] By checking the `Referer:` header value on the requests to the affected
>      CGI application, against the expected URL of HTML form that was supposed
>      to be invoking it. If it matches, let the request through;
>      otherwise deny the request.
> 
>      The most straightforward way to do it would be via mod_rewrite's
>      `RewriteCond`/`RewriteRule` directives:
> 
>          RewriteCond %{HTTP_REFERER} !=http://example.com/preciousform/
>          RewriteRule cgi-bin/precious/program.cgi - [R=403,L]
> 
>      Other ways (with more side effect) are location-confined version
>      of new-style mod_authz_core's `Require`:
> 
>          <Files cgi-bin/precious/program.cgi>
>              SetEnvIf Referer "^http://example\.com/preciousform/$" preciousform_referrer
>              Require env preciousform_referrer
>          </Files>
> 
>      And location-confined version of classic HTTPd 2.2-style
>      mod_access_compat's `Allow from`/`Deny from`:
> 
>          <Files cgi-bin/precious/program.cgi>
>              Order Allow,Deny
>              SetEnvIf Referer "^http://example\.com/preciousform/$" preciousform_referrer
>              Allow from env=preciousform_referrer
>          </Files>
> 
>      Note that:
> 
>      - These assume you're doing it in `.htaccess` at the root directory
>        of the virtual host (or inside `<VirtualHost>` configuration itself).
>      - The placeholder HTML form URL used my example is
>        "http://example.com/preciousform/" (beware that some place
>        in the examples required a regular expression from).
>      - The placeholder on-site location of the CGI application
>        in my example being "cgi-bin/precious/program.cgi"
>        (note the absence of slash prefix).
>      - The "preciousform_referrer" part is a variable that would become exist
>        when the request satisfies condition (having a specified
>        HTTP Referer value). You may change the variable name, but make sure
>        to change all of them in the example code to use the same changed name.
>        But if you have more than one CGI programs which you're adding
>        protection to in such way, make sure that code for each of them
>        use different variable name from another CGI program.
>      - Don't forget to substitute the placeholders I mentioned
>        if you decide to use these.
> 
> [2] Usual method is when user accessed the form, in the form CGI script,
>      you'd assign user a session cookie; then generate one random number,
>      associate it with that session identifier, save that association
>      on some kind of server-side database [3], and display the usual
>      HTML form page, with the usual form, but with one additional hidden field
>      (`<input type="hidden" ...>`) that has the value of aforementioned
>      random number.
> 
>      And once user pressed submit on the form, and POST request arrived
>      at the application's CGI script, check the session cookie,
>      look up in the server-side database to find the correct random number,
>      then check that it must match against the hidden field submitted
>      from client. If any step failed, fail the request, say "Form expired"
>      and direct user back to the original CGI form CGI.
> 
>      (Thus, when attacker blindly flung unsolicited POST requests
>      to your CGI application, he would have neither valid session cookie,
>      nor correct random number that your CGI application recognize;
>      and your application would reject such requests)
> 
>      But this method is quite involved, and you also need to have both
>      your CGI form and CGI application automatically weed out the
>      "used"/"expired" random number associations in the database too.
> 
>      So in Perl CGI, I will not recommend this "usual" method;
>      I would recommend TOTP method instead. [4]
> 
> [3] PHP for example, uses flat-file database for this kind of session data;
>      and it has built-in ways of automatic data removal of expired sessions.
> 
> [4] The TOTP method of (limited) CSRF protection works by having
>      a hidden field in the CGI form which contains an OTP number generated
>      by using on-server TOTP key file, against the timeframe-number
>      (Unix timestamp divided by 30) of the request for the form.
> 
>      Then the CGI application that services the POST request, would generate
>      multiple OTP numbers, using the same on-server TOTP key file--
>      against timeframe-number of the POST request's access time,
>      as well as multiple timeframe-numbers prior to it
>      for the period you deem the form to still be valid.
>      (Generate 20 OTP numbers backward to compare,
>      if you would like the form to stay valid for 10 minutes, for example)
> 
>      Then the CGI application would have to check that the hidden
>      field was submitted in the POST request, and then try to match it
>      to the OTP numbers it generated just now. If the submitted hidden value
>      matched just one of these OTP number, the request was valid and
>      you could proceed. Otherwise, reject it, say "Form expired" or whatever,
>      then direct user back to the original CGI form CGI.
> 
>      (Thus, when attacker blindly flung unsolicited POST requests
>      to your CGI application, he would not have the correct
>      cryptographically-generated OTP number to provide;
>      meaning your application could reject such requests)
> 
>      This method needs neither cookie nor server-side database;
>      only a RFC 6238 TOTP library (which CPAN has several, I believe),
>      and a key file-- which you guard with the same consideration
>      as password file, but less critical.
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [email protected]
> For additional commands, e-mail: [email protected]
>