Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript challenge for HTTP DDoS mitigation #536

Closed
krizhanovsky opened this issue May 26, 2016 · 3 comments · Fixed by #920
Closed

JavaScript challenge for HTTP DDoS mitigation #536

krizhanovsky opened this issue May 26, 2016 · 3 comments · Fixed by #920

Comments

@krizhanovsky
Copy link
Contributor

krizhanovsky commented May 26, 2016

If DDoS bot is able to process cookies and do redirects sent by sticky cookie, then JavaScript is useful to challenge a bot. So http_sticky module should be extended to http_challenge module which should implement JavaScript challenge as well.

The module shall do basically the same as sticky cookie, but using JavaScript instead of HTTP redirects: send 200 response with HTML document containing JavaScript code which sets encrypted/hashed Cookie and requests the same URI.

There is reference implementation by @kyprizel.

There is a good discussion about PhantomJS detection, but all the methods aren't infalliable,

@krizhanovsky krizhanovsky added this to the 0.5.0 Web Server milestone May 26, 2016
@krizhanovsky krizhanovsky modified the milestones: 0.6 WebOS, 0.5.0 Web Server Feb 12, 2017
@krizhanovsky krizhanovsky modified the milestones: 1.0 WebOS, 0.5.0 Web Server Oct 31, 2017
@krizhanovsky
Copy link
Contributor Author

krizhanovsky commented Nov 9, 2017

The module can be configured with following syntax:

js_challenge <resp_code> <delay_min> <delay_range> [delay_limit] [script_template]

e.g.

js_challenge resp_code=503 delay_min=1000 delay_range=1000 delay_limit=3000 /etc/ddos_redirect.html

script_template is an optional argument specifying a file with HTML template, by default it must contain

<html>                                                                                
    <body>                                                                            
        <p></p>&nbsp;<p></p>                                                          
        <h2 align='center'>                                                           
            <a href="http://tempesta-tech.com">Tempesta FW</a>                        
            is verifying your browser, please wait a little bit...                     
        </h2>                                                                         
        <p></p>&nbsp;<p></p>                                                          
                                                                                      
        <script>                                                                      
            var prefix = "[% STICKY_NAME %]";                                         
            var delay_min = [% DELAY_MIN %];                                          
            var delay_range = [% DELAY_RANGE %];                                      
            if (navigator.cookieEnabled                                               
                && document.cookie.startsWith(prefix))                                
            {                                                                         
                var ts = "0x" + document.cookie.substr(prefix.length + 1, 16);        
                setTimeout(function() {                                               
                    location.reload();                                                
                }, delay_min + Number(ts) % delay_range);                             
            } else {                                                                  
                document.write("<h3 align='center' style='color:red'>"                
                               + "Please enable cookies and reload"                   
                               + " the page</h3>");                                   
            }                                                                         
        </script>                                                                     
    </body>                                                                           
</html>             

Note that this is template which must be compiled at system start by tempesta.sh. Use https://github.com/tempesta-tech/tempesta-tech.com/blob/master/perl/compile.pl#L58 for the template compilation. We need generic HTML template to allow a system administrator to write custom redirects. Later the templates can be also adjusted by Tempesta FW in runtime to allow #488 set the delay values according to the client weight.

JavaScript challenge module replies to all requests with resp_code, 503 by default, status code and an HTML document containing the resulting HTML document. delay_min and delay_range are appropriate values for the template variables in the script, in milliseconds: minimal timeout to make a client wait and a range within the timeout varies. The timeout is calculated and verified using Sticky cookie, so the challenge requires Sticky cookie switched on. delay_limit, an optionl argument, specifies maximum difference between current jiffies value when a consequent request is received and a timestamp specified in the sticky cookie. Configuration process must enforce the value to be greater than delay_range + delay_min and show warning if it's less than delay_range + delay_min + 100. Default value is delay_range + delay_min + 1000 (enough ever fro cross atlantic connections and relatively slow hardware and software).

Having the script executed, all following requests will have the right cookie value, so with the challenge switched on we should block all following requests having no set cookie. However, the challenge can not be used for all requests, e.g. images - a browser won't execute the JS code if receives the challenge. Thus, the module sends the redirect only for requests having in Accept header /html. The next limitation for the module is that only GET requests can be challenged this way. The limitations are required to make sure that normal browser is able to execute the challenge, e.g. if the module sent JS code in response to image request, then it'd break the application since browser doesn't try to execute execute <img>'s. All requests not satisfying the limitations and not having the cookie must be blocked either by error response or silent drop. The limitations don't make any problems for normal web applications since the first request is a request to an HTML document referencing all not challengeble medias.

The algorithm for the challenge:

  1. receive a client request and check it against the limitations described above, probably block the request;
  2. respond with the JS challenge and Sticky cookie;
  3. respond with the JS challenge or block all requests from the client, even with the correct Cookie value, before the timeout elapsed;
  4. verify the Cookie value and check that cookie_timestamp + delay_min + cookie_timestamp % delay_range < jiffies < cookie_timestamp + delay_limit

Please add the description of the feature to Configuration and DDoS mitigation Wiki pages.

@krizhanovsky krizhanovsky modified the milestones: 1.0 Web Server, 0.6 KTLS Jan 9, 2018
@krizhanovsky krizhanovsky modified the milestones: 0.6 KTLS, 0.5 alpha Jan 9, 2018
@hroost
Copy link

hroost commented Jan 19, 2018

FYI: cloudflare returns 503 status code when site is in 'under attack' mode and you see JS challenge (and 403 with captcha, as far as I know).
Is it okey to reply with 200 code in you case?

@krizhanovsky
Copy link
Contributor Author

@hroost yes, good comment. I adjusted the configuration requirement to make the response code configurable. I also agree that returning 200 code isn't good if we actually return something other than requested resource. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants