Act Against Security Anomalies
Expect and act against abnormal security related behaviors in your code
In order to prevent hackers abusing our software, as developers we have to get high on security related information; attacks, payloads, defenses… But there are lots of areas to cover and we don’t have time. In this post, we will try to list a few coding patterns, when applied can give you an upper-hand over malicious users.
Zero Length Aggregates or Null Returns
Missing null checks is the root of so many production defects, right? A systematic and simple checking of null values can save lots of lost hours or perhaps days of your support, customer success and agile teams. Additionally, it can also save you from some weird security problems;
So, for example, during the execution of the code below if you expect a non-null receiptid, instead of writing this;
receiptId = Session["receiptid"];
return ReadReceipt(receiptId);
write this;
receiptId = Session["receiptid"];
if(receiptId == null)
{
// log, create alarm, return
}
return ReadReceipt(receiptId);
If the receiptid is null, there’s a high probability that something funky is going on…
Targeted Exception Handling
A similar argument is valid for exception management. Most of the time the main opportunity the exception handling provides is cleaning up resources that were borrowed such as file/network streams or database connections upon unexpected problems. This is a classical and reliable fail-safe behavior.
So, for example, instead of writing a code like this, which is secure against XXE attacks by itself;
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Ignore;
XmlReader xmlReader = XmlReader.Create(input, settings);
var root = XDocument.Load(xmlReader, LoadOptions.PreserveWhitespace);
do this, for further ability to act when someone is messing with us;
try
{
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Ignore;
XmlReader xmlReader = XmlReader.Create(input, settings);
var root = XDocument.Load(xmlReader, LoadOptions.PreserveWhitespace);
}
catch(XmlException xe)
{
// log, create alarm, return
}
You can apply a similar pattern to these operations;
- Deserialization
- Cryptography
- XML Parsing
- Regular Expression
- Arithmetic Operations
The key is to use non-generic, specific exception classes, which is always a good idea anyways.
Normalization on User Inputs
By definition, normalization is to get the simplest form of something. And since hackers substantially rely on encoding techniques when they are sending malicious inputs to our applications, normalization can be one of the most effective and easy ways to seize them.
So, instead of writing this, which is by itself immune to Path Traversal attacks;
fileName = new FileInfo(fileName).Name;
string path = @"E:\uploaded_files\" + fileName;
// do I/O on path
do this, for a more flexible security related actions;
string normalizedFileName = new FileInfo(fileName).Name;
if (normalizedFileName != fileName)
{
// log, create alarm, return
}
Invalid Input Against Whitelists
Whitelisting is “accepting only what is expected”. In other words, if we come across some input that we do not expect, we reject it.
So, what happens when an unexpected input arrives? Whatever your whitelist validation method is, if it fails don’t just return 500. Make sure you log, send an alarm perhaps and then return.
public Response GetTicketDetails(string ticketNo)
{
if (IsValid(ticketNo))
{
// log, optionally an alarm, return
}
}
Simple input validations aside, this pattern can also be applied over lots of other scenarios. Another good example is the algorithms used by the JWT tokens. Just read this.
Actions Against AuthN and AuthZ
One of the most critical parts of software from a security point of view are the authentication and the authorization mechanisms.
Our users shouldn’t use certain parts of our application without valid credentials and they shouldn’t access parts where they don’t have any privileges. There’s a high-stake here to be careful.
Here’s a simple DTO, ViewModel class when used in a UpdateProfile action is immune to Mass Assignment attacks since there’s no way of updating the Role or IsAdmin field of the user on the actual persistent data store.
public class UserViewModel
{
public string FullName { get; set; }
public DateTime DoB { get; set; }
public string PhoneNumber { get; set; }
}
Here’s a bit far-fetched alternative which you can use to catch malicious intents earlier;
public class UserViewModel
{
public string FullName { get; set; }
public DateTime DoB { get; set; }
public string PhoneNumber { get; set; }
public bool IsAdmin
{
set
{
// log, alarm, notify
}
}
}
It is unforgivably naive to let malicious attempts towards our software go unnoticed while we already have the tools under our belt to do otherwise.
Despite chaotic facets of software development, developing secure code is an important survival skill in this hacker-loaded world. Let’s take this skill to a higher level by noticing malicious activities in a precise manner in our code and producing security log entries and perhaps alarms for SOC teams.