DoS - DrAlzahraniProjects/csusb_fall2024_cse6550_team2 GitHub Wiki
Denial of Service (DoS) Protection
Denial of Service (DoS) attacks overwhelm a target system with a flood of illegitimate requests, preventing legitimate users from accessing services. This guide provides an implementation plan for protecting applications from DoS attacks using rate limiting.
Sections
Installation
For this app we are using StreamLit via Docker to implement rate limiting for preventing DoS attack, so follow these steps to verify that you have a proper Docker installation.
Step 1. Ensure Docker is Installed
Docker is the backbone of our containerized workflow. It enables you to package your application and its dependencies into a portable container, ensuring consistency across development, testing, and production environments.
Instructions:
- Open your terminal and run the following command to verify if Docker is installed: bash docker --version
This command should return the installed Docker version, as shown in the screenshot below:
Figure 1: If Docker is already installed, it will show you the version like this.
If Docker isn’t installed, proceed to the next step.
-
Download and install Docker Desktop from the official Docker website. After downloading, follow the installation instructions specific to your operating system (Windows, macOS, or Linux). Once installed, you should be able to verify the version again using the previous command.
-
After installation, verify Docker is working by running:
bash docker run hello-world
This command pulls and runs a test image to confirm your Docker setup is functional.
Figure 2: If Docker is installed properly, it will give you the message like this.
Configuration
Variables
Configure the following environment variables in "streamlit.py" file for rate limiting:
bash MAX_REQUESTS_PER_MINUTE = BLOCK_DURATION_SECONDS =
Figure 3: Variables used for setting up the maximum number of requests per user allowed per minute and block duration
3. Implementation
Step 1: Define Rate-Limiting Logic
Add the 'check_rate_limit' function into the "streamlit.py" file to track request timestamps and enforce limits:
def check_rate_limit(): """Check if the user has exceeded the rate limit.""" now = time.time() if "request_timestamps" not in st.session_state: st.session_state.request_timestamps = []
# Remove timestamps older than a minute
st.session_state.request_timestamps = [
t for t in st.session_state.request_timestamps if now - t <= 60
]
# Check if the rate limit has been exceeded
if len(st.session_state.request_timestamps) >= MAX_REQUESTS_PER_MINUTE:
if "block_until" in st.session_state and st.session_state.block_until > now:
st.error(
"You’ve reached the limit of 10 questions per minute because the server has limited resources. Please try again in 3 minutes."
)
st.stop()
else:
st.session_state.block_until = now + BLOCK_DURATION_SECONDS
st.error(
"You’ve reached the limit of 10 questions per minute because the server has limited resources. Please try again in 3 minutes."
)
st.stop()
# Add current timestamp to the list
st.session_state.request_timestamps.append(now)
Explanation:
1. check_rate_limit Function:
- Maintains a list of timestamps for user requests in st.session_state.
- Removes timestamps older than one minute to keep the list up-to-date.
- Checks if the number of timestamps exceeds the maximum allowed requests per minute.
- Implements a blocking mechanism that prevents further requests for three minutes after hitting the rate limit.
Step 2: Integrate with User Input Handling
Call check_rate_limit in the handle_user_input function.
Figure 4: Calling the "check_rate_limit" function for each user input prompt
Explanation:
- When a user sends a request, the check_rate_limit function is invoked to ensure they haven’t exceeded the allowed number of requests per minute.
- If they exceed the limit, an error message is shown, and further requests are blocked for three minutes.
- If the user is within the limit, their request is processed as usual
4. Usage
Step 1. Building the Docker Image
Once your Dockerfile is prepared, you can build the Docker image. This process packages your application and its dependencies into a single image.
Instructions:
- Run the following command to build the Docker image: bash docker build -t team2-app .
This command creates a Docker image named team2-app. The terminal will display the build process, and a successful build should output something similar to the screenshot below:
Figure 5: To view the build details you can access that URL
Step 2. Running the Docker Container
After the Docker image is built, you can run the container using the following command:
bash docker run --env-file .env -p 5002:5002 -v $(pwd):/app team2-app
This exposes the Streamlit app on port 5002 so you can now view your Streamlit app in your browser using the following URL: bash http://0.0.0.0:5002/team2
Step 3. Simulate Requests
Use a browser to send multiple requests in a short span.
Figure 6: Send multiple requests in 1 minute
Expected Behavior:
The system will allow up to 10 requests per minute. Exceeding the limit will show an error message: “You’ve reached the limit of 10 questions per minute because the server has limited resources. Please try again in 3 minutes.”
Figure 7: It will give an error message and block the user for specified period of time
5. Troubleshooting
Common Issues:
1. Rate Limit Not Enforced:
Cause: Session state not initialized
Solution: Verify the initialization in streamlit.py
Figure 8: Check if the session has been initialized or not
2. Unexpected Blocking:
Cause: Clock skew or incorrect timestamps
Solution: Use time.time() consistently and verify the server clock settings
3. Docker Environment Issues:
Cause: Missing dependencies
Solution: Rebuild the Docker image by the following command
bash docker-compose build
Conclusion
This project offers a DoS protection by rate limiting and logging. Properly configuring these tools can help secure your infrastructure against various forms of malicious activity.