How Allowlist approach can help fix several CWEs ?
- Allow List is also very commonly referred to as White List.
- Allow List defines a set of values that can be used for validation of any given input which is likely to originate from untrusted sources for e.g., User Input, external files, or Database.
- Allow List can turn out as a powerful way to mitigate several findings such as:
- CWE 89 / CWE 564 SQL Injection
- CWE 78 OS Command Injection
- CWE 94 Eval Injection
- CWE 601 URL Redirection
- CWE 73 External Control of Filename or path.
- CWE 470 Unsafe Reflection
- CWE 15 External Control of System or Configuration Setting
The below code receives a Zodiac field of the user and then prints it back to the user.
public class ZodiacGreeting extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)throws Exception {
String zodiac = (String) request.getParameter(”user_zodiac”);
String message = "Your Zodiac is “+zodiac;
PrintWriter out = response.getWriter();
out.println("<h1>" + message + "</h1>");
}
}
The above code has the potential for serious XSS because we have not validated variable $zodiac.Usually, you can avoid this XSS using the appropriate escaping/encoding method.
The objective of this article is not to brief you about how to do escaping/encoding and avoid XSS; but how to ensure the validity of this variable in the first place.
Now as we know the Zodiac would be one of the known zodiac signs as below:
Sagittarius, Virgo, Aquarius, Capricorn, Libra, Aries, Scorpio, Taurus, Pisces, Gemini, Leo, Cancer
We can implement validation as below:
Method using IF Condition
If(zodiac.equals("Sagittarius”) || zodiac.equals("Virgo”) || zodiac.equals("Aquarius”) || zodiac.equals("Capricorn”) || zodiac.equals("Libra”) || zodiac.equals("Aries”) ..
{
//do stuff with $zodiac
}
Using SWITCH Case:
boolean valid = true;
switch(zodiac){
case "Sagittarius” : break;
case "Virgo” : break;
case "Aquarius” : break;
case "Capricorn” : break;
case "Libra” : break;
..
..
default : valid = false;
}
if(valid){
//do stuff with $zodiac
}
Using Collection Utility
ArrayList<String> zodiacAllowlist = (ArrayList<String>)
Arrays.asList(new String[] { "Sagittarius", "Virgo", "Aquarius", "Capricorn","Libra","Aries","Scorpio",
"Taurus","Pisces","Gemini","Leo","Cancer"});
if(zodiacAllowlist.contains(zodiac)){
//do stuff with $zodiac
}
Of course, it is not limited to the above 3 logical implementations only, there would more ways a developer can think about writing his/her code.
Although all of the above validation implementations make total sense and are absolutely safe to use, the Veracode SAST tool, or for that matter any SAST tool, would not be able to detect this implicitly. And we will have to raise Mitigation By Design proposal explicitly and manually for every flaw flagged due to the usage of the variable.
The reason is the $zodiac variable is still considered tainted because of the origin of the value that is assigned to the variable. Being read from the HttpRequest object makes it tainted and will remain tainted until it is modified to an untainted value for e.g., hardcoded value.
Although all of the above validation implementations make total sense and are absolutely safe to use, the Veracode SAST tool, or for that matter any SAST tool, would not be able to detect this implicitly. And we will have to raise Mitigation By Design proposal explicitly and manually for every flaw flagged due to the usage of the variable.
The reason is the $zodiac variable is still considered tainted because of the origin of the value that is assigned to the variable. Being read from the HttpRequest object makes it tainted and will remain tainted until it is modified to an untainted value for e.g., hardcoded value.
String zodiac = (String) request.getParameter(”user_zodiac”);
To avoid this, we would refactor the validation routine a bit.
Method using IF condition
If(zodiac.equals("Sagittarius”)){
zodiac = "Sagittarius”;
// Variable is assigned a new hardcoded value.
// [Same value, but tainted => false ]
// do stuff with $zodiac
}
Using SWITCH
boolean valid = true;
switch(zodiac){
case "Sagittarius” :
zodiac = "Sagittarius”; //tainted => false
break;
case "Virgo” :
zodiac = "Virgo”; //tainted => false
break;
..
..
default : valid = false;
}
if(valid){
//do stuff with $zodiac
}
Using Collection Utility
We strongly recommend using the approach of using Allow list as expressed above. This is not only a legit solution for Input validation, but it also helps the scanner recognize this as Fix and would not flag certain CWEs.
Below is a design pattern that can be used which makes it super convenient to manage the Allow List which is referred to multiple times in the project.
Below are the scenarios of how Allow List approach could be a potential life-saver.
CWE 89 SQL Injection / CWE 564 SQL Injection in Hibernate
We can define an Allow list collection of all SQL queries in something like a “DBMaster” class and refer it in the Dao classes whenever required. It will help us to avoid any kind of dynamic construction of SQL queries
Refer to this link for details:
https://community.veracode.com/s/article/How-to-fix-CWE-89-SQL-Injection-flaws
We can also use Allow list approach for table name and column name if they are dynamic in the code level.
Refer to this link for details:
https://community.veracode.com/s/article/sql-injection-mitigation-page2
CWE 601 URL Redirection
To ensure safe URL Redirection, we are required to validate the URL variable which is flagged as they were originating from untrusted sources (external sources)
We would maintain an allow-list containing all possible URL that are expected to be used by the application.
There is a high possibility that the whole URL will not match (URL with different context, page, or even query string attached) but what we can do is at least validate the beginning part of the URL is matching to one of the Allow-list’s URL. With this approach, we will have to raise Mitigation by design proposal.
Summary:
We would use an equivalent approach as we discussed for CWE 601, We are required to validate the Class-name variable which is flagged as they were originating from untrusted sources(external sources)
We would maintain an allow-list containing all possible Class-names (inc. Package) which are expected to be used by the application.
Summary:
We can define multiple Allow lists, one containing the commands, second containing possible options for the commands. OR define a map (a key-value like structure) to hold allow list of commands as keys and command options as the list would be the value part of the associated key
It is likely possible that we may use some variables which cannot be hardcoded. But at least it makes sense to validate major part of command execution using the allow list approach and the other half using pattern checking. Combined mitigation would be the key. With this approach, we will have to raise Mitigation by design proposal.
CWE 94 Eval Injection
Same as OS Command Injection, you may want to consider a list for EVAL execution also.
CWE 502 Deserialization of Untrusted Data
Use case scenario: javax.naming.InitialContext.lookup()
Java Naming and Directory Interface (JNDI) allows clients to discover and look up data and objects via a name.
Avoid passing untrusted data to lookup() to identify the object. . When the name of the requested object is controlled by an attacker, it is possible to redirect a vulnerable application to a malicious rmi/ldap/corba server that can return an arbitrary object.
We can either split the connectionString into tokens for the example server name, initial catalog, etc. and get server names validated from an Allow List, and get initial catalog validated from its respective Allow List.
ArrayList<String> zodiacAllowlist = (ArrayList<String>)
Arrays.asList(new String[] { "Sagittarius", "Virgo", "Aquarius", "Capricorn","Libra","Aries","Scorpio",
"Taurus","Pisces","Gemini","Leo","Cancer"});
..
..
if(zodiacAllowlist.contains(zodiac)){
for(String z: zodiacAllowlist){
if(z.equals(zodiac)){
zodiac = z; //tainted => false
break;
}
}
//do stuff with $zodiac
}
We strongly recommend using the approach of using Allow list as expressed above. This is not only a legit solution for Input validation, but it also helps the scanner recognize this as Fix and would not flag certain CWEs.
Below is a design pattern that can be used which makes it super convenient to manage the Allow List which is referred to multiple times in the project.
Class AllowListUtil{
ArrayList<String> zodiacAllowlist = new ArrayList<String>(
Arrays.asList(new String[] { "Sagittarius", "Virgo", "Aquarius", "Capricorn","Libra","Aries","Scorpio",
"Taurus","Pisces","Gemini","Leo","Cancer"}));
public static List<String> getZodiacAllowList (){
return Collections.unmodifiableList(zodiacAllowlist);
}
public static String getCleanItemFromList(String str, List list){
if(list!=null && str!=null){
for(String s: list){
if(str.equals(s)){
return s; //hardcode value, tainted => false
} //if
}//for
}//if
}
}
The original code would be modified as below:
public class ZodiacGreeting extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)throws Exception {
String zodiac = (String) request.getParameter(”user_zodiac”);
String message;
message = "Your Zodiac is “+AllowListUtil.getCleanItemFromList(zodiac, AllowListUtil.getZodiacAllowList());
PrintWriter out = response.getWriter();
out.println("<h1>" + message + "</h1>");
}
}
Below are the scenarios of how Allow List approach could be a potential life-saver.
CWE 89 SQL Injection / CWE 564 SQL Injection in Hibernate
We can define an Allow list collection of all SQL queries in something like a “DBMaster” class and refer it in the Dao classes whenever required. It will help us to avoid any kind of dynamic construction of SQL queries
Refer to this link for details:
https://community.veracode.com/s/article/How-to-fix-CWE-89-SQL-Injection-flaws
We can also use Allow list approach for table name and column name if they are dynamic in the code level.
Refer to this link for details:
https://community.veracode.com/s/article/sql-injection-mitigation-page2
CWE 601 URL Redirection
To ensure safe URL Redirection, we are required to validate the URL variable which is flagged as they were originating from untrusted sources (external sources)
We would maintain an allow-list containing all possible URL that are expected to be used by the application.
There is a high possibility that the whole URL will not match (URL with different context, page, or even query string attached) but what we can do is at least validate the beginning part of the URL is matching to one of the Allow-list’s URL. With this approach, we will have to raise Mitigation by design proposal.
Class AllowListUtil{
static List<String> safeRedirectURLsList = (ArrayList<String>)Arrays.asList(new String[]{
"https://www.example.com/",
"https://ext.trustedsite.com/",
"https://auth.idpsite.com/",
"https://int.example.com/",
"https://www.example-preprd.com/"});
public static String getKnownSafeUrl(String url){
if(safeRedirectURLsList!=null && url!=null){
for(String s: safeRedirectURLsList){
if(url.equalsIgnoreCase(s)){
return s;
}
}
}
return null;
}
public static boolean validateUrlPrefix(String url){
if(safeRedirectURLsList!=null && url!=null){
for(String s: safeRedirectURLsList){
if(url.startsWith(s)){
return true;
} //if
}//for
}//if
return false;
}
}
//-------------------------------
public class RedirectServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
..
..
//Strict check --- > SAST shouldn’t flag CWE 601.
String red_url = getKnownSafeUrl(url);
if(red_url!=null){
response.sendRedirect(red_url);
}
..
//-------------------------------------------------
//Check only begin part of URL allowing different context & query //String if any.
// --- > SAST would flag CWE 601, but it makes it eligible for //Mitigation-By-Design.
if(AllowListUtil. validateUrlPrefix(url)){
response.sendRedirect(url);
}
}
}
Summary:
- getKnownSafeUrl() : Veracode SAST tool will automatically recognize the validation effort, so the flaw shouldn’t be flagged anymore.
- validateUrlPrefix() : Veracode SAST will not recognize the validation effort, but eligible for Mitigation-By-Design.
CWE 73 External Control of Filename or path.
We can define multiple Allow lists, one containing the potential folders that ideally files belong to, the second containing possible extensions for a given file.
Class AllowListUtil {
static List<String> targetFilePathsList = (ArrayList<String>)Arrays.asList(new String[]{"c:/usr/csv/","c:/app/data/","/usr/csv/","/app/data/","/usr/profiles/"});
static List<String> allowedFileExtensionList =(ArrayList<String>)Arrays.asList(new String[]{".csv",".pdf",".xls",".xlsx"});
public static boolean validatefilePath(String filename){
if(targetFilePathsList!=null && url!=null){
for(String s: targetFilePathsList){
if(file.startsWith(s)){
return true;
} //if
}//for
}//if
return false;
}
public static boolean validatefileExt(String filename){
if(allowedFileExtensionList!=null && url!=null){
for(String s: allowedFileExtensionList){
if(file.endsWith(s)){
return true;
} //if
}//for
}//if
return false;
}
}
//-------------------------------
Public File getSafeFile(String filename) throws Exception{
..
..
String absolutePath = File.getCanonicalPath(filename);
if (!AllowListUtil.validatefilePath(absolutePath) || !AllowListUtil.validatefileExt(absolutePath){
throw new ValidationException("Invalid path constructed!", path, absolutePath);
}
return new File(absolutePath);
}
Veracode SAST will not recognize the validation effort but is eligible for Mitigation-By-Design.CWE 470 Unsafe Reflection
The application uses untrusted data to load the class using Reflection. Here, the class names are dynamic and flagged because they are tainted data.We would use an equivalent approach as we discussed for CWE 601, We are required to validate the Class-name variable which is flagged as they were originating from untrusted sources(external sources)
We would maintain an allow-list containing all possible Class-names (inc. Package) which are expected to be used by the application.
Class AllowListUtil{
static List<String> safeClassList = (ArrayList<String>)Arrays.asList(new String[]{
"org.commons.apache.Utility",
"oracle.jdbc.driver.OracleDriver",
"com.mysql.jdbc.Driver",
"com.sybase.jdbc.SybDriver",
"com.example.pack1.SomeClass"});
static List<String> safePackageList = (ArrayList<String>)Arrays.asList(new String[]{
"com.example.pkg1.",
"com.example.pkg2.",
"com.example2.pkg3."});
public static String getKnownSafeClass(String cls){
if(safeClassList!=null && url!=null){
for(String s: safeClassList){
if(cls.equalsIgnoreCase(s)){
return s;
}
}
}
return null;
}
public static boolean validatePackagePrefix(String cls){
if(safePackageList!=null && url!=null){
for(String s: safePackageList){
if(cls.startsWith(s)){
return true;
}
}
}
return false;
}
}
//-------------------------------
public class HelloWorld{
public void someFunction(){
..
..
//Strict check --- > SAST shouldn’t flag CWE 470.
String safe_clz = getKnownSafeClass (clz);
if(safe_clz!=null){
Class.forName(safe_clz);
}
..
//-------------------------------------------------
//Check only begin part of package
// --- > SAST would flag CWE 470, but makes it eligible for //Mitigation-By-Design.
if(AllowListUtil. validatePackagePrefix (clz)){
Class.forName(clz);
}
}
}
Summary:
- getKnownSafeClass() : Veracode SAST tool will automatically recognize the validation effort, so the flaw shouldn’t be flagged anymore.
- validatePackagePrefix() : Veracode SAST will not recognize the validation effort, but eligible for Mitigation-By-Design
CWE 78 OS Command Injection
We can define multiple Allow lists, one containing the commands, second containing possible options for the commands. OR define a map (a key-value like structure) to hold allow list of commands as keys and command options as the list would be the value part of the associated key
Map<String,List> commandsAndOptionsMap = new HashMap<String,List>();
commandsAndOptionsMap.put("cmd", Arrays.asList(new String[]{"\\c","dir","date"}));
commandsAndOptionsMap.put("sh", Arrays.asList(new String[]{"-c","ls"}));
commandsAndOptionsMap.put("bash", Arrays.asList(new String[]{"-c","ls"}));
commandsAndOptionsMap.put("host", Arrays.asList(new String[]{"-t","a"}));
commandsAndOptionsMap.put("ls", Arrays.asList(new String[]{"-al"}));
It is likely possible that we may use some variables which cannot be hardcoded. But at least it makes sense to validate major part of command execution using the allow list approach and the other half using pattern checking. Combined mitigation would be the key. With this approach, we will have to raise Mitigation by design proposal.
CWE 94 Eval Injection
Same as OS Command Injection, you may want to consider a list for EVAL execution also.
CWE 502 Deserialization of Untrusted Data
Use case scenario: javax.naming.InitialContext.lookup()
Java Naming and Directory Interface (JNDI) allows clients to discover and look up data and objects via a name.
Avoid passing untrusted data to lookup() to identify the object. . When the name of the requested object is controlled by an attacker, it is possible to redirect a vulnerable application to a malicious rmi/ldap/corba server that can return an arbitrary object.
Class AllowListUtil{
static List<String> jndiNamesList = (ArrayList<String>)Arrays.asList(new String[]{"","",""});
public static String getCleanJndiName(String cls){
..
}
}
//------------------
String safe_lookupobj = getCleanJndiName (lookup_obj);
if(safe_lookupobj!=null){
ctx.lookup(safe_lookupobj);
}
CWE 15 External Control of System or Configuration Setting
Flagged for establishing a SqlConnection or OleDbConnection using connectionString derived from untrusted sources.
We can define an Allow List of the possible connection strings and use it for validation in a similar fashion as explained in previous scenarios.We can either split the connectionString into tokens for the example server name, initial catalog, etc. and get server names validated from an Allow List, and get initial catalog validated from its respective Allow List.
Class AllowListUtil{
static List<String> connectionStringList = (ArrayList<String>)Arrays.asList(new String[]{"","",""});
static List<String> ServernameList = (ArrayList<String>)Arrays.asList(new String[]{"","",""});
static List<String> DbList = (ArrayList<String>)Arrays.asList(new String[]{"","",""});
public static String getCleanConnStr(String connstr){
..
}
//------------------
String safe_connectionStr = getCleanConnStr(connectionstr);
Topics (0)
Related Articles
How to Fix CWE 117 Improper Output Neutralization for Logs 37.44KNumber of Views CWE 89 SQL Injection flaws -Mitigation Page 2 11.85KNumber of Views How to fix flaws of the type CWE 73 External Control of File Name or Path 104.89KNumber of Views Getting a perfect score of 100 and no flaws for my Python Application. Are we good? 246Number of Views How to fix CWE 89 SQL Injection flaws? 24.69KNumber of Views
This topic isn't available in this community.
Related Topics
Ask the Community
Get answers, share a use case, discuss your favorite features, or get input from the Community.
.png)