10 Most common security mistakes in development - My Experience
Nowadays, the security of the applications being used has become a significant concern for organizations, companies, and citizens in general, as they are becoming a more regular part of our daily lives. With the rapidly increasing number of applications, developers should be concerned about rising security vulnerabilities. These vulnerabilities may arise due to poor programming practice or a lack of knowledge about security. It is essential to identify and fix these vulnerabilities in the development process before they are made public.
One of my dear friend, one day discussed with me, what are those vulnerabilities an analyst can find while doing code review that One can not find while doing dynamic testing. So after the aggressive discussion, I concluded to MYSELF that, One can find 95% (don’t ask me, why - 95%, it’s a blunder) of the findings while doing dynamic testing but then, that One guy must be a Genius chap.
As we know an analyst who is doing a code review and finds a vulnerability from the code which might be easily missed by One who is doing dynamic testing, there are multiple examples available where the reviewer found a vulnerability and dynamic tester did not. I wouldn’t say dynamic testing is less important, as real enjoyment of testing lies in dynamic pentesting :D .
So, instead of fighting for which approach is best, security code review or dynamic testing, I should focus on sharing my experience on common security mistakes. By this, it does not mean that I am going to cover the vulnerability list, I am just going to show a few mistakes which developers make while writing code and an analyst can find while doing code review.
I have recently reviewed multiple applications developed in node.js, in which developers wrote a code which calls third party APIs, so partial business logic present in the application itself and rest are present in that third party API.
So let’s talk about common flaw of the application,
Missing input validation
While creating an application which depends on the third party API, this is one of the most common mistakes developers make. The third party APIs trust the user input, that means any input going from your application must be validated before it passes to the API. Missing an input validation on request parameters may lead to many critical vulnerabilities such as SQLInjection, Command Injection , XSS, etc…
- Defined routes
- Actual API Call
So, from the above steps you can observe that the application does not perform any kind of input validation except only required check, and directly passes to the API. So, developers might think that validating schema for required checks is enough but actually is not. He/She must have to perform input validation and only allow whitelisted characters
Custom sanitization code
Many times, it happens that developers don’t use a standard solution for input sanitization instead they create their own, due to this an attacker will be able to bypass such protection, sometimes, it can even lead to some different new vulnerability and thus protection itself becomes a threat.
- Sanitization logic (screenshot showing only first portion of code not whole logic)
- Attacker’s payload
As you can see the actual purpose of the code is to sanitize the request parameters but the logic itself is vulnerable with Denial-of-Service attack. An attacker can supply a crafted input which leads to infinite while loop. you can try yourself.
The reason behind this is, the sanitization code created by developers has neither passed with multiple test cases nor tested by different security professionals. So I advise you to use a standard solution which was tested with thousands of test cases. For example, HTML sanitizer from Google Closure Library, jsdom, etc…
Authentication != Authorization
Missing authorization checks is also one of the common and crucial vulnerabilities as this may lead to leakage of user’s information or modification of victim’s information.
Developer usually checks for only sessions whether the requested user is logged-in or not and gives a response based on the parameter from the query or body. In the case of API, the developer just passes the parameter value after login check and as API trusts the user input it just gives a response based on value.
Observe the case-1, where the developer updates the delivery address of the user based on userid. It takes the userid from the request body if it is available otherwise from the session. And then it passes to the API call, API will update based on the value passed to it. In actual scenario, there is no parameter like
userid passed from front-end code so, One cannot find it during dynamic testing easily but can be easily identified while doing code review.
Observe the case-2, where the developer again only checks whether the user is logged-in or not and retrieves the profile details based on passed parameters, Yes clear case of IDOR.
To remediate, I would recommend that the developer must check for authorization and not only authentication
While doing the code review of node.js application, this is the most common vulnerability I found regularly. The reason behind this is, developers usually use default options of session() or use options without having detailed knowledge of various options.
As you can see in the above screenshot, there is an option
saveUninitialized which has a value set to true. As per the documentation
saveUninitialized Forces a session that is "uninitialized" to be saved to the store. A session is uninitialized when it is new but not modified. Choosingfalse
is useful for implementing login sessions... So, now it is clear to us that this application is vulnerable session fixation vulnerability.
So, I would not recommend to always set it as
false but set a value which better fits your application and read the document first.
Exception details in response
Generally developers do exception handling but then they don’t know what to do with the
error object in the
catch block and this lack of understanding will lead them to pass the detailed error object in response as it is. Developers think handling exceptions is enough but they should understand the purpose of exception handling. First they should handle the exception, so the application does not crash and the second exception handling will help them to monitor/debug purpose or to resolve issues if any.
- Passing error object in error handling response.
- Passing error in response.
From the above screenshots, you can observe that the developer first passed the
error object in function which create error response and in that function it directly send the
error object in response which might disclose the sensitive information such as database error, file path from stacktrace, backend server technology or version, etc…
So instead of passing error details in response, the developer should send customized error messages. Make sure that in the production environment, errors should not be disclosed.
We regularly report this vulnerability while doing code review as the developer usually missed the development time debug logs inside the code and will be there as it is in production which should not be the case. This vulnerability sometimes becomes critical if it disclose the sensitive information such as username-password, session token, configuration details, users data. Logging these things are very common in the development phase. An attacker can get the log files with the chain of other vulnerability such as arbitrary file retrieval, command execution, etc…
- excessive information in logs
While logging all information may be helpful during development stages, it is important that logging levels be set appropriately before a product ships so that sensitive user data and system information are not accidentally exposed to potential attackers. Also, remember to sanitize/encode the log before writing/displaying it. So, logging itself is not vulnerability but excessive logging is.
There are a lot of third party modules available now which developers generally use while developing a huge application and this is an obvious scenario as well. But developers usually do not check whether the module has any known existing vulnerability present or not which makes the application vulnerable indirectly because there is no vulnerability in developer’s code but it is present in the third party module they use.
- Vulnerability inside the module
So, I would recommend that before using any of the third party modules, the developer must check whether the module has known vulnerability or not. Developers can check whether the module has vulnerability or not using Snyk and npm or the module’s official page. Also,
npm audit can be used to check the dependencies.
Excessive information in response
As a security analyst, We have gone through many instances where we get irrelevant/excessive information in response. The reason behind this may be re-use of code without knowing its result, passing full class objects in response, etc…
Re-use of the code is actually a good habit of programming, So many API developers re-use the same function for multiple API calls which sometimes lead to some serious consequences by sending excessive information in API response.
Case-1: Let’s assume there are two APIs,
getUserId so it happens that the developer use the same function for both the API calls because ultimately the response of
getUserId already present in the response of
Case-2: There is one API
getUserName where application only requires current user’s name but the API responds with all the information based on userid, such as Email, phone, Date of Birth, passport-details, last 4 digit of debit card, and in rare case password also. An attacker can retrieve this information and can use it to perform a phishing attack.
So, I would recommend you to send only required data in response. For example,
getUserId API should respond with only user ID and nothing else.
Hard-coded sensitive information and backdoors
As per my personal experience of development, I made such mistakes many times. I have to admit now, I was not a very good developer. But as a security consultant when I reviewed the code of web applications or any API, I came to know that I was not alone in this world who made such horrible mistakes.
Yes, developers usually kept sensitive information such as passwords, refresh-tokens, session-secret or any backdoor checks as it is for testing and forgot to take it out. We as programmers thinks that nobody is going to see this, but it’s definitely possible that this backdoor account gets found out, or there are chances that sensitive information gets leaked by bad guys..
So I would recommend not to keep such sensitive information as it is in production code and also instead of using hard-coded things, maintain a configuration files and use references to that file.
Sensitive information in Comments
And last but not the least (jokes apart), at the time of development, the product programmer usually writes some sensitive information in comment which was not supposed to be there.
While adding general comments is very useful, some programmers tend to leave important data, such as: filenames related to the web application, old links or links which were not meant to be browsed by users, old code fragments, hardcoded passwords, etc…
An attacker who finds these comments can map the application’s structure and files, expose hidden parts of the site and study the fragments of code to reverse engineer the application, which may help develop further attacks against the site.
Programming/Developing an API/application requires a proper understanding of not just codes but also requires the potential security risks. We as a developer wish that we write such code which is secure and robust. However, the above mentioned common errors often occur when developers are not keen.
Hope the reading helps you. Happy secure coding & happy hacking.
At Payatu, we provide a source code security audit services for both thick and thin client applications. We deploy a combination of manual code review and automated code analysis tools. Talk to us about a comprehensive security analysis of your code. Share your requirements with us: https://payatu.com/#get-started.