IP Whitelisting
IP whitelisting is a security feature that restricts access to the UBU Finance backend to a predefined list of IP addresses.
Overview
IP whitelisting adds an additional layer of security by ensuring that only requests from approved IP addresses are processed. This is particularly useful for internal APIs or admin interfaces that should only be accessible from specific locations.
How It Works
When IP whitelisting is enabled, the system checks the client's IP address against a list of allowed IP addresses. If the client's IP is not on the whitelist, the request is rejected with a 403 (Forbidden) status code.
The system supports both individual IP addresses and CIDR notation for IP ranges. It also has an option to always allow localhost connections for development purposes.
Configuration
IP whitelisting can be configured via environment variables or by modifying the app/config/security_config.py file.
Environment Variables
# IP Whitelist
IP_WHITELIST_ENABLED=true
IP_WHITELIST=192.168.1.0/24,10.0.0.1,203.0.113.0/24
IP_WHITELIST_ALLOW_LOCALHOST=true
Configuration Parameters
| Parameter | Description | Default |
|---|---|---|
IP_WHITELIST_ENABLED |
Enable/disable IP whitelisting | false |
IP_WHITELIST |
Comma-separated list of allowed IP addresses or CIDR ranges | "" |
IP_WHITELIST_ALLOW_LOCALHOST |
Allow localhost connections (127.0.0.1) | true |
Implementation
The IP whitelisting feature is implemented in the app/security/ip_whitelist.py module. The module uses the ipaddress library to validate IP addresses and check if an IP is within an allowed range.
API Responses
When a client's IP address is not on the whitelist, the API returns a 403 (Forbidden) status code with a JSON response:
Managing the Whitelist
The whitelist can be managed programmatically through the Security API. This allows administrators to add or remove IP addresses from the whitelist without restarting the application.
Admin API Endpoints
The following endpoints are available for managing the whitelist:
POST /api/admin/security/whitelist/add/{ip}: Add an IP address to the whitelistPOST /api/admin/security/whitelist/remove/{ip}: Remove an IP address from the whitelist
These endpoints require admin privileges and are protected by role-based access control.
Client Implementation Examples
Adding an IP to the Whitelist
import requests
def add_ip_to_whitelist(base_url, token, ip_address):
url = f"{base_url}/api/admin/security/whitelist/add/{ip_address}"
headers = {
"Authorization": f"Bearer {token}"
}
response = requests.post(url, headers=headers)
if response.status_code == 200:
print(f"Successfully added {ip_address} to whitelist")
return True
else:
print(f"Failed to add {ip_address} to whitelist: {response.json()}")
return False
async function addIpToWhitelist(baseUrl, token, ipAddress) {
const url = `${baseUrl}/api/admin/security/whitelist/add/${ipAddress}`;
const headers = {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
};
try {
const response = await fetch(url, {
method: 'POST',
headers: headers
});
const data = await response.json();
if (response.ok) {
console.log(`Successfully added ${ipAddress} to whitelist`);
return true;
} else {
console.error(`Failed to add ${ipAddress} to whitelist: ${data.detail}`);
return false;
}
} catch (error) {
console.error(`Error adding IP to whitelist: ${error}`);
return false;
}
}
#!/bin/bash
add_ip_to_whitelist() {
local base_url=$1
local token=$2
local ip_address=$3
response=$(curl -s -w "%{http_code}" \
-X POST \
-H "Authorization: Bearer $token" \
"$base_url/api/admin/security/whitelist/add/$ip_address")
http_code=${response: -3}
content=${response:0:${#response}-3}
if [ "$http_code" == "200" ]; then
echo "Successfully added $ip_address to whitelist"
return 0
else
echo "Failed to add $ip_address to whitelist: $content"
return 1
fi
}
using System;
using System.Net.Http;
using System.Threading.Tasks;
public class IpWhitelistManager
{
private readonly HttpClient _client;
private readonly string _baseUrl;
public IpWhitelistManager(string baseUrl)
{
_client = new HttpClient();
_baseUrl = baseUrl;
}
public async Task<bool> AddIpToWhitelistAsync(string token, string ipAddress)
{
string url = $"{_baseUrl}/api/admin/security/whitelist/add/{ipAddress}";
_client.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
try
{
HttpResponseMessage response = await _client.PostAsync(url, null);
if (response.IsSuccessStatusCode)
{
Console.WriteLine($"Successfully added {ipAddress} to whitelist");
return true;
}
else
{
string content = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Failed to add {ipAddress} to whitelist: {content}");
return false;
}
}
catch (Exception ex)
{
Console.WriteLine($"Error adding IP to whitelist: {ex.Message}");
return false;
}
}
}
Removing an IP from the Whitelist
import requests
def remove_ip_from_whitelist(base_url, token, ip_address):
url = f"{base_url}/api/admin/security/whitelist/remove/{ip_address}"
headers = {
"Authorization": f"Bearer {token}"
}
response = requests.post(url, headers=headers)
if response.status_code == 200:
print(f"Successfully removed {ip_address} from whitelist")
return True
else:
print(f"Failed to remove {ip_address} from whitelist: {response.json()}")
return False
async function removeIpFromWhitelist(baseUrl, token, ipAddress) {
const url = `${baseUrl}/api/admin/security/whitelist/remove/${ipAddress}`;
const headers = {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
};
try {
const response = await fetch(url, {
method: 'POST',
headers: headers
});
const data = await response.json();
if (response.ok) {
console.log(`Successfully removed ${ipAddress} from whitelist`);
return true;
} else {
console.error(`Failed to remove ${ipAddress} from whitelist: ${data.detail}`);
return false;
}
} catch (error) {
console.error(`Error removing IP from whitelist: ${error}`);
return false;
}
}
#!/bin/bash
remove_ip_from_whitelist() {
local base_url=$1
local token=$2
local ip_address=$3
response=$(curl -s -w "%{http_code}" \
-X POST \
-H "Authorization: Bearer $token" \
"$base_url/api/admin/security/whitelist/remove/$ip_address")
http_code=${response: -3}
content=${response:0:${#response}-3}
if [ "$http_code" == "200" ]; then
echo "Successfully removed $ip_address from whitelist"
return 0
else
echo "Failed to remove $ip_address from whitelist: $content"
return 1
fi
}
using System;
using System.Net.Http;
using System.Threading.Tasks;
public class IpWhitelistManager
{
private readonly HttpClient _client;
private readonly string _baseUrl;
public IpWhitelistManager(string baseUrl)
{
_client = new HttpClient();
_baseUrl = baseUrl;
}
public async Task<bool> RemoveIpFromWhitelistAsync(string token, string ipAddress)
{
string url = $"{_baseUrl}/api/admin/security/whitelist/remove/{ipAddress}";
_client.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
try
{
HttpResponseMessage response = await _client.PostAsync(url, null);
if (response.IsSuccessStatusCode)
{
Console.WriteLine($"Successfully removed {ipAddress} from whitelist");
return true;
}
else
{
string content = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Failed to remove {ipAddress} from whitelist: {content}");
return false;
}
}
catch (Exception ex)
{
Console.WriteLine($"Error removing IP from whitelist: {ex.Message}");
return false;
}
}
}
Best Practices
- Use CIDR Notation for IP Ranges: Instead of adding individual IP addresses, use CIDR notation to specify ranges (e.g.,
192.168.1.0/24). - Regularly Review the Whitelist: Periodically review and update the whitelist to remove unnecessary entries.
- Combine with Other Security Measures: IP whitelisting should be used in conjunction with other security measures like authentication and rate limiting.
- Document Whitelisted IPs: Maintain documentation of whitelisted IP addresses and their purpose.
- Consider Dynamic IPs: Be aware that some clients may have dynamic IP addresses that change over time.
- Test Thoroughly: Test the whitelist configuration thoroughly to ensure legitimate users are not blocked.
- Monitor Rejected Requests: Monitor and log rejected requests to identify potential issues or attacks.