Mitigating Atom-Based Denial of Service Attacks in Elixir
Published: Jun 19 2023
Atoms are an integral part of the Elixir programming language and play a crucial role in its design and functionality. They provide a lightweight and efficient way to represent and compare constants, making them incredibly useful in many scenarios. However, it’s essential to understand that atoms, if misused, can pose a significant security risk. In this blog post, we will explore the potential dangers of allowing user input to create new atoms and discuss a solution to mitigate the risk.
The Power and Peril of Atoms
In Elixir, atoms are unique constants that are stored in a global atom table. They are often used to represent status codes, configuration values, and other fixed values. One of the key advantages of atoms is their efficiency, as they are stored as 1-word values and comparison operations are lightning-fast.
However, the BEAM, the virtual machine that runs Elixir, imposes a limit on the number of atoms that can be created. This limit is defined by the +t option during compilation, which defaults to 1,048,576 atoms. Once this limit is reached, the system crashes, leading to a Denial of Service (DoS) condition.
Atom-Based DoS Attacks:
Allowing user input to create new atoms without any validation or control can lead to a potential Atom-Based Denial of Service (DoS) attack. An attacker can exploit this vulnerability by continuously sending unique atom names, ultimately causing the system to reach the atom limit and crash.
Mitigating the Risk:
To prevent ABDoS attacks and safeguard your Elixir applications, it is crucial to validate and control the atoms being created. Here are a few best practices to consider:
Avoid creating atoms directly from user input: Refrain from using the String.to_atom/1 function, as it can create a new atom for each unique string it receives. Instead, prefer functions like String.to_existing_atom/1 or String.to_atom/1 with a defined whitelist of allowed atom values.
Use existing atoms or predefined values: When possible, use existing atoms or predefined values that are known and limited. For example, if you are accepting a status code from a user, ensure it matches a predefined set of accepted codes instead of creating a new atom for each user-supplied value.
Implement input validation: Validate user input thoroughly to ensure it adheres to expected patterns and constraints. Use regular expressions, predefined patterns, or custom validators to ensure that the input is within acceptable bounds.
Limit atom creation through pattern matching: Utilize pattern matching to handle user input instead of creating atoms. By pattern matching against a predefined set of accepted values, you can avoid creating unnecessary atoms and prevent ABDoS attacks.
Atoms are a powerful feature of Elixir, enabling efficient representation and comparison of constants. However, their unlimited creation from unvalidated user input can lead to serious security vulnerabilities, potentially resulting in a DoS condition. By following best practices like validating user input and using existing atoms, you can significantly reduce the risk of Atom-Based Denial of Service attacks. Remember, it’s crucial to be proactive in ensuring the security of your Elixir applications and protect them from potential threats.